很久之前的一次笔试中见到过AsyncTask 这个东西,一直不太懂怎么使用。
隔了很长时间,终于找了个时间仔细地系统地学习了AsyncTask的使用。
从学习的结果来看,感觉比多线程简单一点,不用写Handler之类的通信类,直接可以修改UI。
从网上查了一下,大致的区别就是,如果程序需要使用异步修改UI,最好使用AsyncTask ,
否则使用Thread更好。
AsyncTask 主要有4个方法,
第一个是doInBackground
这个方法主要是异步处理的核心
一般异步的主要操作都在这个方法里面完成。
然后就是onPreExecute和onPostExecute
一个是执行在doInBackground之前 一个是之后。
之前的是做一些初始化的操作
onPostExecute就是异步操作之后的动作 例如更新UI之类的。
然后我就参照着imooc上的 写了一个异步加载慕课网课程的小demo
这是程序的效果图
下面上代码。
package com.example.myapplication;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
public class MainActivity extends Activity {
//声明ListView
private ListView mListView;
//声明获取课程信息的URL变量
private static String URL = "http://www.imooc.com/api/teacher?type=4&num=30";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化ListView
mListView = (ListView)findViewById(R.id.lv_main);
//创建AsyncTask对象 并且运行 将URL作为参数传入
new NewAsyncTask().execute(URL);
}
//AsyncTask内部类 传入String 要返回一个Bean对象的List集合作为数据源
class NewAsyncTask extends AsyncTask<String , Void , List<NewsBean>>{
//异步操作的方法
protected List<NewsBean> doInBackground(String... params) {
//将URL作为参数传给getJsonData方法
return getJsonData(params[0]);
}
//当doInBackground完成以后 运行onPostExecute方法
//创建一个BaseAdapter对象,context是MainActivity ,数据源为newsBeans
@Override
protected void onPostExecute(List<NewsBean> newsBeans) {
// TODO Auto-generated method stub
super.onPostExecute(newsBeans);
NewsAdapter adapter = new NewsAdapter(MainActivity.this, newsBeans);
//ListView 设置适配器
mListView.setAdapter(adapter);
}
}
private List<NewsBean> getJsonData(String url) {
//创建一个NewsBean的List集合
List<NewsBean> newsBeanList = new ArrayList<NewsBean>();
try {
//打开数据流 从URL上读取Json数据
String jsonString = readStream(new URL(url).openStream());
//Log.d("Main", jsonString);
//以下是解析Json数据 并将Json数据保存到Bean对象中 然后再将Bean对象add到List中去 作为Adapter的数据源
JSONObject jsonObject;
NewsBean newsBean;
jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray("data");
for(int i = 0 ; i < jsonArray.length() ; i++){
jsonObject = jsonArray.getJSONObject(i);
newsBean = new NewsBean();
newsBean.setNewsIconUrl(jsonObject.getString("picSmall"));
newsBean.setNewsTitle(jsonObject.getString("name"));
newsBean.setNewsContent(jsonObject.getString("description"));
newsBeanList.add(newsBean);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return newsBeanList;
}
//以下是读取数据流的具体方法
private String readStream(InputStream is){
InputStreamReader isr;
String result = "";
try {
String line = "";
isr = new InputStreamReader(is,"utf-8");//字节流转化为字符流
BufferedReader br = new BufferedReader(isr);
while((line = br.readLine()) != null){
result += line;
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
}
package com.example.myapplication;
public class NewsBean {
//Bean对象 Model
private String newsIconUrl;
private String newsTitle;
private String newsContent;
public String getNewsIconUrl() {
return newsIconUrl;
}
public void setNewsIconUrl(String newsIconUrl) {
this.newsIconUrl = newsIconUrl;
}
public String getNewsTitle() {
return newsTitle;
}
public void setNewsTitle(String newsTitle) {
this.newsTitle = newsTitle;
}
public String getNewsContent() {
return newsContent;
}
public void setNewsContent(String newsContent) {
this.newsContent = newsContent;
}
}
package com.example.myapplication;
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{
//适配器类 重写BaseAdapter
private List<NewsBean> mList;
private LayoutInflater mInflater;
//mInflater获取当前的Context
public NewsAdapter(Context ctx , List<NewsBean> mList){
this.mList = mList;
mInflater = LayoutInflater.from(ctx);
}
//获取数据源的大小
public int getCount() {
return mList.size();
}
//获取数据源的当前的item
public Object getItem(int position) {
return mList.get(position);
}
//获取数据源的当前的item ID
public long getItemId(int position) {
return position;
}
//获取当前数据源的View
public View getView(int position, View convertView, ViewGroup parent) {
//这里用到了ViewHolder作为优化
//就可以不用每一次运行这个方法就调用一次findViewById 节省时间
ViewHolder viewHolder = null;
if(convertView == null){
//当convertView为空时,创建一个ViewHolder对象,将当前item的布局传给convertView
//并且将item.xml中的组件传递给viewHolder保存
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);
//保存完以后将viewHolder传给convertView保存
convertView.setTag(viewHolder);
}else{
//如果convertView存在的时候,就将保存在convertView中的viewHolder赋值给当前的viewHolder
viewHolder =(ViewHolder) convertView.getTag();
}
//以下是设置组件内容的操作
String url = mList.get(position).getNewsIconUrl();
viewHolder.ivIcon.setImageResource(R.drawable.ic_launcher);
//解析图片的URL 返回bitmap类型的图片 set在ivIcon中
viewHolder.ivIcon.setTag(url);
//以下是获取bitmap的两种方法 一种是使用AsyncTask 另一种是使用多线程的方法
//new ImageLoader().showImageByThread(viewHolder.ivIcon, url);
new ImageLoader().showImageByAsyncTask(viewHolder.ivIcon, url);
viewHolder.tvTitle.setText(mList.get(position).getNewsTitle());
viewHolder.tvContent.setText(mList.get(position).getNewsContent());
return convertView;
}
class ViewHolder{
public TextView tvTitle;
public TextView tvContent;
public ImageView ivIcon;
}
}
package com.example.myapplication;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
public class ImageLoader {
private ImageView mImageView;
private String url;
//Handler作为线程间的通信 将返回的message设置为imageview的图片
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (mImageView.getTag().equals(url)) {
mImageView.setImageBitmap((Bitmap) msg.obj);
}
};
};
//使用多线程的方法获取图片
public void showImageByThread(ImageView imageView, final String url) {
mImageView = imageView;
this.url = url;
new Thread() {
public void run() {
super.run();
Bitmap bitmap = getBitmapFromURL(url);
Message message = Message.obtain();
message.obj = bitmap;
mHandler.sendMessage(message);
}
}.start();
;
}
//具体将图片从缓冲流转为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();
// Thread.sleep(1000);
return bitmap;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
//使用AsyncTask方法从URL上获取图片
public void showImageByAsyncTask(ImageView imageView , String url){
new NewsAsyncTask(imageView , url).execute(url);
}
private class NewsAsyncTask extends AsyncTask<String , Void ,Bitmap>{
private String url;
private ImageView imageview;
public NewsAsyncTask(ImageView imageview , String url){
this.imageview = imageview;
this.url = url;
}
@Override
protected Bitmap doInBackground(String... params) {
return getBitmapFromURL(params[0]);
}
@Override
//在异步操作完以后 可以直接修改UI
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
if(imageview.getTag().equals(url)){
this.imageview.setImageBitmap(result);
}
}
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.myapplication.MainActivity" >
<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dp" >
<ImageView
android:id="@+id/iv_icon"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/ic_launcher" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="4dp"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="15sp"
android:text="Title"
android:maxLines="1"/>
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="3"
android:textSize="10sp"
android:text="Content" />
</LinearLayout>
</LinearLayout>