ListView的優化

ListView的優化問題可以說是面試的必考題。我之前看過一遍視頻 Android必學-異步加載,感覺里面講解的知識都是ListView優化常用的,這里我就通過里面的示例來做一個總結。本篇準備通過這個示例來談一談ListView的優化,通過分析在寫code的過程中遇到的問題,來談一下解決辦法。

示例是這樣的:
http://www.imooc.com/api/teacher?type=4&num=30 中加載json格式的數據,解析出來,然后用ListView顯示出來。下面是完成后的圖片(沒有找到有效設置圖片大小的方法,大家有知道的話,留言給我)
先看我的示例listView的item的布局:

item.png

com.mecury.javamai.png
1.對于這樣一個需求,我們首先應該是解析得到的數據,然后將得到的數據提供給ListView的Adapter,有關于這部分的代碼,寫在了MainActivity.java,我放到文章后面,畢竟重點不在這。
2.當獲得到數據之后,接下來就是編寫Adapter了。
  • 使用ViewHolder模式來提高效率

Viewholder模式充分了ListView的視圖緩存機制,避免了每次在調用getView的時候都去通過findViewById實例化數據。《Android群英傳》中說:據測試,使用ViewHolder將提高50%的效率。對應代碼中就是這樣,先在NewsAdapter(本示例中的Adapter)新建一個內部類:(詳細代碼見文章后的NewsAdapter.java

//使用ViewHolder
    private static class ViewHolder {
        private TextView tvTitle, tvContent;
        private ImageView ivIcon;
    }

在重寫的getView方法中這樣寫:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        //判斷是否有緩存
        if (convertView == null) {
            //通過LayoutInflate實例化布局
            viewHolder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.item_layout, parent, false);
            viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
            viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
            viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
            convertView.setTag(viewHolder);
        } else {
           //通過tag找到緩存的布局
            viewHolder = (ViewHolder) convertView.getTag();
        }
        NewsBean newsBean = newsBeanList.get(position);

        String urlString = newsBean.newsIconUrl;
        viewHolder.ivIcon.setTag(urlString); // 將ImageView與url綁定
        //普通異步加載
       // mImageLoader.showImageByThread(viewHolder.ivIcon,urlString);
        mImageLoader.showImageByAsyncTask(viewHolder.ivIcon,urlString);
        viewHolder.tvTitle.setText(newsBean.newsTitle);
        viewHolder.tvContent.setText(newsBean.newsContent);
        return convertView;
    }
  • 異步加載:耗時的操作放在異步線程中

如果在adapter中的某些操作需要耗費大量的時間,這個時候就要用到異步線程來進行異步就在數據。比如:現在要加載圖片,此時我們需要根據url訪問網絡得到數據,然后將數據解析為Bitmap設置給View。這些操作如果不進行異步處理而直接放入adapter,可想而知,我們的ListView會有多卡。
這里向大家提供兩種異步加載線程的方式:(代碼查看下面的ImageLoader.java)
向網絡獲得數據,異步中需要進行的操作:

    public Bitmap getBitmapFormURL(String urlString) {
        Bitmap bitmap;
        InputStream inputStream = null;

        try {
            URL url = new URL(urlString);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            inputStream = new BufferedInputStream(conn.getInputStream());  //得到圖片的數據流
            bitmap = BitmapFactory.decodeStream(inputStream);  //根據數據流來解析出圖片的bitmap
            conn.disconnect();
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return null;
    }
一種是通過多線程方式通過Handler+Message進行異步加載
private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //這個getTag是下面的問題要講的優化,大家可以先看看
            if (mImageView.getTag().equals(mUrl)) { //當url標記和原先設置的一樣時,才設置ImageView
                mImageView.setImageBitmap((Bitmap) msg.obj);
            }

        }
    };
    public void showImageByThread(ImageView imageView, final String url) {

        this.mImageView = imageView;
        this.mUrl = url;
        new Thread() {
            @Override
            public void run() {
                super.run();
                Bitmap bitmap = getBitmapFormURL(url);
                Message message = Message.obtain();
                message.obj = bitmap;
                handler.sendMessage(message);
            }
        }.start();
    }
另一種是通過AsyncTask來進行異步操作

AsyncTask的使用方法,不熟悉的可以學習下,這里不講了,畢竟不是重點。

public void showImageByAsyncTask(ImageView imageView,String url){  
        new NewsAsyncTask(imageView,url).execute(url);  
    } 

構建的AsyncTask的內部類

