Android AsyncTask 基本使用
我们知道Android的activity如果没有在5秒内处理完某个事件,将会触发一个ANR事件,该事件将会极大地影响用户体验。
使用Android 的AsyncTask可以以后台线程的形式更新用户界面,可在程序中用来处理一些耗时的操作。
比如实现一个从网络上抓取图片显示在一个ImageView中,效果如下图:
布局文件main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn" android:text="Get Image" android:onClick="download" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/progress" android:text="hello" /> <ImageView android:id="@+id/img" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
Activity文件
import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; public class AndroidServiceActivity extends Activity { private DownloadTask mDownloadTask; private final String TAG = "AndroidService"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 如果切换了配置,比如横竖屏切换,需要重新让contex和AsyncTask建立连接 if((mDownloadTask = (DownloadTask)getLastNonConfigurationInstance())!=null){ mDownloadTask.setmContext(this); if(mDownloadTask.getStatus() == AsyncTask.Status.FINISHED){ mDownloadTask.setImageInView(); } } } /** * 视图上点击按钮触发的事件 * @param view */ public void download(View view){ if(mDownloadTask != null){ AsyncTask.Status diStatus = mDownloadTask.getStatus(); if(diStatus!=AsyncTask.Status.FINISHED){ Log.i("AndroidService", "... no need to start a new task!"); return; } } mDownloadTask = new DownloadTask(this); mDownloadTask.execute("http://10.0.2.2:8088/pamdps/images/icon.png"); Log.i("AndroidService", "download"); } /** * 如果切换了配置,比如横竖屏切换,需要重新让contex和AsyncTask建立连接 */ @Override public Object onRetainNonConfigurationInstance() { Log.i(TAG, "onRetainNonConfigurationInstance"); return mDownloadTask; } }
后台异步线程DownloadTask.java
public class DownloadTask extends AsyncTask<String, Integer, Bitmap>{ private Context mContext; Bitmap downloadedImage = null; private final String TAG = "AndroidService"; public DownloadTask(Context context) { super(); this.mContext = context; } /** * 供主线程在更改配置后重新设置该Task的context * @param mContext */ public void setmContext(Context mContext) { Log.v(TAG, "setContext"); this.mContext = mContext; } @Override protected Bitmap doInBackground(String... urls) { return downloadImage(urls); } @Override protected void onPostExecute(Bitmap result) { if(result!=null){ downloadedImage = result; setImageInView(); }else{ Log.e(TAG, "download image error"); } } @Override protected void onPreExecute() { super.onPreExecute(); } @Override protected void onProgressUpdate(Integer... values) { TextView mText = (TextView) ((Activity)mContext).findViewById(R.id.progress); mText.setText("Progress so far:"+values[0]); super.onProgressUpdate(values); } /** * 执行图片的下载 * @param urls * @return */ private Bitmap downloadImage(String... urls) { HttpParams httpParameters; int timeoutConnection = 3000; int timeoutSocket = 5000; httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established. HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT) // in milliseconds which is the timeout for waiting for data. HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); HttpGet request = new HttpGet(urls[0]); Log.i(TAG, urls[0]); HttpClient httpClient = new DefaultHttpClient(httpParameters); httpClient.getParams().setParameter("", 5000); HttpResponse response; try { publishProgress(25); response = httpClient.execute(request); Log.i("", response.getStatusLine().getStatusCode()+""); if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ publishProgress(50); //这一句是为了测试横竖屏切换时是否能正常显示下载的图片,预留切换时间 sleepFor(5000); byte[] image = EntityUtils.toByteArray(response.getEntity()); publishProgress(75); Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length); publishProgress(100); return bitmap; }else{ } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } protected void setImageInView(){ ImageView mImage = (ImageView) ((Activity)mContext).findViewById(R.id.img); mImage.setImageBitmap(downloadedImage); } private void sleepFor(long msecs){ try { Thread.sleep(msecs); } catch (InterruptedException e) { Log.v("", e.getMessage()); } } }
需要在清单文件中添加网络访问权限
<!-- 网络访问权限 --> <uses-permission android:name="android.permission.INTERNET" />
使用AsyncTask包括4个步骤
1、在onPreExecute中执行设置工作,该方法在主线程中执行。
2、使用doInBackground运行后台线程。线程创建全部在后台完成。
3、publishProgress()和onProgressUpdate()来更新进度,前者在doInBackground()中调用,后缀在主线程中执行,所以用这两个方法可以是后台线程在运行期间和主线程通信。
4、onPostExecute()用来更新用户界面,在主线程中执行。
本实例包含以下知识点:
1、httpclient的基本使用方法
2、httpclient的超时设置
3、AsyncTask的基本使用
4、切换横竖屏后Activity和AsyncTask重新建立连接的方法
说明:本文章是参考《精通Android3》第11章写的,权当学习笔记。</