Android必学-异步加载

此文,仅做为个人学习Android,记录成长以及方便复习!


本次是通过JSON获取页面数据,异步加载填充ListView

JSON地址:http://www.imooc.com/api/teacher?type=4&num=30

由于图片加载相对比较麻烦,首先第一步实现加载JSON中的标题和内容填充ListView

由于需要访问网络所以需要在清单文件(AndroidManifest.xml)中添加:

 <uses-permission android:name="android.permission.INTERNET"></uses-permission>

在布局文件Maintivity加载的布局文件activity_main.xml中添加LIstView

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

   <ListView
       android:id="@+id/listview"
       android:layout_height="match_parent"
       android:layout_width="match_parent"/>

</RelativeLayout>

添加一个布局文件(items_layout.xml)给自定义的适配器使用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:layout_marginBottom="10dp">
    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="46dp"
        android:layout_height="46dp"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_marginLeft="10dp"
            android:gravity="center"
            >
            <TextView
                android:id="@+id/tv_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxLines="1"
                android:textSize="20sp"
                android:text="Title"/>
            <TextView
                android:id="@+id/tv_context"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:maxLines="2"
                android:text="context"/>
        </LinearLayout>
</LinearLayout>

创建一个Bean对应适配器的布局文件,为AsynTask做准备

package com.rui.asynctaskdemo2;
/**
 *  对应items_layout的Bean
 */

public class NewsBean {
    private String iv_icon;
    private String tv_title;
    private String tv_context;

    public String getIv_icon() {
        return iv_icon;
    }

    public void setIv_icon(String iv_icon) {
        this.iv_icon = iv_icon;
    }

    public String getTv_title() {
        return tv_title;
    }

    public void setTv_title(String tv_title) {
        this.tv_title = tv_title;
    }

    public String getTv_context() {
        return tv_context;
    }

    public void setTv_context(String tv_context) {
        this.tv_context = tv_context;
    }

    public NewsBean(String iv_icon, String tv_title, String tv_context) {
        this.iv_icon = iv_icon;
        this.tv_title = tv_title;
        this.tv_context = tv_context;
    }
    public NewsBean(){

    }
}

创建一个类继承BaseAdapter接口,创建成一个适配器

package com.rui.asynctaskdemo2;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class NewsAdapter extends BaseAdapter{
    private List<NewsBean> nlist;
    private LayoutInflater inflater;

    public NewsAdapter(Context context,List<NewsBean> data){
        //数据源赋值给nlist
        nlist = data;
        //初始化局部对象
        inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() {
        //显示数量是数据源的大小
        return nlist.size();
    }

    @Override
    public Object getItem(int i) {
        //取出索引对应的数据项
        return nlist.get(i);
    }

    @Override
    public long getItemId(int i) {
        //取出数据对应的索引
        return i;
    }

    //返回每一项的显示内容
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder=new ViewHolder();
        //当view为空的时候
        if(view == null){
            //将layout转成View
            view = inflater.inflate(R.layout.items_layout,null);
            //组件ID存入viewHolder
            viewHolder.iv_icon =  view.findViewById(R.id.iv_icon);
            viewHolder.tv_title =  view.findViewById(R.id.tv_title);
            viewHolder.tv_context =  view.findViewById(R.id.tv_context);
            //viewHolder存入view
            view.setTag(viewHolder);
        }else{//当View存在的时候,直接取出赋值给viewHolder
            viewHolder = (ViewHolder) view.getTag();
        }
        //为view赋值
        viewHolder.iv_icon.setImageResource(R.mipmap.ic_launcher);
        viewHolder.tv_title.setText(nlist.get(i).getTv_title());
        viewHolder.tv_context.setText(nlist.get(i).getTv_context());
        return view;
    }
    //内部类,作用优化
    class ViewHolder{
        public TextView tv_title,tv_context;
        public ImageView iv_icon;
    }
}

在Maintivity.java中主要做了以下事情

1.创建一个内部类,继承AsynTask

2.创建一个方法,解析传入的InputStream转换为字符串

3.配置getJsonData方法,解析JSON成需要的数据

package com.rui.asynctaskdemo2;

