Anroid- 异步加载

作者: ZebraWei | 来源:发表于2017-05-29 23:47 被阅读90次
    一、为什么要使用异步加载
    • 1.还是Android单线程模型
    • 2.耗时操作阻塞UI线程
    二、异步加载最常用的两种方式
    • 1.多线程/线程池
    • 2.AsyncTask
    主要步骤
    1.异步处理的一般方法
    2.使用多线程进行异步加载
    3.使用AsyncTask进行异步加载
    4.异步加载的缓存与优化
    主要思想
    • 1.通过异步加载,避免阻塞UI线程
    • 2.通过LruCache,将已下载图片放到内存中
    • 3.判断ListView滑动状态,决定何时加载图片
    • 4.不仅仅是ListView ,任何控件都可以使用异步加载
    1.实现ListView图文混排

    通过使用AsynacTask网络异步加载数据,获取Json数据。解析Json数据到List中,文艺重现BaseAdapter
    实现网络异步访问:

    /**
     * 实现网络的异步访问
     * @author Administrator
     *
     */
    class NewsAsyncTask extends AsyncTask<String,Void,List<NewBrean>>{
    
        @Override
        protected List<NewBrean> doInBackground(String... params) {
        
            return getJsonData(params[0]); //请求网址
        }
        
        @Override
        protected void onPostExecute(List<NewBrean> result) {
            super.onPostExecute(result);
            NewsAdapter adapter = new NewsAdapter(MainActivity.this,result, mListView);
            mListView.setAdapter(adapter);
        }
    }
    

    将url对应的JSON格式数据转换为我们所封装的NewsBean对象:

    /**
     * 将url对应的JSON格式数据转换为我们所封装的NewsBean对象
     * @param url
     * @return
     */
    private List<NewBrean> getJsonData(String url) {
        List<NewBrean> newsBeanList = new ArrayList<NewBrean>();
        try {
            String jsonString = readStream(new java.net.URL(url).openStream());
            JSONObject jsonObject ;
            NewBrean 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 NewBrean();
                    newsBean.newsIconUrl = jsonObject.getString("picSmall");
                    newsBean.newsTitle = jsonObject.getString("name");
                    newsBean.newsContent = jsonObject.getString("description");
                    newsBeanList.add(newsBean);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            
        } catch (MalformedURLException e) {
        } catch (IOException e) {
            e.printStackTrace();
        }
        return newsBeanList;
    }
    

    通过is解析网页返回的数据:

    /**
     * 通过is解析网页返回的数据
     * @param is
     * @return
     */
    private String readStream(InputStream is) { 
        InputStreamReader isr;
        String result = "";
        try {
            String line = "";
            isr = new InputStreamReader(is,"utf-8");
            BufferedReader br = new BufferedReader(isr);
            while((line = br.readLine())!=null) {
                result += line;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return result;
        
    }
    

    NewsBean对象代码:

    public String newsIconUrl;
    public String newsTitle;
    public String newsContent;
    
    2.图片异步加载

    通过URL获取Bitmap。使用多线程和AsyncTask异步加载图片两种方式。采用的LruCache缓存图片。
    多线程加载图片:

    public void showImageByThread(ImageView imageView,final String url) {
        mImageView = imageView;
        mUrl = url;
        new Thread(){
            @Override
            public void run() {
                super.run();
                Bitmap bitmap = getBitmapFromURL(url);
                Message message = Message.obtain();
                message.obj = bitmap;
                handler.sendMessage(message);
            }
        }.start();
    }
    

    通过URL获取Bitmap:

    public Bitmap getBitmapFromURL(String urlString) {
        Bitmap bitmap;
        InputStream is = null;
        try {
            URL url = new URL(urlString);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            is = new BufferedInputStream(connection.getInputStream());
            bitmap = BitmapFactory.decodeStream(is);
            connection.disconnect();
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        return null;
        
    }
    

    UI图片效果实现代码:

    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            super.handleMessage(msg);
            if(mImageView.getTag().equals(mUrl)) {
                mImageView.setImageBitmap((Bitmap)msg.obj);
            }
        };
    };
    

    AsyncTask方式异步加载图片:

    public void showImageByAsyncTask(ImageView imageView, String url){
        //从缓存中取出对应的图片
        Bitmap bitmap = getBitmapFromCache(url);
        //如果缓存中没有,那么必须去下载
        if(bitmap == null ){
            //new  NewsAsyncTask(url).execute(url);
            imageView.setImageResource(R.drawable.ic_launcher);
        } else {
            imageView.setImageBitmap(bitmap);
        }
    }
    
    private class NewsAsyncTask extends AsyncTask<String,Void,Bitmap> {
       // private ImageView mImageView;
        private String mUrl;
        
        public NewsAsyncTask(String url) {
            //mImageView = imageView;
            mUrl = url;
        }
        
        @Override
        protected Bitmap doInBackground(String... params) {
            String url = params[0];
            //从网络上获取图片
            Bitmap bitmap = getBitmapFromURL(params[0]);
            if(bitmap !=null) {
                //将不在缓存的图片加入缓存
                addBitmapToCache(url, bitmap);
            }
            return bitmap;
            
        }
        
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            /*if(mImageView.getTag().equals(mUrl)) {
                mImageView.setImageBitmap(result);
            }*/
            ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
            if(imageView != null && bitmap != null) {
                 imageView.setImageBitmap(bitmap);
            }
            mTask.remove(this);
        }
    }
    

    采用的LruCache缓存图片

    public ImageLoader(ListView listview) {
        mListView = listview;
        mTask = new HashSet<NewsAsyncTask>();
        //获取最大可用内存
        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();
            }
        };
    }
    
    //从缓存中获取数据
    public Bitmap getBitmapFromCache(String url) {
        return mCaches.get(url);
        
    }
    
    //增加到缓存
    public void addBitmapToCache(String url, Bitmap bitmap) {
        if(getBitmapFromCache(url) == null ){
            mCaches.put(url, bitmap);
        }
    }
    

    取消异步加载:

    public void cancelAllTasks() {
        if(mTask != null) {
            for(NewsAsyncTask task : mTask) {
                task.cancel(false);
            }
        }
    }
    
    3. 滚动的高效优化

    获取滚动起始数据、图片加载优化、滚动状态判断与处理 首次启动预加载。
    获取滚动起始数据:

    /**
     * @param  firstVisibleItem:第一个可见元素 
     * @param  visibleItemCount 可见元素的总数
     */
    @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;
         }
        
    }
    //滚动状态
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if(scrollState == SCROLL_STATE_IDLE) {
            //加载可见项
            mImageLoader.loadImages(mStart, mEnd);
        } else {
            //停止任务
            mImageLoader.cancelAllTasks();
        }
        
    }
    

    滚动判断与处理

    /**
     * 用来加载从start 到end的所有图片
     * @param start
     * @param end
     */
    public void loadImages(int start, int end) {
        for(int i = start; i < end; i++) {
            String  url = NewsAdapter.URLS[i];
            //从缓存中取出对应的图片
            Bitmap bitmap = getBitmapFromCache(url);
            //如果缓存中没有,那么必须去下载
            if(bitmap == null ){
                NewsAsyncTask task = new NewsAsyncTask(url);
                task.execute(url);
                mTask.add(task);
            } else {
                ImageView imageView = (ImageView) mListView.findViewWithTag(url);
                imageView.setImageBitmap(bitmap);
            }
        }
    }

    相关文章

      网友评论

        本文标题:Anroid- 异步加载

        本文链接:https://www.haomeiwen.com/subject/wimlfxtx.html