Android异步加载

为什么要异步加载:

为了用户体验,避免卡顿

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

异步加载的常用的方式:

多线程/线程池

AsyncTask


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

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

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

和一个MyAdapter类:

public class MyAdapter extends BaseAdapter{
	private List<MyBean> mList;
	private LayoutInflater mInflater;

	public MyAdapter(Context context, List<MyBean> 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<MyBean> getJsonData(String url){
	//将Url的Json数据转化为所封装的MyBean对象
	List<MyBean> myBeanList = new ArrayList<>();
	try{
		String jsonString = readStream(new URL(url).openStream());
		//上述语句功能与url.openConnection().getInputStream()相同,
		//可根据URL直接联网获取网络数据,简单粗暴,返回值类型为InputStream
		JSONObject jsonObject;
		MyBean myBean;
		try{
			jsonObject = new jsonObject(jsonString);
			JSONArray jsonArray = jsonObject.getJSONArray("data");
			for(int i =0;i<jsonArray.length();i++){
				jsonObject = jsonArray.getJSONObject(i);
				myBean = new MyBean();
				myBean.MyIconUrl = jsonObject.getString("picSmall");
				myBean.MyTitle = jsonObject.getString("name");
				myBean.MyContent = jsonObject.getString("description");
				myBeanList.add(myBean);
				//循环完毕时,将所有数据加入MyBean对象中,之后就可以将数据设置在ListView中
			}
		}catch(JSONException e){
			e.printStackTrace();
		}
	}catch(IOException e){
		e.printStackTrace();
	}
	return myBeanList;
}

private String readStream(InputStream is){

	//通过InputStream解析网页返回的数据
	InputSrteamReader isr;
	String result = "";
	try{
		String line = "";
		isr = new InputStream(is, "utf-8");
		BufferedReader br = new BufferedReader(isr);
		while((line = br.readLine())!= null){
			result+=line;
		}
	}catch(UnsupportedEncodingException e){
		e.printStackTrace();
	}catch(IOException e){
		e.printStackTrace();
	}
	return result;
}


class MyAsyncTask extends AsyncTask<String, Void, List<MyBean>>{
	//实现网络的异步访问
	protected List<MyBean> doInBackground(String... params){
		return getJsonData(params[0]);
	}

	protected void onPostExecute(List<MyBean> 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<String, Void, Bitmap>{
	
	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<String, Void, Bitmap>{
	
	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);
	}
}

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








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值