import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ListView listView; //声明ListView
    //json在线链接
    private static 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 = (ListView)findViewById(R.id.listview);
        NewsAsyncTask nat = new NewsAsyncTask();
        nat.execute(url);
    }


    //解析传入的URl
    public List<NewsBean> getJsonData(String url){
        List<NewsBean> newsBeanList = new ArrayList<NewsBean>();
       try {
            //获取JSON数据
            String jsonString = readStream(new URL(url).openStream());
            //Log.i("info",jsonString);打印是否能获取到JSON数据
            //声明JSONBObject和NewsBean
           JSONObject jsonObject;
           NewsBean newsBean;
           try {
               //实例化JSONObject
               jsonObject = new JSONObject(jsonString);
               //获取数组节点data
               JSONArray jsonArray = jsonObject.getJSONArray("data");
               //循环出去数组中的子节点赋值给NewsBean
               for(int i=0; i<jsonArray.length(); i++){
                   //获取数组中个每个子节点存入JSONObject
                   jsonObject = jsonArray.getJSONObject(i);
                   //实例化NewsBean
                   newsBean = new NewsBean();
                   //赋值
                   newsBean.setIv_icon(jsonObject.getString("picBig"));
                   newsBean.setTv_title(jsonObject.getString("name"));
                   newsBean.setTv_context(jsonObject.getString("description"));
                   //NewsBean加入集合
                   newsBeanList.add(newsBean);
               }
           } catch (JSONException e) {
               e.printStackTrace();
           }
       } catch (IOException e) {
            e.printStackTrace();
        }
        //添加完成返回集合
        return newsBeanList;
    }

    //解析字节流
    @NonNull
    private String readStream(InputStream is){
        //初始化InputStreamReader、result
        InputStreamReader isr;
        StringBuffer result = new StringBuffer();
        try {
            //读取字符暂存
            String line;
            //字节流转字符流并设置编码为UTF-8
            isr = new InputStreamReader(is,"utf-8");
            //字符流转缓冲流
            BufferedReader br =  new BufferedReader(isr);
            //循环趣数据存入result
            while((line = br.readLine())!= null){
                result.append(line);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result.toString();
    }

    //内部类AsyncTask异步加载
    public class NewsAsyncTask extends AsyncTask<String,Void,List<NewsBean>>{

        @Override
        protected List<NewsBean> doInBackground(String... strings) {
            //获取传入的URL,通过getJsonData解析
            return getJsonData(strings[0]);
        }

        @Override
        protected void onPostExecute(List<NewsBean> newsBeans) {
            super.onPostExecute(newsBeans);
            //实例化NewsAdapter 
            NewsAdapter newsAdapter = new NewsAdapter(MainActivity.this,newsBeans);
            //listView添加自定义适配器
            listView.setAdapter(newsAdapter);
        }
    }
}


加载图像之---通过线程方式加载图像

添加一个用来加载图像的类ImageLoader.java

其中getBitmapFromUrl用来把图片URL解析成Bitmap

showImageByThread则是通过getBitmapFromUrl把bitmap传给Handler

最后通过Hander来显示图像

package com.rui.asynctaskdemo2;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by qqazl001 on 2018-04-08..
 * 处理图像的类
 */

public class ImageLoader {
    //声明ImageView 接收showImageByThread传入的值
    ImageView mimageView;
    //用来判断mimageView中的getTag是否包含了url
    String murl;
    //接收线程发送的消息,通过Hanlder实现设置UI
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //判断mimageView中的getTag是否包含了url
            if(mimageView.getTag().equals(murl)){
            mimageView.setImageBitmap((Bitmap) msg.obj);
            }
        }
    };

    //把Bitmap传给Handler
    public void showImagebyThread(final ImageView imageView, final String url){
        new Thread(){
            @Override
            public void run() {
                super.run();
                mimageView = imageView;
                murl = url;
                //通过getBitmapFromUrl将url转成Bitmap
                Bitmap bitmap = getBitmapFromUrl(url);
                //创建一个message
                Message message = Message.obtain();
                //bitmap存入message
                message.obj = bitmap;
                //通过把存放了bitmap的message发送给Handler
                mHandler.sendMessage(message);
            }
        }.start();
    }

    //通过图片的URL解析成Bitmap
    public Bitmap getBitmapFromUrl(String urlString){
        Bitmap bitmap;
        InputStream is = null;
        try {
            //通过url获取图片的字节流
            URL url = new URL(urlString);
            HttpURLConnection connection= (HttpURLConnection) url.openConnection();
            is = new BufferedInputStream(connection.getInputStream());
            //通过Biteamp工程转成bitmap
            bitmap = BitmapFactory.decodeStream(is);
            //关闭connection
            connection.disconnect();
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            //关闭流
            if(is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

把NewsAdapter.java的getView方法修改为,其实也就是把图像加载的类给加入了并传值

    //返回每一项的显示内容
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder=new ViewHolder();
        //当view为空的时候
        if(view == null){
            //将layout转成View
            view = inflater.inflate(R.layout.items_layout,null);
            //组件ID存入viewHolder
            viewHolder.iv_icon =  view.findViewById(R.id.iv_icon);
            viewHolder.tv_title =  view.findViewById(R.id.tv_title);
            viewHolder.tv_context =  view.findViewById(R.id.tv_context);
            //viewHolder存入view
            view.setTag(viewHolder);
        }else{//当View存在的时候,直接取出赋值给viewHolder
            viewHolder = (ViewHolder) view.getTag();
        }
        viewHolder.iv_icon.setImageResource(R.mipmap.ic_launcher);
        ImageView imageView = viewHolder.iv_icon;
        String url = nlist.get(i).getIv_icon();
        //用来解决异步加载错误的问题!
        viewHolder.iv_icon.setTag(url);
        //为view赋值
        new ImageLoader().showImagebyThread(imageView,url);
        viewHolder.tv_title.setText(nlist.get(i).getTv_title());
        viewHolder.tv_context.setText(nlist.get(i).getTv_context());
        return view;
    }

加载图像之---通过AsynTask方式加载图像

添加一个用来加载图像的类ImageLoader.java

其中getBitmapFromUrl用来把图片URL解析成Bitmap

showImageByAsyncTask负责调用AsyncTask实现加载图像

package com.rui.asynctaskdemo2;

import android.content.AsyncTaskLoader;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by qqazl001 on 2018-04-08..
 * 处理图像的类
 */

public class ImageLoader {
    //通过图片URL解析成Bitmap
    public Bitmap getBitmapFromUrl(String urlString){
        Bitmap bitmap;
        InputStream is;
        try {
            //实例化URL类,将URL传入
            URL url = new URL(urlString);
            //打开链接
            HttpURLConnection connection =  (HttpURLConnection) url.openConnection();
            //将图片url转成流
            is = new BufferedInputStream(connection.getInputStream());
            //将流转成Bitmap图像
            bitmap = BitmapFactory.decodeStream(is);
            //关闭链接
           if(connection!=null) {
               connection.disconnect();
           }
            //关闭流
            if(is!=null){
            is.close();
            }
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    //通过AsyncTask异步加载图像
    public void  showImageByAsyntask(ImageView imageView,String url){
        //实现异步加载类,并传值
        new NewsAsynctask(imageView,url).execute(url);
    }

    //内部类,继承异步加载
    class NewsAsynctask extends AsyncTask<String,Void,Bitmap>{
        private ImageView mimageView;
        private String murl;
        //初始化参数
        public NewsAsynctask(ImageView imageView,String url){
            mimageView =  imageView;
            murl = url;
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            //通过getBitmapFromUrl方法,传入URL获取bitmap
            return getBitmapFromUrl(strings[0]);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //判断图像的URL和传入的是否一致,一致则显示,解决显示跳动
            if(mimageView.getTag().equals(murl)){
                //为ImageView设置图像
                mimageView.setImageBitmap(bitmap);
            }
        }
    }
}

把NewsAdapter.java的getView方法修改为,其实也就是把图像加载的类给加入了并传值

    //返回每一项的显示内容
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder=new ViewHolder();
        //当view为空的时候
        if(view == null){
            //将layout转成View
            view = inflater.inflate(R.layout.items_layout,null);
            //组件ID存入viewHolder
            viewHolder.iv_icon =  view.findViewById(R.id.iv_icon);
            viewHolder.tv_title =  view.findViewById(R.id.tv_title);
            viewHolder.tv_context =  view.findViewById(R.id.tv_context);
            //viewHolder存入view
            view.setTag(viewHolder);
        }else{//当View存在的时候,直接取出赋值给viewHolder
            viewHolder = (ViewHolder) view.getTag();
        }
        //为view赋值
        //设置默认显示的图像
        viewHolder.iv_icon.setImageResource(R.mipmap.ic_launcher);
        viewHolder.tv_title.setText(nlist.get(i).getTv_title());
        viewHolder.tv_context.setText(nlist.get(i).getTv_context());
        //设置图像
        ImageView mImageView = viewHolder.iv_icon;
        String mUrl = nlist.get(i).getIv_icon();
        //获取URL存入setTag,配合gettag 获取来匹配解决异步加载的错乱问题
        mImageView.setTag(mUrl);
        new ImageLoader().showImageByAsyntask(mImageView,mUrl);
        return view;
    }

为项目添加缓存(Lru)

1.初始化缓存,设置大小为可用内存的4分之1

2.添加2个方法,一个添加数据到缓存,一个取出

3.配置方法,在显示图像前判断缓存中是否存在,如果存在则直接使用缓存,不存在则加载并存入缓存

package com.rui.asynctaskdemo2;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.widget.ImageView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by qqazl001 on 2018-04-08..
 * 处理图像的类
 */

public class ImageLoader {
    //声明缓冲
    private LruCache<String,Bitmap> mLruCache;
    public ImageLoader(){
        //获取最大可用内存
        int maxMemory = (int)Runtime.getRuntime().maxMemory();
        //最大可用内存的4分之1
        int cachesize = maxMemory / 4;
        //实例化缓存类,并实现匿名内部类
        mLruCache = new LruCache<String,Bitmap>(cachesize){
            //匿名内部类
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //每次存入缓存时调用,查看Bitmap值的大小
                return value.getByteCount();
            }
        };
    }

    //增加内容到缓存
    public  void addBitmapToCache(String url,Bitmap bitmap){
        if(getBitmapFromUrl(url)==null){
            mLruCache.put(url,bitmap);
        }
    }
    //从缓存中读取
    public Bitmap getBitmapFromCache(String url){
        return mLruCache.get(url);
    }

    //通过图片URL解析成Bitmap
    public Bitmap getBitmapFromUrl(String urlString){
        Bitmap bitmap;
        InputStream is;
        try {
            //实例化URL类,将URL传入
            URL url = new URL(urlString);
            //打开链接
            HttpURLConnection connection =  (HttpURLConnection) url.openConnection();
            //将图片url转成流
            is = new BufferedInputStream(connection.getInputStream());
            //将流转成Bitmap图像
            bitmap = BitmapFactory.decodeStream(is);
            //关闭链接
           if(connection!=null) {
               connection.disconnect();
           }
            //关闭流
            if(is!=null){
            is.close();
            }
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    //通过AsyncTask异步加载图像
    public void  showImageByAsyntask(ImageView imageView,String url){
        //从缓存中获取图片
        Bitmap bitmap = getBitmapFromCache(url);
        if(bitmap==null){
            //实现异步加载类,并传值
            new NewsAsynctask(imageView,url).execute(url);
        }else{
            imageView.setImageBitmap(bitmap);
        }

    }

    //内部类,继承异步加载
    class NewsAsynctask extends AsyncTask<String,Void,Bitmap>{
        private ImageView mimageView;
        private String murl;
        //初始化参数
        public NewsAsynctask(ImageView imageView,String url){
            mimageView =  imageView;
            murl = url;
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            Bitmap bitmap = getBitmapFromUrl(strings[0]);
            if(bitmap!=null){
                addBitmapToCache(strings[0],bitmap);
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //判断图像的URL和传入的是否一致,一致则显示,解决显示跳动
            if(mimageView.getTag().equals(murl)){
                //为ImageView设置图像
                mimageView.setImageBitmap(bitmap);
            }
        }
    }
}

最后一步优化,滑动的时候不加载图像,让他开心的去滑,等滑动结束,再加载图像!

1.添加滑动的监听事件implements AbsListView.OnScrollListener

2.添加滑动加载滑动后可见项和滑动不加载的方法

滑动不加载的方法cancelAllTask()
停止滑动后加载图像的方法 loadImage()

3.添加解决首次启动不加载图像的逻辑

MainActivit.java当中NewsAsyncTask在适配器传入listView

    //内部类AsyncTask异步加载
    public class NewsAsyncTask extends AsyncTask<String,Void,List<NewsBean>>{

        @Override
        protected List<NewsBean> doInBackground(String... strings) {
            //获取传入的URL,通过getJsonData解析
            return getJsonData(strings[0]);
        }

        @Override
        protected void onPostExecute(List<NewsBean> newsBeans) {
            super.onPostExecute(newsBeans);
            //实例化NewsAdapter
            NewsAdapter newsAdapter = new NewsAdapter(MainActivity.this,newsBeans,listView);
            //listView添加自定义适配器
            listView.setAdapter(newsAdapter);
        }
    }

适配器NewsAdapter添加是监听事件

package com.rui.asynctaskdemo2;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.List;

public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener{
    private List<NewsBean> nlist;
    private LayoutInflater inflater;
    private ImageLoader mimageLoader;
    //设置一个布尔值,用来初始化界面时候,解决启动页面没有滑动不加载图像问题
    private boolean mFirstIn;
    //保存滑动后的第一项和最后一项
    private int mStrat,mEnd;
    //存放所有图片的URL
    public static String[] URLS;

    public NewsAdapter(Context context,List<NewsBean> data,ListView listView){
        //数据源赋值给nlist
        nlist = data;
        //初始化局部对象
        inflater = LayoutInflater.from(context);
        //初始化图像加载类,在构造方法初始化,配合缓存
       mimageLoader = new ImageLoader(listView);
       //初始化数组=数据源大小
       URLS = new String[data.size()];
        //所有图片的URL存入URLS数组
        for(int i=0;i<data.size();i++){
            URLS[i] = data.get(i).getIv_icon();
        }
        //为ListView设置滑动监听事件
        listView.setOnScrollListener(this);
        //初始化为true,表示首次启动需要加载图像
        mFirstIn = true;
    }

    @Override
    public int getCount() {
        //显示数量是数据源的大小
        return nlist.size();
    }

    @Override
    public Object getItem(int i) {
        //取出索引对应的数据项
        return nlist.get(i);
    }

    @Override
    public long getItemId(int i) {
        //取出数据对应的索引
        return i;
    }

    //返回每一项的显示内容
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder=new ViewHolder();
        //当view为空的时候
        if(view == null){
            //将layout转成View
            view = inflater.inflate(R.layout.items_layout,null);
            //组件ID存入viewHolder
            viewHolder.iv_icon =  view.findViewById(R.id.iv_icon);
            viewHolder.tv_title =  view.findViewById(R.id.tv_title);
            viewHolder.tv_context =  view.findViewById(R.id.tv_context);
            //viewHolder存入view
            view.setTag(viewHolder);
        }else{//当View存在的时候,直接取出赋值给viewHolder
            viewHolder = (ViewHolder) view.getTag();
        }
        //为view赋值
        //设置默认显示的图像
        viewHolder.iv_icon.setImageResource(R.mipmap.ic_launcher);
        viewHolder.tv_title.setText(nlist.get(i).getTv_title());
        viewHolder.tv_context.setText(nlist.get(i).getTv_context());
        //设置图像
        ImageView mImageView = viewHolder.iv_icon;
        String mUrl = nlist.get(i).getIv_icon();
        //获取URL存入setTag,配合gettag 获取来匹配解决异步加载的错乱问题
        mImageView.setTag(mUrl);
        mimageLoader.showImageByAsyntask(mImageView,mUrl);
        return view;
    }
    //滑动状态切换下调用
    @Override
    public void onScrollStateChanged(AbsListView absListView, int i) {
        if(i == SCROLL_STATE_IDLE){
            //停止状态加载可见项
            mimageLoader.loadImage(mStrat,mEnd);
        }else{
            //停止任务
            mimageLoader.cancelAllTask();
        }
    }
    //滑动状态调用
    @Override
    public void onScroll(AbsListView absListView, int i, int i1, int i2) {
        mStrat =  i;//第一个可见元素
        mEnd = i+i1;//第一个可见元素+可见元素长度=最后一个可见元素
        //首次启动软件 mFirstIn为True且可见元素大于0个的时候,加载图像
        if(mFirstIn && i1 >0){
            mimageLoader.loadImage(mStrat,mEnd);
            //设置为False,软件首次启动加载之后,次逻辑结束!
            mFirstIn = false;
        }
    }

    //内部类,作用优化
    class ViewHolder{
        public TextView tv_title,tv_context;
        public ImageView iv_icon;
    }
}

ImageLoader.java添加了加载可见项图像和取消加载方法

package com.rui.asynctaskdemo2;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by qqazl001 on 2018-04-08..
 * 处理图像的类
 */

public class ImageLoader {
    //初始化ListView
    private ListView mlistView;
    //把NewsAsynctask都存入一个集合,便于管理
    private Set<NewsAsynctask> mtask;
    //声明缓冲
    private LruCache<String,Bitmap> mLruCache;

    public ImageLoader(ListView listView){
        mlistView = listView;
        mtask = new HashSet<>();
        //获取最大可用内存
        int maxMemory = (int)Runtime.getRuntime().maxMemory();
        //最大可用内存的4分之1
        int cachesize = maxMemory / 4;
        //实例化缓存类,并实现匿名内部类
        mLruCache = new LruCache<String,Bitmap>(cachesize){
            //匿名内部类
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //每次存入缓存时调用,查看Bitmap值的大小
                return value.getByteCount();
            }
        };
    }

    //滑动的时候取消加载
    public void cancelAllTask(){
        //集合中有NewsAsyncTask,不为空
        if(mtask != null){
            //遍历取出其中的taks,并标记为false,便于调用销毁停止
            for(NewsAsynctask task :mtask ){
                task.cancel(false);
            }
        }
    }
    //滑动时加载图像
    public void  loadImage(int strat, int end){
        //根据可见项获取设置图像
        for(int i=strat;i<end;i++){
            //从所有图像的UR'LS集合中依次取出存入url
            String url = NewsAdapter.URLS[i];
            //从缓存中获取图片
            Bitmap bitmap = getBitmapFromCache(url);
            //缓存中没有保存图像
            if(bitmap==null){
                //通过NewsAsynctask加载
                NewsAsynctask task = new NewsAsynctask(url);
                task.execute(url);
                //并把NewsAsynctask存入集合,便于管理
                mtask.add(task);
            }else{
                //通过Tag查找ListView中对应的 ImageView
                ImageView imageView = mlistView.findViewWithTag(url);
                //把从缓存中获取的bitmap设置到ImageView
                imageView.setImageBitmap(bitmap);
            }
        }
    }

    //增加内容到缓存
    public  void addBitmapToCache(String url,Bitmap bitmap){
        if(getBitmapFromUrl(url)==null){
            mLruCache.put(url,bitmap);
        }
    }
    //从缓存中读取
    public Bitmap getBitmapFromCache(String url){
        return mLruCache.get(url);
    }

    //通过图片URL解析成Bitmap
    public Bitmap getBitmapFromUrl(String urlString){
        Bitmap bitmap;
        InputStream is;
        try {
            //实例化URL类,将URL传入
            URL url = new URL(urlString);
            //打开链接
            HttpURLConnection connection =  (HttpURLConnection) url.openConnection();
            //将图片url转成流
            is = new BufferedInputStream(connection.getInputStream());
            //将流转成Bitmap图像
            bitmap = BitmapFactory.decodeStream(is);
            //关闭链接
           if(connection!=null) {
               connection.disconnect();
           }
            //关闭流
            if(is!=null){
            is.close();
            }
            return bitmap;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    //通过AsyncTask异步加载图像
    public void  showImageByAsyntask(ImageView imageView,String url){
        //从缓存中获取图片
        Bitmap bitmap = getBitmapFromCache(url);
        if(bitmap==null){
          imageView.setImageResource(R.mipmap.ic_launcher);
        }else{
            imageView.setImageBitmap(bitmap);
        }

    }

    //内部类,继承异步加载
    class NewsAsynctask extends AsyncTask<String,Void,Bitmap>{
        private ImageView mimageView;
        private String murl;
        //初始化参数
        public NewsAsynctask(String url){
            murl = url;
        }

        @Override
        protected Bitmap doInBackground(String... strings) {
            Bitmap bitmap = getBitmapFromUrl(strings[0]);
            if(bitmap!=null){
                addBitmapToCache(strings[0],bitmap);
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
//            //判断图像的URL和传入的是否一致,一致则显示,解决显示跳动
//            if(mimageView.getTag().equals(murl)){
//                //为ImageView设置图像
//                mimageView.setImageBitmap(bitmap);
//            }
            //从ListView获取ImageView
            ImageView imageView = mlistView.findViewWithTag(murl);
            //ImageVIew不为空和图像不为空的时候,为ImageView设置图像
            if(imageView !=null && bitmap!=null){
                imageView.setImageBitmap(bitmap);
            }
            //设置完图像之后,从mtask集合中移除
            mtask.remove(this);
        }
    }
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值