Android异步加载
Posted Sharley
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android异步加载相关的知识,希望对你有一定的参考价值。
Android异步加载
一、为什么要使用异步加载?
1.android是单线程模型
2.耗时操作阻碍UI线程
二、异步加载最常用的两种方式
1.多线程、线程池
2.AsyncTask
三、实现ListView图文混排
3-1 实现读取网页中的json数据到ListView中 (图片首先为默认图片)
3.1.1:主布局只有一个ListView和一个listView_item的布局
3.1.2:网页json数据的链接(http://www.imooc.com/api/teacher?type=4&num=30),打开后为json数据,开发者可以通过使用Json格式化工具进行清楚的查看json数据的信息
3.1.3:书写解析网页JSON数据的代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109package
cn.edu.bzu.async_listview;
import
java.io.BufferedReader;
import
java.io.IOException;
import
java.io.InputStream;
import
java.io.InputStreamReader;
import
java.io.UnsupportedEncodingException;
import
java.util.ArrayList;
import
java.util.List;
import
java.net.MalformedURLException;
import
java.net.URL;
import
org.json.JSONArray;
import
org.json.JSONException;
import
org.json.JSONObject;
import
android.app.Activity;
import
android.os.AsyncTask;
import
android.os.Bundle;
import
android.util.Log;
import
android.widget.ListView;
public
class
MainActivity
extends
Activity {
private
ListView mListView;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView=(ListView) findViewById(R.id.lv_main);
new
NewAsyncTask().execute(URL);
}
/**
*实现网络的异步访问
*/
class
NewAsyncTask
extends
AsyncTask<String, Void, List<NewsBean> >{
//参数:params:传入值 progress :进程 Result:返回值
@Override
protected
List<NewsBean> doInBackground(String... params) {
return
getJsonData(params[
0
]);
//得到从url读取的JSON数据
}
@Override
protected
void
onPostExecute(List<NewsBean> newsBean) {
// 将生成的newsBean设置给ListView
super
.onPostExecute(newsBean);
NewsAdapter adapter=
new
NewsAdapter(MainActivity.
this
, newsBean);
//创建适配器对象
mListView.setAdapter(adapter);
}
}
/**
* 将url对应的json数据转换为我们所封装的NewsBean对象
* @param url
* @return newsList
*/
private
List<NewsBean> getJsonData(String url) {
List<NewsBean> newsBeanList=
new
ArrayList<NewsBean>();
try
{
String jsonString=readStream(
new
URL(url).openStream());
//此句功能与url.openConnection().getInputStream()相同,可根据URL直接联网获取数据,返回值类型 InputStream;
//Log.d("json",jsonString ); 打印读取的json信息
//解析json数据
JSONObject jsonObject;
NewsBean newsBean;
//用于封装jsonObject
jsonObject=
new
JSONObject(jsonString);
//json数据添加到jsonObject中
JSONArray jsonArray=jsonObject.getJSONArray(
"data"
);
//取出json中的data数据,data为一个数组类型
for
(
int
i=
0
;i<jsonArray.length();i++){
//取出data中的数据
jsonObject=jsonArray.getJSONObject(i);
newsBean=
new
NewsBean();
newsBean.imgIconUrl=jsonObject.getString(
"picSmall"
);
newsBean.newsTitle=jsonObject.getString(
"name"
);
newsBean.newsContent=jsonObject.getString(
"description"
);
newsBeanList.add(newsBean);
}
}
catch
(IOException e) {
e.printStackTrace();
}
catch
(JSONException e) {
e.printStackTrace();
}
return
newsBeanList;
}
/**
* 通过inputStream解析网页所返回的数据
* @param is
* @return result
*/
private
String readStream(InputStream is){
InputStreamReader isr;
String result=
""
;
try
{
String line=
""
;
//每行的数据
isr=
new
InputStreamReader(is,
"utf-8"
);
//字节流转换为字符流
BufferedReader br=
new
BufferedReader(isr);
//将字符流以buffer的形式读取出来
while
((line=br.readLine())!=
null
){
result+=line;
//拼接到result中
}
}
catch
(UnsupportedEncodingException e) {
e.printStackTrace();
}
catch
(IOException e) {
e.printStackTrace();
}
return
result;
}
}
思路解析:
1) 一个内部类继承AsyncTask,书写未实现的方法,其中在方法中有一个doBackground()方法,在其方法中书写得到Json数据的方法
2) 书写通过inputStream解析网页所返回的数据,只有拿到网页中的json数据才能实现解析的操作
3)将url对应的json数据转换为我们所封装的NewsBean对象,在这个方法中,我们通过第二步拿到了json数据,然后进行json数据的解析,并且封装到实体类对象中,这样你的实体类中就有解析的json数据了
4)创建ListView的适配器
5)在继承AsyncTask的类中书写onPostExecute()方法,在这个方法中,实现绑定适配器,加载数据源的操作
6)在onCreate方法中执行这个异步操作:new NewAsyncTask().execute(URL);并且传入url地址
7)在清单文件中添加联网权限 <use-permission android:name="android.permission.INTERNET"/>
3-2 实现在ListView中添加网络中图片
&由于加载图片是一种耗时操作,所以我们可以通过新建Thread的方法或者继承AsyncTask来实现
3.2.1:我们通过新线程的方式来实现加载网络图片,新建ImageLoader.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
package cn.edu.bzu.async_listview; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.os.Message; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.widget.ImageView; /** * 用于处理图片的加载 * @author monster * */ public class ImageLoader { private ImageView mImageView; private String mUrl; /** * UI主线程 */ private Handler mHandler= new Handler(){ public void handleMessage(Message msg) { super .handleMessage(msg); //通过设置tag属性避免缓存图片对正确图片的影响 if (mImageView.getTag().equals(mUrl)){ mImageView.setImageBitmap((Bitmap) msg.obj); } }; }; /** * 通过多线程的方式加载图片 * @param imageView * @param url */ public void showImageByThread(ImageView imageView, final String url){ mImageView=imageView; //将ImageView保存进成员变量中 mUrl=url; new Thread(){ @Override public void run() { super .run(); Bitmap bitmap=getBitmapFromURL(url); Message message=Message.obtain(); message.obj=bitmap; mHandler.sendMessage(message); //将内容发送到Handle线程中 } }.start(); } /** * 通过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(); //打开链接 //注意是:HttpURLConnection而不是HttpsURLConnection is= new BufferedInputStream(connection.getInputStream()); bitmap=BitmapFactory.decodeStream(is); //将这个流转换为bitmap connection.disconnect(); //资源释放 return bitmap; } catch (java.io.IOException e) { e.printStackTrace(); } finally { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } return null ; } } |
思路解析:
1)新建一个线程来实现加载图片
2)创建加载图片的方法,方法的参数为图片的url,这个url可以通过解析刚才的json数据得到
1HttpURLConnection connection=(HttpURLConnection) url.openConnection();
//打开链接 //注意是:HttpURLConnection而不是HttpsURLConnection
通过这条语句,将连接转化成流,然后得到流,最后将流转换为bitmap对象
3)得到bitmap对象后,我们新建Handler线程,在这个线程中进行图片的更换,由于bitmap在我们的新线程中,所以我们通过handler的消息传递进行将bitmap对象传入到主线程中去
4)由于ListView的缓存机制,所以我们通过在适配器为图片设置tag的方法从而实现图片的正确加载,避免导致图片的来回替换
在Handler中,我们通过通过设置判断tag属性,来判断图片的url是否相等
附录:ListView适配器的代码:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263package
cn.edu.bzu.async_listview;
import
java.util.List;
import
android.content.Context;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.BaseAdapter;
import
android.widget.ImageView;
import
android.widget.TextView;
public
class
NewsAdapter
extends
BaseAdapter {
private
List<NewsBean> mList;
private
LayoutInflater mInflater;
public
NewsAdapter(Context context,List<NewsBean> data){
mList=data;
mInflater=LayoutInflater.from(context);
}
@Override
public
int
getCount() {
return
mList.size();
}
@Override
public
Object getItem(
int
position) {
return
mList.get(position);
}
@Override
public
long
getItemId(
int
position) {
return
position;
}
@Override
public
View getView(
当活动中的异步任务完成时如何在片段中重新加载ui?
如何延迟或异步此 WordPress javascript 片段以最后加载以加快页面加载时间?
Android 逆向类加载器 ClassLoader ( 类加载器源码简介 | BaseDexClassLoader | DexClassLoader | PathClassLoader )(代码片段