RecyclerView.ViewHolder
内部クラスとして使用できますか? そうすることに問題はありますか?
私は周りを検索しましたが、それに関するドキュメントは見つかりませんでした!
RecyclerView.ViewHolder
内部クラスとして使用できますか? そうすることに問題はありますか?
私は周りを検索しましたが、それに関するドキュメントは見つかりませんでした!
実際には、ViewHolder は静的なネストされたクラス (静的なことに注意してください!) またはトップレベルのクラス (実際には違いはありません。クラス名には外部クラス名とそれに続く $ が含まれ、次に内部クラス名)。
なぜそう思うのですか?ViewHolder がアダプターの非静的内部クラスである場合、アダプターへの参照を保持します。ここで、 RecyclerView.swapAdapter(newAdapter, false) を呼び出すと (または本当だったのか覚えていません)、新しいアダプターは古いアダプターによって以前に作成された ViewHolders を使用します。これらのホルダーでこのような暗黙的な参照を null またはクリアすることは不可能であるため、最初のアダプターへのこの参照はリークされており、ガベージ コレクションを実行できません。これは十分に悪いです。
しかし、私の場合、メモリとは関係のない実際の問題がありました。私のアダプターには、位置からデータへのマッピングを保持する「選択モデル」があり、ビューホルダーはアイテムを表示するときにデータを使用します(たとえば、選択モデルが位置17のアイテムが選択されていると言ったときなど)画面に描画されると、そのフォントの色が変わります)、ユーザー向けにマークします。これは、アダプタから選択モデル フィールドにアクセスするだけで実行されます。これは、Java では、囲んでいるアダプタ インスタンスへの暗黙的な参照を使用して、そのフィールドにアクセスすることを意味します。現在、swapAdapter の後、保存された ViewHolders はまだ古いアダプターの選択モデルを使用しており、UI が壊れていました。新しいモデルでは選択されていなかったアイテムが選択されたように表示されるためです。
本質的に、それらを作成したアダプターよりも長く存続し、別のアダプターによって使用される非静的内部クラス所有者が、古いアダプターを実際に忘れて新しいアダプターを使用することは不可能です。これは、暗黙の参照をクリアする方法がないためです。
これには多くの解決策があります。そのうちの 1 つは、ViewHolder を静的なネストされたクラスにし、バインド時にアダプターへの参照を明示的に与え、バインド解除時に null にすることです。私は、アダプターへの明示的な参照を使用して、ビューホルダーにトップレベルのクラスを使用してきました。これは、あなたが求めているものだと思います。非常に多くの場合、ホルダーはアダプターへの参照をまったく必要としないため、アダプターをまったく設定する必要がない場合があることに注意してください。
もちろん、私の問題はカーソルを交換したことに起因しています。やらなければ問題に気付かないかもしれませんが、気を付けたほうがいいと思います。