转载请说明出处,欢迎转载。http://write.blog.csdn.net/postedit/51533261
本篇博客总结了慕课网关于异步加载图片的知识要点,和大家一起分享,有感觉听得不连贯的可以来看看。
看完本篇博客,你将学习到下面的知识:
1.怎样将一个url(也可以说是一个InputStream)转换为一个json字符串信息。
2.怎样运用插件写一个我认为完美的model类来为解析json做准备。
3.AsyncTask的基本用法。
4.Gosn的基本用法。
5.Adapter的常用优化写法。
6.通过LruCache缓存已经加载的图片。
7.listview高效加载复杂item布局。
8.编写json实体类的AS小插件。
好了,直接上代码,代码里面有详细的解释。
package com.robin.loadimageinlistview; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.ListView; import com.google.gson.Gson; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.List; public class MainActivity extends AppCompatActivity { private ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.lv_main); String URL1 = "http://www.imooc.com/api/teacher?type=4&num=30"; new MyAsyncTask().execute(URL1); } class MyAsyncTask extends AsyncTask<String, Void, List<NewsBean.BeanData>> {//<strong><span style="color:#ff0000;">(知识点3)</span></strong> @Override protected List<NewsBean.BeanData> doInBackground(String... params) { return getJsonData(params[0]); } @Override protected void onPostExecute(List<NewsBean.BeanData> beanDatas) { super.onPostExecute(beanDatas); NewsAdapter adapter = new NewsAdapter(MainActivity.this, beanDatas, listView); listView.setAdapter(adapter); } } /** * 通过URL获取json字符串<strong><span style="color:#ff0000;">(知识点2)</span></strong> * * @param url * @return List<NewsBean.BeanData> */ private List<NewsBean.BeanData> getJsonData(String url) { String jsonString = null; try { jsonString = readStream(new URL(url).openStream()); } catch (IOException e) { e.printStackTrace(); } Gson gson = new Gson(); if(jsonString==null||"".equals(jsonString))return null;//如果jsonString返回有问题,就不解析了。 NewsBean newsBean = gson.fromJson(jsonString, NewsBean.class);//<span style="color:#ff0000;"><strong>(知识点4)</strong></span>需要将Gosn的包导入进project中。怎么导,就不详细说了,去Google return newsBean.getData(); } /** * 怎样将一个url(也可以说是一个InputStream)转换为一个json字符串信息。<strong><span style="color:#ff0000;">(知识点1)</span></strong> * * @param is * @return String */ private String readStream(InputStream is) { String result = ""; InputStreamReader isr; String line; try { isr = new InputStreamReader(is, "utf-8");//字节流转化为字符流 BufferedReader br = new BufferedReader(isr); while ((line = br.readLine()) != null) { result += line; } } catch (IOException e) { e.printStackTrace(); } return result; } }
package com.robin.loadimageinlistview; 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.BeanData> newsBeans; private LayoutInflater mInflater; private ImageLoader imageLoader; private int mStart,mEnd; public static String[] URLS;//存放要加载的图片的url private boolean isFirst = false;//控制第一次进入listview的时候加载数据 public NewsAdapter(Context context, List<NewsBean.BeanData> newsBeans, ListView listView) {//初始化数据 this.newsBeans = newsBeans; this.mInflater = LayoutInflater.from(context); imageLoader = new ImageLoader(listView);// 确保只有一个LruCache URLS = new String[newsBeans.size()]; for (int i=0;i<newsBeans.size();i++){//获取newsBeans中的图片的url URLS[i] = newsBeans.get(i).getPicSmall(); } isFirst = true; listView.setOnScrollListener(this); } @Override public int getCount() { return newsBeans.size(); } @Override public Object getItem(int position) { return newsBeans.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder;//利用viewholder进行优化,这一点也是写类似listview的adapter的getView方法的一个模板。 if(convertView==null){ viewHolder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item_layout,null); 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{//如果convertView不为空就不用再次去加载布局了,因为加载布局耗时很长,造成listview的卡顿 viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.ivIcon.setImageResource(R.mipmap.ic_launcher); String url = newsBeans.get(position).getPicSmall(); viewHolder.ivIcon.setTag(url);//将url作为tag imageLoader.showImageByAsyncTask(viewHolder.ivIcon,url); viewHolder.tvTitle.setText(newsBeans.get(position).getName()); viewHolder.tvContent.setText(newsBeans.get(position).getDescription()); return convertView; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) {//滑动状态改变时调用<span style="color:#ff0000;"><strong>(知识点7)</strong></span> if(scrollState==SCROLL_STATE_IDLE){//停止滚动,加载可见项 imageLoader.loadImage(mStart,mEnd); }else{//停止加载 imageLoader.cancelAllTask(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {//整个滑动的时候都会调用 mStart = firstVisibleItem;//第一个可见元素 mEnd =firstVisibleItem+visibleItemCount;//最后一个可见元素=第一个可见元素+可见元素的数量 if(isFirst && visibleItemCount > 0){//第一次加载的时候调用,显示图片 imageLoader.loadImage(mStart,mEnd); isFirst=false; } } class ViewHolder{ public TextView tvTitle; public TextView tvContent; public ImageView ivIcon; } }对 知识点7的一点解释,当item布局非常复杂的时候,这是用户区频繁滚动listview,listview会频繁调用getView方法去获取item,导致卡顿,然而,平常的使用过程中,我们发现一般用户滚动的时候不太注意内容,停止滚动的时候才回去看内容,因此我们考虑如果将显示内容的权利从getView中移交给滚动事件处理的话,这个问题就能得到解决。
接下来上最重要的控制图片缓存以及加载的类
package com.robin.loadimageinlistview; 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.URL; import java.util.HashSet; import java.util.Set; public class ImageLoader { private LruCache<String,Bitmap> cache;//用于缓存图片 private ListView listView; private Set<NewsAsyncTask> mTask;//管理AsyncTask public ImageLoader(ListView listView) {//初始化一些数据 this.listView = listView; this.mTask = new HashSet<>(); int maxMemry = (int) Runtime.getRuntime().maxMemory();//获取当前应用可用的最大内存 int cacheSize = maxMemry/4;//以最大的四分之一作为可用的缓存大小 this.cache = new LruCache<String,Bitmap>(cacheSize){//初始化LruCache @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount();//每次存入缓存的大小,即bitmap的大小 } }; } /** * 将内容保存到LruCache * @param url * @param bitmap */ public void addBitmapToCache(String url,Bitmap bitmap){ if(getBitmapFromCache(url)==null){//如果没有保存的话就保存。 cache.put(url,bitmap); } } /** * 从LruCache中获取bitmap * @param url * @return Bitmap */ public Bitmap getBitmapFromCache(String url){ return this.cache.get(url); } /** * 将图片url转化为bitmap * @param urlString * @return 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 (IOException e) { e.printStackTrace(); }finally { try { if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } public void showImageByAsyncTask(ImageView imageView,String url){//改进之后,获取图片的控制权由原来getview改成了滚动状态。 Bitmap bitmap = getBitmapFromCache(url);//从缓存中获取图片 if(bitmap==null){//如果没有就设置默认的图片 imageView.setImageResource(R.mipmap.ic_launcher); }else{//如果有就设置当前的图片 imageView.setImageBitmap(bitmap); } } private class NewsAsyncTask extends AsyncTask<String,Void,Bitmap>{ private String url; public NewsAsyncTask(String url) { this.url = url; } @Override protected Bitmap doInBackground(String... params) { String url = params[0]; Bitmap bitmap = getBitmapFromUrl(url);//获取网络图片 if(bitmap!=null){ addBitmapToCache(url,bitmap); //将不在缓存的图片加载的缓存中去 } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); ImageView imageView =(ImageView) listView.findViewWithTag(url); if(imageView!=null&&bitmap!=null){//判断这个url所对应的imageview是否对应,对应的话才设置图片, imageView.setImageBitmap(bitmap); } } } /** * 加载从start到end的所有图片 * @param start * @param end */ public void loadImage(int start,int end){ for (int i= start;i<end;i++){//拿到数组中的图片对应的url String url = NewsAdapter.URLS[i]; Bitmap bitmap = getBitmapFromCache(url); if(bitmap==null){//没有就要去下载 NewsAsyncTask newsAsyncTask = new NewsAsyncTask(url); newsAsyncTask.execute(url); mTask.add(newsAsyncTask); }else{ ImageView imageView =(ImageView) listView.findViewWithTag(url);//通过findViewWithTag找到imageview,这个tag就是imageview的url imageView.setImageBitmap(bitmap); } } } public void cancelAllTask() { if(mTask!=null){ for (NewsAsyncTask task:mTask) { task.cancel(false); } } } }
https://github.com/zzz40500/GsonFormat
好了,大概就这些了,上传一张效果图
最后感谢大家,喜欢请点赞,有疑问,可以回复交流,有错误,请指出。Thx。
转载请说明出处,欢迎转载。http://write.blog.csdn.net/postedit/51533261
阿斯顿