ListView的网络加载(使用LRU缓存,滚动监听器)
public class MainActivity extends AppCompatActivity { private List<Newsbeans> mlist; private static String url="http://www.imooc.com/api/teacher?type=4&num=30"; private ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Myaysctask myaysctask=new Myaysctask(); //将url传递进去实现对于url的异步访问 new Myaysctask().execute(url); listView= (ListView) findViewById(R.id.listview); } //将url转化为我们所需要的json对象 private List<Newsbeans> getjsondata(String url){ //初始化list mlist=new ArrayList<>(); JSONObject jsonObject; Newsbeans newsbeans; try { //获取字节流 String jsonstring= readStream(new URL(url).openStream()); //将传入的字节流转化为json对象 jsonObject=new JSONObject(jsonstring); //得到json下的data下的数组 JSONArray jsonArray=jsonObject.getJSONArray("data"); for(int i=0;i<jsonArray.length();i++){ //遍历json数组的到jsonobject的值 jsonObject=jsonArray.getJSONObject(i); newsbeans=new Newsbeans(); //将jsonobject中的值赋予到已经封装好的值之中,通过getString方法获得 newsbeans.newscontent=jsonObject.getString("description"); newsbeans.newspic=jsonObject.getString("picSmall"); newsbeans.newstitle=jsonObject.getString("name"); //将newsbeans添加到list之中 mlist.add(newsbeans); } } catch (IOException | JSONException e) { e.printStackTrace(); } return mlist; } private String readStream(InputStream is){ String result=""; String line=""; try { //将inputstream传入的为字节流,通过inputstreamreader将字节流转换为字符流 InputStreamReader irs=new InputStreamReader(is,"utf-8"); //通过bufferedreader将输入流读取出来 BufferedReader br= new BufferedReader(irs); while ((line= br.readLine())!=null){ result+=line; } } catch (IOException e) { e.printStackTrace(); } return result; } class Myaysctask extends AsyncTask<String,Void,List<Newsbeans>>{ @Override //进行所有的耗时操作但不包括更改UI protected List<Newsbeans> doInBackground(String... strings) { //将string数组中的0位返回也就是传入url return getjsondata(strings[0]); } @Override protected void onPostExecute(List<Newsbeans> newsbeans) { Myadapter myadapter=new Myadapter(MainActivity.this,newsbeans,listView); listView.setAdapter(myadapter); super.onPostExecute(newsbeans); } } }
在mainactivity中从网络中获取JSON数组,并转化为JSON对象,通过AsyncTask使用异步线程下载数据,并封装在已经设置好的空间中以及在子线程中设置UI,通过Myadapter对象传递参数用于在BaseAdapter中设置监听事件和设置ListView
public class ImageviewHolder { //设置全局变量 private String mURL; private LruCache<String,Bitmap> mCache; private Set<MyAsynctask> mTask; private ListView mListView; public ImageviewHolder(ListView listview){ //在构造方法中初始化LruCache mListView=listview; mTask=new HashSet<>(); //获取当前系统的最大的运行内存 int MaxMem= (int) Runtime.getRuntime().maxMemory(); //设置当前的缓存的内存 int CacheMem=MaxMem/2; mCache=new LruCache<String,Bitmap>(CacheMem){ //重写sizeof方法,获取缓存图片的大小 @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; } private void addBitMapToCache(String url,Bitmap bitmap){ //自定义方法,在判断所需的图片没有在缓存中存在的时候,将其放入到缓存之中 if(getBitMapFromCache(url)==null){ mCache.put(url,bitmap); } } private Bitmap getBitMapFromCache(String url){ return mCache.get(url); } public void showImageBy(ImageView imageView,String mURL) { Bitmap bitmap= getBitMapFromCache(mURL); /* * 判断在缓存中的图片是否存在,如果不存在则通过网络下载图片,其实这个方法在设定onScrollListener之后的作用 * 已经失效了,只是作为一个在没有加载的时候初始化图标的功能。 * */ if (bitmap==null){ imageView.setImageResource(R.mipmap.ic_launcher); }else { imageView.setImageBitmap(bitmap); } } public void imageLoder(int start,int end){ //传递进来新的参数,在当前屏幕上的第一个和最后一个的可见项 for (int i=start;i<end;i++){ //获取到从第一个开始到最后一个结束的图片所对应的一个url,并对每一个url进行判断 String url=Myadapter.mURLs[i]; //加载我们所定义的一组imageview Bitmap bitmap= getBitMapFromCache(url); //判断在缓存中的图片是否存在,如果不存在则通过网络下载图片 if (bitmap==null){ MyAsynctask task =new MyAsynctask(url); task.execute(url); //将task对象放入一个set集合之中,统一的做管理,如果listview不在滚动的时候就将其全部取消加载 mTask.add(task); }else { ImageView imageView= (ImageView) mListView.findViewWithTag(url); imageView.setImageBitmap(bitmap); } } } public void cancelTask(){ if (mTask!=null){ for (MyAsynctask task:mTask){ task.cancel(false); } } } public Bitmap getbitmapstream(String bitmapurl) throws IOException { InputStream is=null; //指向互联网资源的指针 URL url=new URL(bitmapurl); //打开连接,并强行转换格式 HttpURLConnection connection= (HttpURLConnection) url.openConnection(); //获取输入的数据流 is=new BufferedInputStream(connection.getInputStream()); //解析所传入的数据 Bitmap bitmap= BitmapFactory.decodeStream(is); //断开连接 connection.disconnect(); return bitmap; } public class MyAsynctask extends AsyncTask<String,Void,Bitmap> { //通过AsyncTask通过网络下载图片,如果下载的图片不在缓存中则放入缓存中 private ImageView mImageView; private String mURL; public MyAsynctask(String url){ mURL=url; } @Override protected Bitmap doInBackground(String... strings) { String url=strings[0]; //从网络获取图片 Bitmap bitmap = null; try { bitmap = getbitmapstream(url); } catch (IOException e) { e.printStackTrace(); } //将不在缓存的图片加入缓存 if (bitmap!=null){ addBitMapToCache(url,bitmap); } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); ImageView imageView= (ImageView) mListView.findViewWithTag(mURL); if (bitmap!=null&&imageView!=null){ imageView.setImageBitmap(bitmap); } mTask.remove(this); } } }
在ImageHolder中设置BaseAdapter中所要获取的方法,设置Lru,若所要获取的图片已经存在则从缓存中获取,若没有在缓存中则需要从从网络中下载(也就是通过自定义方法通过url下载),通过传递进来的屏幕中的第一个和最后一个的item位置,通过for循环,为每一个item设置图片,如果已经存在则从缓存中取出,在找所要定义的imageview的时候,通过已经提前为imageview设置好的tag也就是对应的url找到
public class Myadapter extends BaseAdapter implements AbsListView.OnScrollListener { private Context mContext; private List<Newsbeans> mlist; private ListView mListView; private LayoutInflater mlayoutinflater; private boolean mFirstIntial; //如果使用new ImageViewHolder方法创建则每次调用都会创建一个新的LRUCache,通过定义全局变量确保只有一个LRUCACHE创建 public ImageviewHolder mImageViewHolder; private int mStart,mEnd; public static String mURLs[]; public Myadapter(Context context, List<Newsbeans> mlist1,ListView listView){ mlist=mlist1; mListView=listView; mFirstIntial=true; //初始化字符数组的大小 mURLs=new String[mlist.size()]; //获取管理器 mlayoutinflater=LayoutInflater.from(context); mImageViewHolder=new ImageviewHolder(mListView); mListView.setOnScrollListener(this); for (int i=0;i<mlist1.size();i++){ mURLs[i]=mlist.get(i).newspic; } } @Override public int getCount() { return mlist.size(); } @Override public Object getItem(int i) { return mlist.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View convertview, ViewGroup viewGroup) { Viewholder viewholder=null; if(convertview==null){ viewholder=new Viewholder(); //将item的layout文件转化为view,必须是item文件在之后的view中还要找到对应的控件 convertview=mlayoutinflater.inflate(R.layout.item,null); viewholder.contenttext= (TextView)convertview.findViewById(R.id.tv_content); viewholder.imageView=(ImageView)convertview.findViewById(R.id.imageview); viewholder.titletext=(TextView)convertview.findViewById(R.id.tv_title); convertview.setTag(viewholder); } else { viewholder=(Viewholder)convertview.getTag(); } Newsbeans newsbeans=mlist.get(i); viewholder.imageView.setImageResource(R.mipmap.ic_launcher); //调用方法传递所需信息 mImageViewHolder.showImageBy(viewholder.imageView,mlist.get(i).newspic); viewholder.imageView.setTag(mlist.get(i).newspic); viewholder.titletext.setText(newsbeans.newstitle); viewholder.contenttext.setText(newsbeans.newscontent); return convertview; } @Override public void onScrollStateChanged(AbsListView absListView, int i) { if(i==SCROLL_STATE_IDLE){ //如果listview不在滑动状态 mImageViewHolder.imageLoder(mStart,mEnd); }else{ //如果listview在滑动状态 mImageViewHolder.cancelTask(); } } @Override public void onScroll(AbsListView absListView, int i, int i1, int i2) { mStart=i; mEnd=i+i1; /* * i为firstvisbieitem,i1为visbileItemCount,i2为totalitemcount * 在这里判断是否为第一次加载和listview是否开始加载,若没开始加载的时候可见项(visbleitem为0) * * */ if (mFirstIntial&&i1>0){ mImageViewHolder.imageLoder(mStart,mEnd); mFirstIntial=false; } } class Viewholder{ public TextView titletext; public TextView contenttext; public ImageView imageView; } }
通过设置BaseAdapter的onScrollListener接口,在OnScrollChanged方法中设定在只有在滑动后停止的时候才加载所需要的图片,若没有滑动的时候取消所有加载