Android AsyncTask 异步任务
【AsyncTask】
1、前面已经介绍过,Android的UI线程主要负责处理用户的按键事件、用户触屏事件及屏幕绘图事件等,因此开发者的其他操作不应该、也不能阻塞UI线程,否则UI界面将会变得停止响应——用户感觉非常糟糕。我们可以开辟一个新的线程来解决这个问题,同时Android中为了简化我们的负担,引进了一个异步任务处理类AsyncTask类
2、 AsyncTask<>是一个抽象类,通常用于被继承,继承AsyncTask时需要指定如下三个泛型参数。
相对来说AsyncTask更加轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。
AsyncTask<Params,Progress,Result>是抽象类,它定义了如下三种泛型类型。
- Params:启动任务执行的输入参数的类型。
- Progress:后台任务完成的进度值的类型。
- Result:后台执行任务完成后返回结果的类型。
使用AsyncTask只要如下三步即可。
- 使用AsyncTask的子类,并为三个泛型参数指定类型。如果某个泛型参数不需要指定类型,可将它指定为Void。
- 根据需要,实现AsyncTask的如下方法。
- doInBackground(Params...):重写该方法就是后程序将要完成的任务。该方法可以调用publicProgress(Progress...values)方法更新任务的执行进度。
- onProgressUpdate(Progress... values):在doInBackground()方法中调用publishProgress()方法更新任务的执行进度后,将会触发该方法。
- onPreExecute():该方法将在执行后台耗时操作前被调用。通常该方法用于完成一些初始化的准备工作,比如在界面上显示进度条等。
- onPostExecute(Result result):当doInBackground()完成后,系统会自动调用onPostExecute()方法,并将doInBackground()方法的返回值传给该方法。
3. 调用AsyncTask子类的实例的execute(Params...params)开始执行耗时操作。使用AsyncTask时必须遵守如下规则。
- 必须在UI线程中创建AsyncTask的实例。
- 必须在UI线程中调用AsyncTask的execute()方法。
- AsyncTask的onPreExecute()、onPostExecute(Result result)、doInBackground(Params...params),onProgressUpdate(Progress... values)方法,不应该由程序员写代码调用,而是由Android系统负责调用。
- 在同一个执行周期中,相同的AsyncTask实例只能被执行一次,多次调用将会引发异常。
【实例】
我们还是以一个下载网页内容的应用来进行讲解,非常的简单,布局文件中仅有两个一个TextView和一个按钮,当我们点击按钮时,就开始为网页的读取,当读取完毕之后,就将内容显示在TextView中,我们知道在android 4.0之后,要求所有关于网络的代码必须全部放在新的线程中,否则就会崩掉,同样我们要将所有的关于网络的代码全部放在AsyncTask中,才能够正常运行
先来看看效果 :

异步任务类文件:
1 package com.penglee.asynctask_test; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.net.URL; 7 import java.net.URLConnection; 8 import android.app.ProgressDialog; 9 import android.content.Context; 10 import android.os.AsyncTask; 11 import android.widget.TextView; 12 13 public class NetDownloadTask extends AsyncTask<URL , Integer , String>{ 14 15 Context context ; 16 ProgressDialog proDialog; 17 TextView textView ; //当前的主布局中的TextView 18 int hasRead=0; //当前已经读取的行数 19 20 public NetDownloadTask(Context context , TextView view){ 21 this.textView = view ; 22 this.context = context ; 23 } 24 25 /** 26 *在任务执行之前会自动的调用这个方法,一般是做一些初始化 27 **/ 28 @Override 29 protected void onPreExecute() { 30 31 proDialog = new ProgressDialog(context); 32 //设置对话框的标题 33 proDialog.setTitle("正在进行页面下载"); 34 //设置对话框显示的内容 35 proDialog.setMessage("网页下载中......"); 36 //设置对话框不能用"取消"按钮关闭 37 proDialog.setCancelable(false); 38 //设置对话框的进度条风格 39 proDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 40 proDialog.show(); 41 super.onPreExecute(); 42 43 } 44 45 /** 46 * 真正的任务执行位置 47 * */ 48 @Override 49 protected String doInBackground(URL... params) { 50 51 StringBuilder stringContent = new StringBuilder() ; 52 53 try { 54 URLConnection conn=params[0].openConnection(); 55 BufferedReader bReader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8")); 56 String tempString = null ; 57 while((tempString= bReader.readLine())!=null){ 58 stringContent.append(tempString + "\n"); 59 hasRead++ ; 60 publishProgress(hasRead);//调用这个方法的时候会自动的调用onProgressUpdate方法 61 } 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 66 return stringContent.toString(); 67 } 68 69 /** 70 * 在这个方法中更新进度,或者说,在这个方法中可以更改UI界面 71 * */ 72 @Override 73 protected void onProgressUpdate(Integer... values) { 74 textView.setText("当前已经读取了"+values[0]+"行数据"); 75 super.onProgressUpdate(values); 76 } 77 78 /** 79 * 当doInBackground方法执行完毕之后,就会自动的回到这个方法 80 * */ 81 @Override 82 protected void onPostExecute(String result) { 83 textView.setText(result); 84 //proDialog.dismiss(); //将进度条对话框销毁 85 super.onPostExecute(result); 86 } 87 88 }
主布局文件:
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="com.penglee.asynctask_test.MainActivity" > 10 11 <TextView 12 android:id="@+id/textView" 13 android:layout_width="match_parent" 14 android:layout_height="match_parent"/> 15 16 <Button 17 android:layout_width="match_parent" 18 android:layout_height="wrap_content" 19 android:layout_alignParentBottom="true" 20 android:text="开始下载天猫网页" 21 android:onClick="onClick"/> 22 23 </RelativeLayout>
主Activity文件
1 package com.penglee.asynctask_test; 2 3 import java.net.MalformedURLException; 4 import java.net.URL; 5 6 import android.app.Activity; 7 import android.os.Bundle; 8 import android.view.Menu; 9 import android.view.MenuItem; 10 import android.view.View; 11 import android.widget.TextView; 12 13 public class MainActivity extends Activity { 14 15 TextView textView ; 16 17 @Override 18 protected void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 22 textView = (TextView)findViewById(R.id.textView); 23 } 24 25 public void onClick(View view) throws MalformedURLException{ 26 new NetDownloadTask(MainActivity.this ,textView ) 27 .execute(new URL("http://www.tianmao.com/")); 28 } 29 30 31 @Override 32 public boolean onCreateOptionsMenu(Menu menu) { 33 // Inflate the menu; this adds items to the action bar if it is present. 34 getMenuInflater().inflate(R.menu.main, menu); 35 return true; 36 } 37 38 @Override 39 public boolean onOptionsItemSelected(MenuItem item) { 40 // Handle action bar item clicks here. The action bar will 41 // automatically handle clicks on the Home/Up button, so long 42 // as you specify a parent activity in AndroidManifest.xml. 43 int id = item.getItemId(); 44 if (id == R.id.action_settings) { 45 return true; 46 } 47 return super.onOptionsItemSelected(item); 48 } 49 }
最后注意在Manifest.xml文件中添加网络访问权限,一般将数据网络和WiFi网络权限都添加上

浙公网安备 33010602011771号