class NewsAsyncTask extends AsyncTask<String,Void,Bitmap>{  
          
        private ImageView myImageView;  
        private String mUrl;  
          
        public NewsAsyncTask(ImageView imageView,String url){  
            myImageView = imageView;  
            mUrl = url;  
        }  
              //String...params是可變參數接受execute中傳過來的參數  
        @Override  
        protected Bitmap doInBackground(String... params) {  
              
            String url=params[0];  
            //這里同樣調用我們的getBitmapFromeUrl  
            Bitmap bitmap = getBitmapFromUrl(params[0]);  
            return bitmap;  
        }  
        //這里的bitmap是從doInBackgroud中方法中返回過來的  
        @Override  
        protected void onPostExecute(Bitmap bitmap) {  
            super.onPostExecute(bitmap);  
                imageView.setImageBitmap(bitmap);  
        }  
    } 

listView錯位加載問題

當上面的代碼寫完時,如果先不用讓大家先看看的mImageView.getTag().equals(mUrl)判斷一下(上面的代碼并不完整,下面會講),你會發現如下圖的情況,在Listview中的各個item加載的過程中,出現了item錯位的情況。一張圖片在多個位置顯示,過了一段時間才正常。

GIF.gif

對于上面的情況,我們先來看看產生這種情況的原因(下面內容主要引用自android listview 異步加載圖片并防止錯位):

231543494598347.jpg

網上找了一張圖, listview 異步加載圖片之所以錯位的根本原因是重用了 convertView 且有異步操作.
如果不重用 convertView 不會出現錯位現象, 重用 convertView 但沒有異步操作也不會有問題。
我簡單分析一下:
當重用 convertView 時,最初一屏顯示 7 條記錄, getView 被調用 7 次,創建了 7 個 convertView.
當 Item1 劃出屏幕, Item8 進入屏幕時,這時沒有為 Item8 創建新的 view 實例, Item8 復用的是
Item1 的 view 如果沒有異步不會有任何問題,雖然 Item8 和 Item1 指向的是同一個 view,但滑到
Item8 時刷上了 Item8 的數據,這時 Item1 的數據和 Item8 是一樣的,因為它們指向的是同一塊內存,
但 Item1 已滾出了屏幕你看不見。當 Item1 再次可見時這塊 view 又涮上了 Item1 的數據。
但當有異步下載時就有問題了,假設 Item1 的圖片下載的比較慢,Item8 的圖片下載的比較快,你滾上去
使 Item8 可見,這時 Item8 先顯示它自己下載的圖片沒錯,但等到 Item1 的圖片也下載完時你發現
Item8 的圖片也變成了 Item1 的圖片,因為它們復用的是同一個 view。 如果 Item1 的圖片下載的比
Item8 的圖片快, Item1 先刷上自己下載的圖片,這時你滑下去,Item8 的圖片還沒下載完, Item8
會先顯示 Item1 的圖片,因為它們是同一快內存,當 Item8 自己的圖片下載完后 Item8 的圖片又刷成
了自己的,你再滑上去使 Item1 可見, Item1 的圖片也會和 Item8 的圖片是一樣的,
因為它們指向的是同一塊內存。

解決的辦法由很多種,這里說一下最簡單的一種:使用findViewWithTag
在NewsAdapter中為ImageView設置Tag標識位:

//將url設為imagView的標識位
String urlString = newsBean.newsIconUrl; 
viewHolder.ivIcon.setTag(urlString); // 將ImageView與url綁定

然后再加載的過程中通過url來判斷對應imagview位置是否一致來決定是否加載。

if (mImageView.getTag().equals(mUrl)) { 
//當url標記和原先設置的一樣時,才設置ImageView    
mImageView.setImageBitmap((Bitmap) msg.obj);
}

為圖片設置緩存

設置緩存的重要性不言而喻,在加載數據的過程中,你不可能每次都從網絡上加載(除非數據量小)。如果即之一這樣做就要面對兩個問題:1.加載數據浪費的時間 2.加載數據消耗的流量 。信不信用戶一言不合就把你這破app給卸載了。。。。。。
設置緩存的原理這里也不再說了,要說的話估計又成一片博文了。這里介紹用法,讓你看看怎么寫:(這部分代碼,在文章末尾的ImageLoader.java中)
1.首先聲明一個LrcCache
private LruCache<String,Bitmap> mMemoryCaches;
2.然后初始化

 //下面是建立緩存
        int maxMemory = (int) Runtime.getRuntime().maxMemory();  //運行時最大內存
        int cacheSize = maxMemory/4;  //緩存的大小
        mCaches = new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };

