一、Adapter写在哪并不是重点
ListView的Adapter应该写在Activity外面还是里面?
我想很多很多开发者估计都不知道这个问题。
而有部分人可能会嗤之以鼻,adapter写在外面和里面不都一样么?爱怎么写怎么写
这话没错,其实写在哪里都是没有问题的。
请别拍我板砖,我不是来搞笑的。
我先要说明一下我为什么要写这么一篇博客。
最近看了一些其他同时以前的项目,发现大多数项目的做法是建立一个package包专门存放Adapter类的,也有的人会嫌麻烦两个类切来切去,干脆都写在Activity中。
而我属于后者,我并不觉得adapter需要单独占用一个包,因为大多数时候他们并不能给其他Activity复用。
然而这两种方式都是可以的,看个人习惯或者团队做法了。
但有一点很关键,无论如何,adapter不能持有activity的引用!否则会出现内存泄漏的风险!
为什么呢? 因为adapter里面可能会做一些耗时操作,当finish activity时会因为被adapter持有引用而导致activity无法被回收,从而导致内存泄漏。
二、Adapter为什么写在Activity外面
上面也说了,adapter不能持有Activity的引用,否则会有内存泄漏的风险。
而Java中,非静态内部类对象是会隐式持有外部类引用的,也就是说adapter持有了activity的引用……
关于内部类可以看这篇博客:Java中的内部类和匿名类
所以就有将Adapter写在单独的一个包中的做法,估计很多开发者都不知道原来是这个原因,认为只是为了让Activity看起来更简洁。
然而我还想说的是,adapter写在外面也阻止不了蹩脚程序员(噗,其实我前段时间就是)想在adapter内持有Activity引用。因为很多时候adapter不可避免的需要和Activity交互,或者需要一个context对象
比如说这种情况……
需要点击某个Item中的Button,跳转到一个新的Activity的时候。
很多人会这么做……
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MainActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AppCompatActivity</span> {</span>
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.listView);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 看这里,activity对象传入adapter</span>
ExampleAdapter adapter = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ExampleAdapter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);
listView.setAdapter(adapter);
}
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ExampleAdapter</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">BaseAdapter</span> {</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 看这里,持有了Activity引用</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Context mContext;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ExampleAdapter</span>(Context context) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.mContext = context;
}
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> View <span class="hljs-title" style="box-sizing: border-box;">getView</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> position, View convertView, ViewGroup parent) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (convertView == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 这里也用到了activity的引用……</span>
convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>);
}
TextView textView = (TextView) convertView.findViewById(R.id.text);
textView.setText(String.valueOf(position));
Button button = (Button) convertView.findViewById(R.id.button);
button.setOnClickListener(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> View.OnClickListener() {
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onClick</span>(View v) {
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 看这里,跳转activity……</span>
mContext.startActivity(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Intent(mContext, SecondActivity.class));
}
});
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> convertView;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li></ul>
这种情况下adapter就持有了Activity引用了,如果我在adapter中进行耗时操作(比如加载图片之类的),并且finish Activity。
虽然此时Activity销毁了,但是GC也是无法回收的……而Activity占用的内存还是比较大的。
三、不持有Activity对象的情况下怎么和Activity交互
首先说明一种情况,有人会想着使用弱引用来保存Activity。
但我认为这是不好的做法,因为弱引用对象随时都有可能被回收,虽然可以判断是否为空不至于报空指针异常,但是会导致和Activity交互失败。用户体验肯定是不好的
在上main的例子中,想要和Activity交互还是有很多方式的。
首先我们来说一下inflate一个xml,完全可以使用parent的context,如下
然后button的点击跳转Activity,我们可以弄一个回调,如:
adapter构造中的context忘记删除了,别在意细节……反正没持有引用对吧
这样就可以在不持有activity的情况下愉快的交互了
四、说好的Adapter写在内部呢
别急,adapter写在Activity里面的话只需要加个static关键字就行了,其他和写在外面是一样的。
结语:
Adapter到底写在哪呢?
你怎么舒服怎么来就行了,千万小心不要导致内存泄漏就行,反正我是喜欢写里边,隐藏外部访问并且写起来舒服╮(╯-╰)╭
不止adapter,如果还写了的话也要写成静态的内部类哦
还有handler之类的~~~