我们编程的时候经常需要处理同步任务和异步任务,在Android里面存在一个特性,就是UI线程是不安全的线程。所谓UI线程不安全也就是我们的主线程(进程启动的第一个线程)不能在线程外操作主线程的资源。因为主线程的资源没有做同步处理。也就是我们一般说的线程同步问题。
我们做Android应用的时候,进程需要在一个子线程执行一些耗时的操作,例如下载、播放等。这种情况我们一般使用Handler和线程结合处理,子线程负责处理耗时操作,然后通知Handler处理UI更新。Handler和子线程结合处理适合对精度控制要求比较高或者任务耗时比较长或者比较反复的情况。除了Handler和线程结合使用,Android也为我们提供了另外一种选择,也就是今天要说的AsyncTask。
AsyncTask内部也是使用了Handler和线程的模式,只是Google把它封装好了。下面我们看看AsyncTask如何使用。
(PS:新建的QQ群,有兴趣可以加入一起讨论:Android群:322599434)
1、android.os.AsyncTask的定义
public abstract class AsyncTask<Params, Progress, Result>
- Params:输入的参数
- Progress:更新的进度,一般用来更新UI的进度信息
- Result:是执行后的返回结果
这些参数都是泛型定义,所以我们可以定义自己的数据类型作为参数,另外如果不需要相关传输,可以传入Void即可。
2、AsyncTask接口
//执行异步任务,启动异步任务需要执行这个接口
public final AsyncTask<Params, Progress, Result> execute(Params... params)
{
return executeOnExecutor(sDefaultExecutor, params);
}
//在execute()被调用后立即执行,可以做一些任务初始化
protected void onPreExecute()
{
}
//在onPreExecute()执行后执行,执行一些耗时操作,此方法将接收输入参数和返回计算结果。
//在执行过程中可以调用publishProgress()来更新进度信息
protected abstract Result doInBackground(Params... params);
//在调用publishProgress(Progress... values)时,回调这个方法,用来更新进度信息
protected void onProgressUpdate(Progress... values)
{
}
//doInBackground执行完后,会回调此方法,用于更新界面信息
protected void onPostExecute(Result result)
{
}
上面是AsyncTask的一些重要接口和方法,可以看出大部分都是空方法还有就是虚函数。我们继承AsyncTask的时候,一般都需要重写上面的方法,方便我们执行相应的操作。
3、AsyncTask例子
下面是我编写的一个使用AsyncTask下载图片的例子,这个例子功能是利用AsyncTask下载一张图片。
private class DownLoad extends AsyncTask<String, Integer, String>
{
//onPreExecute方法在execute()后执行
@Override
protected void onPreExecute()
{
Log.i(TAG, "onPreExecute() enter");
mShowLogTextView.setText("onPreExecute。。。begin downLoad");
} //doInBackground方法内部执行后台任务,不能在里面更新UI,否则有异常。
@Override
protected String doInBackground(String... params)
{
Log.i(TAG, "doInBackground(String... params) enter"); URL imageUrl=null;
try
{
imageUrl=new URL(params[]);
}
catch (MalformedURLException e)
{
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
try
{
//使用HttpURLConnection打开连接
HttpURLConnection urlConn=(HttpURLConnection)imageUrl.openConnection();
urlConn.setDoInput(true);
urlConn.connect();
//将得到的数据转化成InputStream
InputStream is=urlConn.getInputStream();
//将InputStream转换成Bitmap
mDownLoadBtBitmap=BitmapFactory.decodeStream(is);
is.close();
//不能在这里更新UI,否则有异常******
//mNetImageView.setImageBitmap(bitmap);
}catch(IOException e)
{
Log.e(TAG,e.getMessage());
} return "ok";
} //onProgressUpdate方法用于更新进度信息
@Override
protected void onProgressUpdate(Integer... progresses)
{
Log.i(TAG, "onProgressUpdate(Integer... progresses) enter"); mShowLogTextView.setText("onProgressUpdate Downloading...");
} //onPostExecute用于doInBackground执行完后,更新界面UI。
//result是doInBackground返回的结果
@Override
protected void onPostExecute(String result)
{
Log.i(TAG, "onPostExecute(Result result) called");
mShowLogTextView.setText("Down load finish result="+result); mNetImageView.setImageBitmap(mDownLoadBtBitmap);
} //onCancelled方法用于取消Task执行,更新UI
@Override
protected void onCancelled()
{
Log.i(TAG, "onCancelled() called");
mShowLogTextView.setText("onCancelled");
}
}
上面是继承了AsyncTask类,重写了里面相关方法的之类,从上面可以看出AsyncTask主要的操作任务都是放到了doInBackground执行。然后onPostExecute最后更新结果。让AsyncTask开始执行 的方法很简单,只要调用execute并传入相关参数即可。
public void onClick(View v)
{
if (v==mPlayMusicButton)
{
//传入下载图片的地址 mythou
mDownLoad.execute("http://pic.desk.chinaz.com/file/10.11.10/7/jillxs40.jpg");
//mDownLoad.execute("http://www.baidu.com/img/bdlogo.gif");
}
}
这里传入的参数是作为doInBackground方法的参数,这里传入图片的URL,然后执行下载图片操作。下面说说AsyncTask使用的时候需要注意的事情。
- AsyncTask的实例必须在UI线程中创建,并且在UI线程调用execute(Params... params)开始任务。
- 不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values), onPostExecute(Result result)等AsyncTask的回调函数。
- 不能在doInBackground(Params... params)中更改UI组件的信息。
- 一个任务实例只能执行一次,如果执行第二次将会抛出异常。
下面是这个例子执行效果:
AsyncTask的Demo代码下载:点击这里
Edited by mythou
原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3191174.html