转发请注明出处:http://blog.csdn.net/qq_28055429/article/details/51934966
前言:因为handler+message来实现异步操作相对复杂,故而如果只需简单异步操作的话,可用异步任务AsyncTask来实现
一,基本知识:
(1)原型:
android.os.AsyncTask<Params,Progress,Result> :
三个参数
Params --------启动任务执行的输入参数,比如HTTP请求的URL。
Progress -----后台任务执行的百分比,。
Result --------后台执行任务最终返回的结果,比如Drawable。
(2)基本步骤:
4个步骤:
onPreExecute(): 执行后台操作前回调的函数,常用来设置任务,例如:在用户界面中显示一个进度条。
doInBackground(Void... params) :后台执行耗时的操作,常用于接受参数返回结果,结果返回到onPostExecute()中
不能直接操作UI,在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
onProgressUpdate(Progress...) : 在调用publishProgress(Progress... values)时,此方法被执行,直接将进度信息更新到UI组件上。
onPostExecute (String result):执行后台操作完毕后自动回调此函数,后台操作结束后的结果会返回到这里,来使用
(3)基本方法:
boolean cancel(boolean mayInterruptIfRunning) :尝试取消,如任务下载时,突然想停止,可设置XX.cancel(true);
execute(Params... params) :根据参数来开始执行
get():如果有必要,就等待计算完成,然后取它的结果
get(long timeout, TimeUnit unit) :如果有必要,等待规定时间的计算,然后取它的结果
boolean isCancelled() :判断操作是否已经取消了
AsyncTask.Status getStatus() :获取当前任务的状态,
(4)4个原则:
1.异步任务的实例必须在UI线程中创建。
2.execute(Params... params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。
4.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
(5)用法:一般都是一个类去继承AsyncTask,重写里面的方法,一般重写的方法有:doInBackground和onPostExecute
这是官方的例子:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } } 在MainActivity中执行代码: new DownloadFilesTask().execute(url1, url2, url3);
二,例子:
例子(1):加载网络图片:
布局:activity_third:放置一个imageView用于显示图片
<?xml version="1.0" encoding="utf-8"?> <!--定义基本布局:LinearLayout--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!--定义一个imageView来显示图片--> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:src="@drawable/load"/> </LinearLayout>
异步类:ImageAsyncTask:继承自AsyncTask<Void , Void, Drawable>,实现其中的方法:
package testsdcard.com.maiyu.s04_79.domain; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.widget.ImageView; import java.io.IOException; import java.io.InputStream; import java.net.URL; import testsdcard.com.maiyu.s04_79.R; /**自定义ImageAsynTask类,继承自异步任务类 * Created by maiyu on 2016/7/17. */ public class ImageAsynTask extends AsyncTask<Void ,Void ,Drawable> { private ImageView m ; //用来显示图片 private String imageUrl ; //记录网络图片地址 //根据imageView对象和网络图片网址的,构造函数 public ImageAsynTask(ImageView i , String t){ m = i ; imageUrl = t ; } //后台执行耗时的操作 @Override protected Drawable doInBackground(Void... voids) { return loadImages(imageUrl); //自定义加载图片的方法 } //执行后台操作完毕后自动回调此方法 @Override protected void onPostExecute(Drawable drawable) { super.onPostExecute(drawable); if(drawable != null){ //判断图片加载是否成功 m.setImageDrawable(drawable); }else { m.setImageResource(R.drawable.failed); } } //执行后台操作前的回调函数 @Override protected void onPreExecute() { super.onPreExecute(); } //根据网址加载图片 private Drawable loadImages(String url) { try{ //生成URL对象 URL mUrl = new URL(url); //得到inputStream InputStream inputStream = (InputStream)mUrl.openStream(); return Drawable.createFromStream(inputStream , "test"); //生成并返回图片 }catch(IOException e){ e.printStackTrace(); } return null; } }
测试类:ThridActivity:在里面主要新建异步任务来测试加载图片:
new ImageAsynTask(mImage , "http://p4.so.qhimg.com/t01aade72dccf26cffe.jpg").execute();
代码如下:
package testsdcard.com.maiyu.s04_79.activity; import android.app.Activity; import android.os.Bundle; import android.widget.ImageView; import testsdcard.com.maiyu.s04_79.R; import testsdcard.com.maiyu.s04_79.domain.ImageAsynTask; /** * Created by maiyu on 2016/7/17. */ public class ThirdActivity extends Activity { private ImageView mImage ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); mImage = (ImageView)findViewById(R.id.imageView); //新建一个异步任务,开始加载网络图片 new ImageAsynTask(mImage , "http://p4.so.qhimg.com/t01aade72dccf26cffe.jpg").execute(); } }
记得加网络权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
结果:略,,,
例子2:根据网址下载网络Html内容,可中断下载,即测试类cancel(boolean)方法:
布局:activity_four:放置一个editText,两个按钮,即下载和停止,一个ScrollView(里面放置一个TextView)用于显示内容:
<?xml version="1.0" encoding="utf-8"?> <!--定义当前的基本布局;LinearLayout--> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!--定义获得用户需要加载的网址的输入框--> <EditText android:id="@+id/Et" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/four_edt1"/> <!--定义用户单击开始加载按钮控件--> <Button android:id="@+id/BtnStart" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/four_btn1"/> <!--定义用户单击终止加载按钮控件--> <Button android:id="@+id/BtnStop" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/four_btn2"/> <!--用于显示内容--> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/Tv" android:layout_width="match_parent" android:layout_height="match_parent" /> </ScrollView> </LinearLayout>
异步类:HtmlAsyncTask继承自AsyncTask<Void , Void, String>,再去实现里面方法,
代码如下:
package testsdcard.com.maiyu.s04_79.domain; import java.io.IOException; import android.os.AsyncTask; import android.util.Log; import android.widget.TextView; //自定义ImageAsynTask类,继承自异步任务类 public class HtmlAsyncTask extends AsyncTask<Void, Void, String> { //用来存储加载网址内容成功后展示网络源代码的TextView对象 private TextView m; //记录需要加载的网络地址 private String url; //构造函数,传入TextView对象和网络地址 public HtmlAsyncTask(TextView i, String t) { m = i; url = t; } //后台执行耗时的操作 @Override protected String doInBackground(Void... params) { return requestByHttpGet(url); } //执行后台操作完毕后自动回调此函数 @Override protected void onPostExecute(String result) { super.onPostExecute(result); Log.e("isCancelled()", isCancelled() + ""); //如果用户取消此异步任务 if (isCancelled()) { m.setText("取消加载"); } //如果加载的得到的网络地址的源代码不为空的话,设置textview对象的值 else if (null != result) { m.setText(result); } //如果加载的内容为空的话,显示加载失败 else { m.setText("加载失败"); } } //执行后台操作前回调的函数 @Override protected void onPreExecute() { super.onPreExecute(); } //通过加载url的网络内容 public String requestByHttpGet(String url) { //新建HttpGet对象 HttpGet httpGet = new HttpGet(url); //定义HttpClient对象 HttpClient httpClient = new DefaultHttpClient(); //定义HttpResponse实例 HttpResponse httpResp; try { httpResp = httpClient.execute(httpGet); // 判断是够请求成功 if (httpResp.getStatusLine().getStatusCode() == 200) { // 获取返回的数据 String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8"); Log.e("TAG", "HttpGet方式请求成功,返回数据如下:"); return result; } else { Log.e("TAG", "HttpGet方式请求失败"); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
测试类:同理:代码如下:
package testsdcard.com.maiyu.s04_79.activity; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import testsdcard.com.maiyu.s04_79.R; import testsdcard.com.maiyu.s04_79.domain.HtmlAsyncTask; //定义了本实例的主要Activity public class FourActivity extends Activity { //定义布局中的TextView控件 private TextView tv; //定义布局中的EditText控件 private EditText et; //定义布局中的开始加载Button控件 private Button btnstart; //定义布局中的终止加载Button控件 private Button btnstop; //定义异步请求html代码的异步任务 protected HtmlAsyncTask hat; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findView(); setListener(); } private void setListener() { //设置btn的点击监听器 btnstart.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //初始textview的内容 tv.setText("Html加载中........."); //获取EditText的用户输入值 String str = et.getText().toString(); //启动异步任务加载用户输入的url中的网络html hat = new HtmlAsyncTask(tv, str); hat.execute(); } }); btnstop.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //终止异步任务 hat.cancel(true); } }); } private void findView() { //得到布局中的TextView的对象 tv = (TextView) findViewById(R.id.Tv); //得到布局中的EditText的对象 et = (EditText) findViewById(R.id.Et); //得到布局中的开始加载的Button的对象 btnstart = (Button) findViewById(R.id.BtnStart); //得到布局中的开始加载的Button的对象 btnstop = (Button) findViewById(R.id.BtnStop); } }
同样要加网络权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
结果:略,,
三,总结:
AsyncTask使用的一般步骤:
(1)创建一个类,继承AsyncTask<参数1,参数2,参数3>,参数一般为<Void,Void,你想要返回的类型>,
如:ImageAsyncTask extends AsyncTask<Void ,Void ,Drawable> {}//获取图片
StringAsyncTask extends AsyncTask<Void ,Void ,String>{}//获取字符串数据
(2)然后去重写其中的方法,一般重写的有doInBackground和onPostExecute
如:略,,,
(3)在测试类中去调用,并执行execute()方法。
上一个例子中:
new HtmlAsyncTask(tv, str).execute();