3.添加方法,在適當的地方調用

//將bitmap添加到緩存
    public void addBitmapToCache(String url,Bitmap bitmap){
        if (getBitmapFormCache(url) == null){
            mCaches.put(url, bitmap);
        }
    }

    //從緩存中獲取數據
    public Bitmap getBitmapFormCache(String url){
        return mCaches.get(url);
    }

ListView的滑動時停止加載和分頁加載

先說分頁加載,我們不用每次把ListView所有的Item都一次性加載完畢,這樣做沒必要也很累。我們僅僅需要加載那部分顯示在屏幕部分的Item即可,這樣所要加載的數據就減少了很多。另一方面,我們需要考慮另一個問題,當用戶滑動時,顯示在屏幕的Item會不斷的變化,如果只是加載顯示在屏幕的Item,這也沒有必要,因此我們應該在停止滑動時再加載數據。這樣說,understand?
實現步驟:
1.讓NewsAdapter實現接口AbsListView.OnScrollListener,并復寫里面的方法
2.在復寫的方法里面進行一些操作。

@Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        switch (scrollState){
            case SCROLL_STATE_IDLE:  //滑動停止時。
                mImageLoader.loadImages(mStart, mEnd);
                break;
            case SCROLL_STATE_TOUCH_SCROLL: //正在滑動時
                mImageLoader.cancelAllTasks();
                break;
            case SCROLL_STATE_FLING: //手指拋動時,即手指用力滑動在離開后ListView由于慣性而繼續滑動

                break;
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mStart = firstVisibleItem;
        mEnd = firstVisibleItem + visibleItemCount;
        //第一次的時候預加載
        if (mFirstIn && visibleItemCount > 0){
            mImageLoader.loadImages(mStart, mEnd);
            mFirstIn = false;
        }
    }

可以看到在滑動停止時我們調用了ImageLoader類的loadIamge方法,這是一個加載圖片的方法,用于加載Item對應的第mSart項t到第mEnd項之間的數據(這兩個數據怎么來的,你先把這個問題放在心里),看下loadImage法的代碼實現:

public void loadImages(int start, int end){
        for (int i = start; i < end; i++){
            String url = NewsAdapter.URLS[i];
            //由緩存中得到bitmap
            Bitmap bitmap = getBitmapFormCache(url);
            if (bitmap == null){
                //當bitmap為空時,由AsyncTask進行加載,并在onPostExecute()方法中setImageBitmap
                NewsAsyncTask task = new NewsAsyncTask(url);
                task.execute(url);
                mAsyncTask.add(task);
            } else {
                //當bitmap不為空時,直接進行setImageBitmap
                ImageView imageView = (ImageView) mListView.findViewWithTag(url);
                imageView.setImageBitmap(bitmap);
            }
        }
    }

由代碼中可以看到我們由NewsAdatper.URLS[]中取出了start到end的url,然后加載了這些數據,我們看下這個數組,這是在NewsAdapter的構造器中,可以明顯看到里面存放了所有Item的圖片的url:

//將圖片的url存儲在數組中
        URLS = new String[data.size()];
        for (int i = 0; i < data.size(); i++) {
            URLS[i] = data.get(i).newsIconUrl;
        }

此時再來看NewsAsyncTask的代碼:

  //參數1:啟動任務輸入的參數,參數2:后臺任務執行的百分比,參數3,后臺執行任務的返回方法
    private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap> {

        private String mUrl;

        public NewsAsyncTask(String stringUrl) {
            mUrl = stringUrl;
        }

        //doInBackground方法的參數是上面輸入的第一個參數,返回的對象會傳遞給onPostExecute方法
        @Override
        protected Bitmap doInBackground(String... params) {
            String url = params[0];
            Bitmap bitmap = getBitmapFormURL(url);
            if (bitmap != null){
                addBitmapToCache(url,bitmap); //將bitmap添加到緩存
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //根據url從listView中找到對應的ImageView
            ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
            if (imageView != null && bitmap != null){
                imageView.setImageBitmap(bitmap); //為imageView設置圖片
            }
            mAsyncTask.remove(this);
        }
    }

可以看到這就是根據url為所對應ImageView設置圖片。看到這就只有一個問題了,那就是mStart和mEnd是怎么得到的,再看代碼我們重寫的onScroll方法:

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mStart = firstVisibleItem;
        mEnd = firstVisibleItem + visibleItemCount;
        //第一次的時候預加載
        if (mFirstIn && visibleItemCount > 0){
            mImageLoader.loadImages(mStart, mEnd);
            mFirstIn = false;
        }
    }

