android的ListView点击事件问题?

someone
  • 1.8k

当我在写一个android应用的时候遇到了这样一个需求:

有个ListView,里面的item都有图片和文字,当一个item被点击的时候显示在此item上显示图片和一个进度条,当另一个item被点击的时候隐藏上一次被电击item的图片和进度条,显示当前被点击item的图片和进度条

我的有关代码是这样的,用的是simpleAdapter

clipboard.png

我的思路是就这样的,先把ListView的所有item遍历,隐藏我该隐藏的控件,然后显示当前被点击item的要显示的控件(progressbar和playing_effect)

不过问题出现了,点击之后的效果特别卡,不知道怎么回事点击40-50次之后就出现手机内存不足的情况,难道我的思路一开始是错误的吗?还是需要优化?耗内存是怎么回事啊

谢谢






public class MainActivity extends AppCompatActivity {



    ArrayList<Boolean> itemState = new ArrayList<>();
    int checkedItemIndex = -1;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for (int s=0;s<20;s++){
            itemState.add(false);
        }


        class AudioListAdapter extends SimpleAdapter{

            public AudioListAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
                super(context, data, resource, from, to);
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                View v = super.getView(position, convertView, parent);
                //
                if (itemState.get(position)){
                    // 设置点击状态
                    v.findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
                    v.findViewById(R.id.playing_effect).setVisibility(View.VISIBLE);
                }else {
                    // 设置未点击状态
                    v.findViewById(R.id.progressBar).setVisibility(View.GONE);
                    v.findViewById(R.id.playing_effect).setVisibility(View.GONE);
                }
                //

                return v;
            }
        }



        final ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>();
        for (int i = 0; i < 10; i++){
            HashMap<String,Object> map = new HashMap<String, Object>();
            map.put("song","song name "+i);
            map.put("singer","singer "+i);
            map.put("currentTime","01:3"+i);
            map.put("allTime","04:5"+i);

            listItem.add(map);
        }

        final ListView listView = (ListView)findViewById(R.id.listView);
        final AudioListAdapter audioListAdapter = new AudioListAdapter(
                this,
                listItem,
                R.layout.item,
                new String[]{"song","singer","currentTime","allTime"},
                new int[]{R.id.song,R.id.singer,R.id.currentTime,R.id.allTime}
        );

        listView.setAdapter(audioListAdapter);

        // onclick
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //
                if (checkedItemIndex>=0){
                    itemState.set(checkedItemIndex,false);
                }
                checkedItemIndex = position;
                itemState.set(position,true);
                audioListAdapter.notifyDataSetChanged();
                //
            }
        });

    }

    @Override
    public void onStart(){
        super.onStart();
    }

}

上面我把所有代码给贴出来的,我按楼下回复里的想法去做的,我发现结果同样很卡,内存耗得更快,大神们看一下吧

谢谢

回复
阅读 5.1k
4 个回答
原文海
  • 1.3k
✓ 已被采纳

楼上两位已经说的比较清楚了,自己维护一个列表,然后在getView中根据列表的状态绘制不同的View。
之前你的方法需要遍历并创建所有itemView的实例,无论是对cpu还是内存都有很大的压力,所以会卡,在item数量未知的前提下最好不要遍历,保存一个上次点击的index就行了。
随便写了些伪代码,大概是这样的

 ArrayList<Boolean> list = new ArrayList<>();
 int listClickedItemIndex = -1;
    public View getView(int position, View convertView, ViewGroup parent) {
        if(list.get(position)){
            //设为点击状态
        }else{
            //设为未点击状态
        }
        return convertView;
    }
    public void onItemClick(int position){
       if(listClickedItemIndex >= 0){
           list.set(listClickedItemIndex,false);
       }
        listClickedItemIndex = position;
        list.set(position,true);
        adapter.notifyDataSetChanged();
    }

----------------------------分割线---------------------
你getView部分的代码有问题,在这里你应该创建/复用convertView

我说下我的思路吧:
把item的点击状态都存在adapter中,每次点击只要去更新adapter中具体item的某个属性就行了。接着在getView里根据这个属性的不同做不同的处理。

把显示/隐藏的逻辑写在listView的adapter的getView方法,点击的时候调用notifyDataSetChanged就可以了

guzhanwei8
  • 4
新手上路,请多包涵

3楼正解,自己新建一个boolean类型的list用以保存每个item的状态,每次点击先将下标currentitemindex的item属性改为false,将下标position的item属性设为true。然后更新curreentitemindex.最后刷新adapter

宣传栏