告诉你ListView的Adapter应该写在Activity外面还是里面

来源:互联网 发布:更改路由器端口 编辑:程序博客网 时间:2024/05/16 23:59

一、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之类的~~~

0 0