为什么要异步加载:

为了用户体验,避免卡顿

Android系统要求使用异步加载,耗时操作会阻塞UI线程

异步加载的常用的方式:

多线程/线程池

AsyncTask


以下以加载网络图片为示例

在主类之外声明一个单独的MyBean类:

class MyBean{public String MyIconUrl;public String MyTitle;public String MyContent;} 

和一个MyAdapter类:

public class MyAdapter extends BaseAdapter{private List mList;private LayoutInflater mInflater;public MyAdapter(Context context, List data){mList = data;mInflater = LayoutInflater.from(context);}public int getCount(){return mList.size();}public Object getItem(int position){return mList.get(position);}public long getItemId(int position){return position;}public View getView(int position, View convertView, ViewGroup parent){ViewHolder viewHolder = null;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{viewHolder = (ViewHolder)convertView.getTag();}viewHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);//这是使用默认的ic_launcher作为图标
//-----------------下述是调用异步加载图片的内容作为图标
new ImageLoader().showImageByThread(viewHolder.ivIcon, mList.get(position).myIconUrl);
//-----------------viewHolder.tvTitle.setText(mList.get(position).MyTitle);viewHolder.tvContent.setText(mList.get(position).MyContent);return convertView;}class ViewHolder{public TextView tvTitle, tvContent;public ImageView ivIcon;}}

接下来是主类中的方法:

private ListView mListView;private static String URL = "http://www.xxxxxxxxx.com/xxx/xxx/xxx";protected void OnCreate(Bundle savedInstanceState){super.OnCreate(savedInstanceState);setContentView(R.Layout.activity_main);mListView = (ListView)findViewById(R.id.lv_main);new MyAsyncTask().execute(URL);}

private List getJsonData(String url){//将Url的Json数据转化为所封装的MyBean对象List myBeanList = new ArrayList<>();try{String jsonString = readStream(new URL(url).openStream());//上述语句功能与url.openConnection().getInputStream()相同,//可根据URL直接联网获取网络数据,简单粗暴,返回值类型为InputStreamJSONObject jsonObject;MyBean myBean;try{jsonObject = new jsonObject(jsonString);JSONArray jsonArray = jsonObject.getJSONArray("data");for(int i =0;i>{//实现网络的异步访问protected List doInBackground(String... params){return getJsonData(params[0]);}protected void onPostExecute(List myBean){super.onPostExecute(myBean);MyAdapter adapter = new MyAdapter(MainActivity.this, myBean );mListView.setAdapter(adapter);}}
上述实现了ListView图文混排

接下来是对图像的异步加载:

public class ImageLoader{private ImageView mImageView;private Handler mHandler = new Handler();private Handler handler = new Handler(){public void handleMessage(Message msg){super.handleMessage(msg);mImageView.setImageBitmap((Bitmap)msg.obj);}}public void showImageByThread(ImageView imageView, String url){mImageView = imageView;new Thread(){public void run(){super.run();Bitmap bitmao = getBitmapFromURL(url);Message message = Message.obtain();message.obj = bitmap;mHandler.sendMessage(message);}}.start();}public Bitmap getBitmapFromURL(String urlStirng){Bitmap bitmap;InputStream is;try{URL url = new URL(urlStirng);HttpURLConnection connection = (HttpURLConnection)url.openConnection();is = new BufferedInputStream(connection.getInputStream());bitmap = BitmapFactory.decodeStream(is);connection.disconnect();return bitmap;}catch(java.io.IOException e){e.printStackTrace();}finally{is.close();}return null;}}
事实上,上面的方法,在网速不是很快的时候,会出现刷新时图片错乱的现象,因为ListView的缓存机制导致图片显示错位,则只需要改进一步,在MyAdapter类中的getView()方法中增加三行代码:

viewHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);String utl = mList.get(position).MyIconUrl;viewHolder.ivIcon.setTag(utl);new ImageLoader().showImageByThread(viewHolder.ivIcon, url);viewHolder.tvTitle.setText(mList.get(position).MyTitle);viewHolder.tvContent.setText(mList.get(position).MyContent);return convertView;
之后在ImageLoader类中handleMessage()方法中增加判断语句,最终修改为:

public class ImageLoader{private ImageView mImageView;private Handler mHandler = new Handler();private String mUrl;private Handler handler = new Handler(){public void handleMessage(Message msg){super.handleMessage(msg);if(mImageView.getTag().equals(mUrl))mImageView.setImageBitmap((Bitmap)msg.obj);}}public void showImageByThread(ImageView imageView, String url){mImageView = imageView;mUrl = url;new Thread(){public void run(){super.run();Bitmap bitmao = getBitmapFromURL(url);Message message = Message.obtain();message.obj = bitmap;mHandler.sendMessage(message);}}.start();}public Bitmap getBitmapFromURL(String urlStirng){Bitmap bitmap;InputStream is;try{URL url = new URL(urlStirng);HttpURLConnection connection = (HttpURLConnection)url.openConnection();is = new BufferedInputStream(connection.getInputStream());bitmap = BitmapFactory.decodeStream(is);connection.disconnect();return bitmap;}catch(java.io.IOException e){e.printStackTrace();}finally{is.close();}return null;}}
一般有两种办法避免ListView的缓存特性带来的ListView的Item的错乱,一种是在BaseAdapter中设置tag,将身份验证信息与相应的Item绑定,在加载时判断身份验证信息是否正确,正确才设置图片操作,第二种,是使用成员变量,将对应的数据进行缓存,从而避免网络下载时间不确定导致的时序的混乱。大部分的异步加载错误都可以使用这两种办法解决。


使用AsyncTask()方法异步加载

public void showImageByAsyncTask(ImageView imageView, String url){new MyAsyncTask(imageView).execute(url);}private class MyAsyncTask extends AsyncTask{private ImageView imageView;public MyAsyncTask(ImageView imageView){mImageView = imageView;}protected Bitmap doInBackground(String... params){return getBitmapFromURL(params[0]);}protected void onPostExecute(Bitmap bitmap){super.onPostExecute(bitmap);mImageView.setImageBitmap(bitmap);}}

之后再回到MyAdapter类中,将多线程的方法加载图片的语句换掉:

//new ImageLoader().showImageByThread(viewHolder.ivIcon, url);new ImageLoader().showImageByAsyncTask(viewHolder.ivIcon, url);
同样,AsyncTask方法也会出现刷新时图片错乱的现象,因为AsyncTask本身就是基于多线程,所以对其进行处理,修改之后:

public void showImageByAsyncTask(ImageView imageView, String url){new MyAsyncTask(imageView, url).execute(url);}private class MyAsyncTask extends AsyncTask{private ImageView imageView;private String mUrl;public MyAsyncTask(ImageView imageView, String url){mImageView = imageView;mUrl = url;}protected Bitmap doInBackground(String... params){return getBitmapFromURL(params[0]);}protected void onPostExecute(Bitmap bitmap){super.onPostExecute(bitmap);if(mImageView.getTag().equals(mUrl))mImageView.setImageBitmap(bitmap);}}

至此,便实现了异步加载网络图片。








更多相关文章

  1. 初学Android,手势缩放图片(四十八)
  2. 关于android获得图片的总结
  3. Android(安卓)debug时一直处于waiting for debugger解决办法
  4. Android(安卓)Paint类方法说明
  5. Android(安卓)6种快速开发框架
  6. 关于Android加载图片时的OOM的一些解决方法和优化
  7. 浅谈WebView的使用
  8. 【Android】Android中使用JNI调用底层C++代码
  9. 2.android中使用锁来兼容netty客户端的写法

随机推荐

  1. Android——四大组件、六大布局、五大存
  2. 自定义ListView分割线
  3. Android事件分发机制完全解析(二)
  4. Android基础学习【历史流程重走】 ---- A
  5. achartengine(Google给android提供的绘图
  6. Android添加自定义系统服务
  7. Android开发Tips(3)
  8. android loginDemo +WebService用户登录
  9. android 实现指定wifi切换
  10. Android 开发艺术探索笔记(五) 之 Android