

AndroidのListViewのAdapterを静的インナークラスで実装しています。  
AdapterからActivityの変数を参照する為に、Adapterの中に弱参照でActivityを保持しています。

以下、疑問に思っていることです。

・Adapterの中でmActivity.get()がnullを返すことはあるのか？  
もしある場合は、TestAdapter.getView()でnullを返してもよいのでしょうか？  
但し、固定でnullを返すと例外が発生しました。

・どこかのサイトでインナークラスは静的クラスのほうがメモリリークしないと書いてあったので、Adapterを静的インナークラスにしましたが、正しい実装なのでしょうか？

どうかアドバイスをよろしくお願いします。

[code]

    public class TestActivity extends Activity {
    
      private List<String> mData = new ArrayList<String>();
      private ListView mListView;
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.testactivity);
        mListView = (ListView)findViewById(R.id.listview);
        mListView.setAdapter(new TestAdapter(this));
      }
    
      private static class ViewHolder {
    
        public ViewHolder(View view) {
        }
    
      }
    
      private static class TestAdapter extends BaseAdapter {
    
        private WeakReference<TestActivity> mActivity;
    
        public TestAdapter(TestActivity activity) {
          super();
          mActivity = new WeakReference<TestActivity>(activity);
        }
    
        @Override
        public int getCount() {
          TestActivity activity = mActivity.get();
          return activity != null ? activity.mData.size() : 0;
        }
    
        @Override
        public Object getItem(int position) {
          TestActivity activity = mActivity.get();
          return activity != null ? activity.mData.get(position) : null;
        }
    
        @Override
        public long getItemId(int position) {
          return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
          MovieListActivity activity = mActivity.get();
          if (activity == null)
            return null;    //ここでnullを返してもよいのか？
    
        }
    
      }
    
    }
    
[/code]


CC BY-SA 3.0
2017-02-26T07:54:30.097
32957
2017-04-11T08:49:38.517
2017-02-26T08:18:14.637
7212
7212
question
android
AndroidのListViewのAdapterは、静的インナークラスで作成したほうがよいのでしょうか？


> Adapterの中に弱参照でActivityを保持しています。

弱参照で保有する必要は特に無いように感じます。

> ・Adapterの中でmActivity.get()がnullを返すことはあるのか？

弱参照である以上、無いとは言えないと思います。

> TestAdapter.getView()でnullを返してもよいのでしょうか？

落ちるので駄目だと思います。

> Adapterを静的インナークラスにしましたが、正しい実装なのでしょうか？

正しい実装です。staticにしなければ、メモリーリークの原因になります。

僕の感想ですが、今回WeakReferenceを利用する理由は特に無さそうなので

[code]

    private TestActivity mActivity;
    public TestAdapter(TestActivity activity) {
      super();
      mActivity = activity;
    }
    
[/code]

とするのが良いと思います。


CC BY-SA 3.0
2017-02-26T09:15:26.373
32958
2017-02-26T09:15:26.373
354
32957
answer


**_・Adapterの中でmActivity.get()がnullを返すことはあるのか？_**

普通の実装ならありえません。が、そのようなことが起こるコードを無理に書こうと思えばできなくもありません。意識せずにやったことが同じ結果を引き起こすこともないとは言えません。どのような書き方が「普通」の範囲に入るのかよくわからないのであれば、あり得ると思った方が良いでしょう。

**_もしある場合は、TestAdapter.getView()でnullを返してもよいのでしょうか？_**

`TestAdapter.getView()`が呼ばれているということは、`ListView`が`ListView`として働こうとしているのですから、そこで`null`を返すと、やはり例外になる可能性が高いです。上記で「あり得る」の立場をとるのであれば、`null`は返してはいけない、と考えるべきです。

ただ、無理にやったにせよ意識せずにやったにせよ、なんらかのバグがないと、普通はこの状態にはならないですから、わざと例外を出させてバグをさっさと見つける、と言うのはあり得る考え方かもしれません。

**_・どこかのサイトでインナークラスは静的クラスのほうがメモリリークしないと書いてあったので、Adapterを静的インナークラスにしましたが、正しい実装なのでしょうか？_**

全ての非静的インナークラスがメモリリークを引き起こすわけではありませんが、「非静的インナークラスがメモリリークを引き起こす」仕組みが十分理解できている人でさえ、特定のコードを見て、そのコードがメモリリークを引き起こすかどうかを判定するのは極めて困難であることが多いです。ましてや、その仕組みが十分できていないのであれば「インナークラスを書く場合には、必ず静的にしないといけない」と覚えておいた方が良いでしょう。

ただし、「そもそもインナークラスにせずに全くの別クラスにする」と言う選択肢もあるはずなので、そこまで気を使ってインナークラスにする必要があるのかどうかは甚だ疑問です。「正しい実装」なのかどうかはなんとも言えないです。

* * *

最後になりますが、

**_Adapterの中に弱参照でActivityを保持しています。_**

こちらについては「正しい実装です」と断言しておきます。弱参照にしなければ明確な循環参照が発生してしまうところを、それを避けるために弱参照を使用するのは正しい判断です。ガベージコレクションが働くJavaであっても、循環参照の存在はガベージコレクタにとって大きな負荷になりますし、上記の『「非静的インナークラスがメモリリークを引き起こす」仕組みが十分理解できている』ならば、同じ理屈で、循環参照によってメモリリークのリスクが増すことは理解できるはずです。

**簡単に避けられるならば循環参照は避けた方が良い** と言うのは頭に入れておいた方が良いでしょう。


CC BY-SA 3.0
2017-02-26T10:09:20.323
32960
2017-02-26T10:09:20.323
13972
32957
answer