2020-05-09-Android的ListView和RecyclerView

滑動列表是最常見的UI界面,也常見卡頓問題。
今天看下兩種列表的使用上面有什么區(qū)別。

ListView

ListView使用非常簡單,但是也容易出現(xiàn)卡頓問題。默認(rèn)情況下是比較耗時的。下圖一幀的耗時是118毫秒。


1.PNG

如果對ConvertView進行復(fù)用,可以在一定程度上進行優(yōu)化,避免多次inflate。下圖優(yōu)化后依然卡頓,時間是80毫秒。


2.PNG

如果增加一個ViewHolder緩存,就可以避免多次findViewById。下圖優(yōu)化后依然卡頓,時間是58毫秒。
3.PNG

最后,可以把一些耗時操作通過AsyncTask實現(xiàn)異步,下圖優(yōu)化后依然卡頓,時間是36毫秒。


4.PNG
public class MyAdapter extends ArrayAdapter<ApplicationInfo> {

    private static final String TAG = "MyAdapter";

    private PackageManager pms;
    private Context context;

    public MyAdapter(Context context, int resource) {
        super(context, resource);
        this.context = context;
        pms = context.getPackageManager();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Log.d(TAG, "getView position=" + position);
        ApplicationInfo info = getItem(position);
        View infoView = convertView;
        ViewHolder viewHolder;
        if (infoView == null) {
            infoView = LayoutInflater.from(context).inflate(R.layout.layout_list_item, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.imageView = (ImageView)infoView.findViewById(R.id.img);
            viewHolder.textView = (TextView)infoView.findViewById(R.id.text);
            infoView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) infoView.getTag();
        }
        viewHolder.textView.setText(pms.getApplicationLabel(info));
        new LoadTask(viewHolder).execute(info);
        return infoView;
    }

    private static class ViewHolder {
        ImageView imageView;
        TextView textView;
    }

    private class LoadTask extends AsyncTask<ApplicationInfo, Void, Drawable> {

        private ViewHolder viewHolder;

        public LoadTask(ViewHolder viewHolder) {
            this.viewHolder = viewHolder;
        }

        @Override
        protected void onPostExecute(Drawable drawable) {
            viewHolder.imageView.setImageDrawable(drawable);
        }

        @Override
        protected Drawable doInBackground(ApplicationInfo... infos) {
            return pms.getApplicationIcon(infos[0]);
        }
    }
}

ListView有時會遇到瓶頸,上面的代碼多次優(yōu)化后依然卡頓,可以選擇使用RecyclerView。

RecyclerView

RecyclerView可以實現(xiàn)更強大的功能,比如橫向滑動,瀑布流布局等。同時默認(rèn)有ViewHolder緩存機制,滑動更流暢。


5.PNG
public class HorizontalAdapter extends RecyclerView.Adapter<HorizontalAdapter.ViewHolder> {

    private static final String TAG = "HorizontalAdapter";

    private List<ApplicationInfo> list;
    private PackageManager pms;

    public HorizontalAdapter(List<ApplicationInfo> list) {
        this.list = list;
    }

    public void setContext(Context context) {
        pms = context.getPackageManager();
        Log.d(TAG, "getInstalledApplications size=" + list.size());
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d(TAG, "onCreateViewHolder");
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_horizontal_item,
                parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Log.d(TAG, "onBindViewHolder position=" + position);
        ApplicationInfo info = list.get(position);
        new LoadTask(holder).execute(info);
        String label = pms.getApplicationLabel(info).toString();
        if (label.length() > 6) {
            label = label.substring(0, 6);
        }
        holder.textView.setText(label);
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {

        ImageView imageView;
        TextView textView;

        public ViewHolder(View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.img);
            textView = itemView.findViewById(R.id.text);
        }
    }

    private class LoadTask extends AsyncTask<ApplicationInfo, Void, Drawable> {

        private ViewHolder viewHolder;

        public LoadTask(ViewHolder viewHolder) {
            this.viewHolder = viewHolder;
        }

        @Override
        protected void onPostExecute(Drawable drawable) {
            viewHolder.imageView.setImageDrawable(drawable);
        }

        @Override
        protected Drawable doInBackground(ApplicationInfo... infos) {
            return pms.getApplicationIcon(infos[0]);
        }
    }
}

參考

android ListView 工作原理
ListView 的 Adapter 中g(shù)etView方法的原理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容