一、AsyncTask介绍
Android提供了几种在其他线程中访问UI线程的方法。
Activity.runOnUiThread( Runnable ) View.post( Runnable ) View.postDelayed( Runnable, long ) Hanlder
这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。
为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。不需要借助线程和Handler即可实现。
AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。
◆Params 启动任务执行的输入参数,比如HTTP请求的URL。
◆Progress 后台任务执行的百分比。
◆Result 后台执行任务最终返回的结果,比如String。
AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。
子类化AsyncTask
实现AsyncTask中定义的下面一个或几个方法
onPreExecute()
该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。
doInBackground(Params...)
将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
onProgressUpdate(Progress...)
在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result)
在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.
为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI thread中创建
2) execute方法必须在UI thread中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
4) 该task只能被执行一次,否则多次调用时将会出现异常
针对主线程和AsyncTask子线程的调用关系如下图:
1>主线程调用AsynTask子类实例的execute()方法后,首先会调用onPreExecute()方法。onPreExecute()在主线程中运行,可以用来写一些开始提示代码。
2>之后启动新线程,调用doInBackground()方法,进行异步数据处理。
3>处理完毕之后异步线程结束,在主线程中调用onPostExecute()方法。onPostExecute()可以进行一些结束提示处理。
补充:在doInBackground()方法异步处理的时候,如果希望通知主线程一些数据(如:处理进度)。这时,可以调用publishProgress()方法。这时,主线程会调用AsynTask子类的onProgressUpdate()方法进行处理。
各个函数间数据的传递
通过上面的调用关系,我们就可以大概看出一些数据传递关系。如下:
execute()向doInBackground()传递。
doInBackground()的返回值会传递给onPostExecute()。
publishProgress()向progressUpdate()传递。
要点:为了调用关系明确及安全,AsynTask类在继承时要传入3个泛型。第一个泛型对应execute()向doInBackground()的传递类型。第二个泛型对应doInBackground()的返回类型和传递给onPostExecute()的类型。第三个泛型对应publishProgress()向progressUpdate()传递的类型。
传递的数据都是对应类型的数组,数组都是可变长的哦。可以根据具体情况使用。
二、图片异步下载举例说明
1.首先定义一个简单布局:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context=".MainActivity" > 10 11 <Button 12 android:id="@+id/btndownload" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:layout_alignParentBottom="true" 16 android:layout_centerHorizontal="true" 17 android:text="DOWNLOAD" /> 18 19 <EditText 20 android:id="@+id/texturl" 21 android:layout_width="wrap_content" 22 android:layout_height="wrap_content" 23 android:layout_above="@+id/btndownload" 24 android:layout_centerHorizontal="true" 25 android:ems="10" > 26 27 <requestFocus /> 28 </EditText> 29 30 <ImageView 31 android:id="@+id/imageView1" 32 android:layout_width="wrap_content" 33 android:layout_height="wrap_content" 34 android:layout_alignParentTop="true" 35 android:layout_centerHorizontal="true" 36 android:layout_above="@id/texturl" 37 android:src="@drawable/ic_launcher" /> 38 39 </RelativeLayout>
2.别忘了加上网络访问权限
1 <uses-sdk 2 android:minSdkVersion="8" 3 android:targetSdkVersion="18" /> 4 <uses-permission android:name="android.permission.INTERNET"/>
3.进入到MainActivity进入主要代码编写
1 package com.example.android_asynctask_download; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 7 import org.apache.http.HttpResponse; 8 import org.apache.http.HttpStatus; 9 import org.apache.http.client.HttpClient; 10 import org.apache.http.client.methods.HttpGet; 11 import org.apache.http.impl.client.DefaultHttpClient; 12 13 import android.os.AsyncTask; 14 import android.os.Bundle; 15 import android.app.Activity; 16 import android.app.ProgressDialog; 17 import android.graphics.Bitmap; 18 import android.graphics.BitmapFactory; 19 import android.view.Menu; 20 import android.view.View; 21 import android.view.View.OnClickListener; 22 import android.widget.Button; 23 import android.widget.EditText; 24 import android.widget.ImageView; 25 26 public class MainActivity extends Activity { 27 28 private Button button; 29 private ImageView imageView; 30 private EditText texturl; 31 private String pic_pathString = "http://b.hiphotos.baidu.com/image/h%3D1200%3Bcrop%3D0%2C0%2C1920%2C1200/sign=165d5bcf9f16fdfac76cc2ec84bfb737/bf096b63f6246b60bd811290e9f81a4c500fa243.jpg"; 32 private ProgressDialog progressDialog; 33 34 @Override 35 protected void onCreate(Bundle savedInstanceState) { 36 super.onCreate(savedInstanceState); 37 setContentView(R.layout.activity_main); 38 39 button = (Button) this.findViewById(R.id.btndownload); 40 imageView = (ImageView) this.findViewById(R.id.imageView1); 41 texturl = (EditText) this.findViewById(R.id.texturl); 42 texturl.setText(pic_pathString); 43 progressDialog = new ProgressDialog(this); 44 progressDialog.setTitle("提示信息"); 45 progressDialog.setMessage("正在下载,请稍后..."); 46 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); 47 button.setOnClickListener(new OnClickListener() { 48 49 @Override 50 public void onClick(View v) { 51 // TODO Auto-generated method stub 52 pic_pathString = texturl.getText().toString(); 53 new mytask().execute(pic_pathString); 54 } 55 }); 56 57 } 58 59 public class mytask extends AsyncTask<String, Integer, Bitmap> { 60 @Override 61 protected void onPreExecute() { 62 // TODO Auto-generated method stub 63 // super.onPreExecute(); 64 progressDialog.show(); 65 } 66 67 @Override 68 protected Bitmap doInBackground(String... params) { 69 // // TODO Auto-generated method stub 70 // Bitmap bitmap = null; 71 // HttpClient httpClient = new DefaultHttpClient(); 72 // HttpGet httpGet = new HttpGet(params[0]); 73 // try { 74 // HttpResponse httpResponse = httpClient.execute(httpGet); 75 // if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 76 // byte[] data = EntityUtils.toByteArray(httpResponse 77 // .getEntity()); 78 // bitmap = BitmapFactory 79 // .decodeByteArray(data, 0, data.length); 80 // } 81 // } catch (ClientProtocolException e) { 82 // // TODO Auto-generated catch block 83 // e.printStackTrace(); 84 // } catch (IOException e) { 85 // // TODO Auto-generated catch block 86 // e.printStackTrace(); 87 // } 88 // 89 // return bitmap; 90 91 //完成对图片的下载和进度数值的更新 92 Bitmap bitmap = null; 93 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 94 InputStream inputStream = null; 95 try { 96 HttpClient httpClient = new DefaultHttpClient(); 97 HttpGet httpGet = new HttpGet(params[0]); 98 HttpResponse httpResponse = httpClient.execute(httpGet); 99 if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 100 inputStream = httpResponse.getEntity().getContent(); 101 //先要获得文件的总长度 102 long file_length = httpResponse.getEntity().getContentLength(); 103 int len = 0; 104 byte[] data = new byte[128]; 105 int total_length = 0; 106 while ((len = inputStream.read(data)) != -1) { 107 total_length+=len; 108 int value = (int)((total_length/(float)file_length)*100); 109 publishProgress(value); 110 outputStream.write(data, 0, data.length); 111 } 112 byte[] result = outputStream.toByteArray(); 113 bitmap = BitmapFactory.decodeByteArray(result, 0, result.length); 114 } 115 } catch (Exception e) { 116 // TODO: handle exception 117 }finally{ 118 if(inputStream != null) 119 { 120 try { 121 inputStream.close(); 122 } catch (IOException e) { 123 // TODO Auto-generated catch block 124 e.printStackTrace(); 125 } 126 } 127 } 128 129 return bitmap; 130 } 131 132 @Override 133 protected void onProgressUpdate(Integer... values) { 134 // TODO Auto-generated method stub 135 //super.onProgressUpdate(values); 136 progressDialog.setProgress(values[0]); 137 } 138 139 @Override 140 protected void onPostExecute(Bitmap result) { 141 // TODO Auto-generated method stub 142 // super.onPostExecute(result); 143 progressDialog.dismiss(); 144 imageView.setImageBitmap(result); 145 } 146 147 } 148 149 @Override 150 public boolean onCreateOptionsMenu(Menu menu) { 151 // Inflate the menu; this adds items to the action bar if it is present. 152 getMenuInflater().inflate(R.menu.main, menu); 153 return true; 154 } 155 156 }
在手机上运行的样子:
谢谢耐心阅读,希望对您有些帮助。