Android异步加载
16lz
2021-01-26
为什么要异步加载:
为了用户体验,避免卡顿
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);}}
至此,便实现了异步加载网络图片。
更多相关文章
- 初学Android,手势缩放图片(四十八)
- 关于android获得图片的总结
- Android(安卓)debug时一直处于waiting for debugger解决办法
- Android(安卓)Paint类方法说明
- Android(安卓)6种快速开发框架
- 关于Android加载图片时的OOM的一些解决方法和优化
- 浅谈WebView的使用
- 【Android】Android中使用JNI调用底层C++代码
- 2.android中使用锁来兼容netty客户端的写法