這個方法有三個參數,對應的為
firstVisibleItem:ListView所有當前可見的Item第一個Item
visibleItemCount:可見Item的總數
totalItemCount :所有Item的總數
這樣一來大家是不是都懂了。

code

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ListView listView;

    private static final String url = "http://www.imooc.com/api/teacher?type=4&num=30";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView) findViewById(R.id.lv);

        new MainAsyncTask().execute(url);

    }


    public List<NewsBean> getJsonData(String url){
        List<NewsBean> newsBeanList = new ArrayList<>();
        try {
            String jsonString = readStream(new URL(url).openStream());//利用readStream得到String數據
            Log.e("JSON",jsonString); //打印出string數據

            //下面解析得到的json數據
            JSONObject jsonObject;
            NewsBean newsBean;
            try {
                jsonObject = new JSONObject(jsonString);
                JSONArray jsonArray = jsonObject.getJSONArray("data");
                for (int i=0; i<jsonArray.length(); i++){
                    jsonObject = jsonArray.getJSONObject(i);
                    newsBean = new NewsBean();
                    newsBean.newsIconUrl = jsonObject.getString("picSmall");
                    newsBean.newsTitle = jsonObject.getString("name");
                    newsBean.newsContent = jsonObject.getString("description");
                    newsBeanList.add(newsBean);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return newsBeanList;
    }

    //由輸入流中讀取數據并將數據返回
    public String readStream(InputStream in){
        InputStreamReader reader;
        String result = "";
        String line = "";
        try {
            reader = new InputStreamReader(in, "UTF-8");
            BufferedReader br = new BufferedReader(reader);
            while((line = br.readLine())!=null){
                result += line;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }


    //異步線程類
    class MainAsyncTask extends AsyncTask<String, Void, List<NewsBean>>{

        //該方法運行在后臺線程中
        @Override
        protected List<NewsBean> doInBackground(String... params) {
            return getJsonData(params[0]);
        }

        @Override
        protected void onPostExecute(List<NewsBean> newsBeanList) {
            super.onPostExecute(newsBeanList);
            NewsAdapter newsAdapter = new NewsAdapter(MainActivity.this, newsBeanList, listView);
            listView.setAdapter(newsAdapter);
        }
    }
}

NewsAdapter.java

public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener {

    private List<NewsBean> newsBeanList = new ArrayList<>();
    private LayoutInflater mInflater;
    private ImageLoader mImageLoader;
    private int mStart, mEnd;
    public static String[] URLS;
    private boolean mFirstIn;

    public NewsAdapter(Context context, List<NewsBean> data, ListView listView) {
        newsBeanList = data;
        mInflater = LayoutInflater.from(context);
        mImageLoader = new ImageLoader(listView);

        //將圖片的url存儲在數組中
        URLS = new String[data.size()];
        for (int i = 0; i < data.size(); i++) {
            URLS[i] = data.get(i).newsIconUrl;
        }

        listView.setOnScrollListener(this);
        mFirstIn = true;
    }

    @Override
    public int getCount() {
        return newsBeanList.size();
    }

    @Override
    public Object getItem(int position) {
        return newsBeanList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        //判斷是否有緩存
        if (convertView == null) {
            //通過LayoutInflate實例化布局
            viewHolder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.item_layout, parent, false);
            viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
            viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
            viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
            convertView.setTag(viewHolder);
        } else {
           //通過tag找到緩存的布局
            viewHolder = (ViewHolder) convertView.getTag();
        }
        NewsBean newsBean = newsBeanList.get(position);

        String urlString = newsBean.newsIconUrl;
        viewHolder.ivIcon.setTag(urlString); // 將ImageView與url綁定
        //普通異步加載
       // mImageLoader.showImageByThread(viewHolder.ivIcon,urlString);
        mImageLoader.showImageByAsyncTask(viewHolder.ivIcon,urlString);
        viewHolder.tvTitle.setText(newsBean.newsTitle);
        viewHolder.tvContent.setText(newsBean.newsContent);
        return convertView;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        switch (scrollState){
            case SCROLL_STATE_IDLE:  //滑動停止時。
                mImageLoader.loadImages(mStart, mEnd);
                break;
            case SCROLL_STATE_TOUCH_SCROLL: //正在滑動時
                mImageLoader.cancelAllTasks();
                break;
            case SCROLL_STATE_FLING: //手指拋動時,即手指用力滑動在離開后ListView由于慣性而繼續滑動

                break;
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mStart = firstVisibleItem;
        mEnd = firstVisibleItem + visibleItemCount;
        //第一次的時候預加載
        if (mFirstIn && visibleItemCount > 0){
            mImageLoader.loadImages(mStart, mEnd);
            mFirstIn = false;
        }
    }

    //使用ViewHolder
    private static class ViewHolder {
        private TextView tvTitle, tvContent;
        private ImageView ivIcon;
    }
}

ImageLoder.java

public class ImageLoader {

    private ImageView mImageView;
    private String mUrl;

    private LruCache<String, Bitmap> mCaches;
    private ListView mListView;
    private Set<NewsAsyncTask> mAsyncTask;

    public ImageLoader(ListView listView){

        mListView = listView;
        mAsyncTask = new HashSet<>();

        //下面是建立緩存
        int maxMemory = (int) Runtime.getRuntime().maxMemory();  //運行時最大內存
        int cacheSize = maxMemory/4;
        mCaches = new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }

    //將bitmap添加到緩存
    public void addBitmapToCache(String url,Bitmap bitmap){
        if (getBitmapFormCache(url) == null){
            mCaches.put(url, bitmap);
        }
    }
    //從緩存中獲取數據
    public Bitmap getBitmapFormCache(String url){
        return mCaches.get(url);
    }
//===================================下面為普通異步加載===========================================
private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (mImageView.getTag().equals(mUrl)) { //當url標記和原先設置的一樣時,才設置ImageView
                mImageView.setImageBitmap((Bitmap) msg.obj);
            }
        }
    };

    public void showImageByThread(ImageView imageView, final String url) {

        this.mImageView = imageView;
        this.mUrl = url;
        new Thread() {
            @Override
            public void run() {
                super.run();
                Bitmap bitmap = getBitmapFormURL(url);
                Message message = Message.obtain();
                message.obj = bitmap;
                handler.sendMessage(message);
            }
        }.start();
    }

//====================上面是使用普通的異步加載,下面是使用AsyncTask進行的異步加載==================
    public Bitmap getBitmapFormURL(String urlString) {
        Bitmap bitmap;
        InputStream inputStream = null;

        try {
            URL url = new URL(urlString);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            inputStream = new BufferedInputStream(conn.getInputStream());  //得到圖片的數據流
            bitmap = BitmapFactory.decodeStream(inputStream);  //根據數據流來解析出圖片的bitmap
            conn.disconnect();
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return null;
    }

   
    //加載圖片
    public void showImageByAsyncTask(ImageView ImageView, String url) {
        Bitmap bitmap = getBitmapFormCache(url);
        if (bitmap == null){
            ImageView.setImageResource(R.mipmap.ic_launcher);
        }else{
            ImageView.setImageBitmap(bitmap);
        }
    }

    public void cancelAllTasks(){
        if (mAsyncTask != null){
            for (NewsAsyncTask task : mAsyncTask){
                task.cancel(false);
            }
        }
    }

    public void loadImages(int start, int end){
        for (int i = start; i < end; i++){
            String url = NewsAdapter.URLS[i];
            //由緩存中得到bitmap
            Bitmap bitmap = getBitmapFormCache(url);
            if (bitmap == null){
                //當bitmap為空時,由AsyncTask進行加載,并在onPostExecute()方法中setImageBitmap
                NewsAsyncTask task = new NewsAsyncTask(url);
                task.execute(url);
                mAsyncTask.add(task);
            } else {
                //當bitmap不為空時,直接進行setImageBitmap
                ImageView imageView = (ImageView) mListView.findViewWithTag(url);
                imageView.setImageBitmap(bitmap);
            }
        }
    }

    //參數1:啟動任務輸入的參數,參數2:后臺任務執行的百分比,參數3,后臺執行任務的返回方法
    private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap> {

        private String mUrl;

        public NewsAsyncTask(String stringUrl) {
            mUrl = stringUrl;
        }

        //doInBackground方法的參數是上面輸入的第一個參數,返回的對象會傳遞給onPostExecute方法
        @Override
        protected Bitmap doInBackground(String... params) {
            String url = params[0];
            Bitmap bitmap = getBitmapFormURL(url);
            if (bitmap != null){
                addBitmapToCache(url,bitmap); //將bitmap添加到緩存
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //根據url從listView中找到對應的ImageView
            ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
            if (imageView != null && bitmap != null){
                imageView.setImageBitmap(bitmap);
            }
            mAsyncTask.remove(this);
        }
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容