在上一篇,详细介绍了AsynTask的基础知识。没有读过的朋友可以点击下面的链接:

http://www.cnblogs.com/fuly550871915/p/4892310.html

      那么在这篇文章中,将编写实际的小例子,让大家看看,到底AsynTask是如何使用的。废话不多说了,例子很简单,请往下看。

一、一个异步加载网络图片的小例子

     现在就跟着我一起来用AsynTask实现一个加载一张网络图片的小例子吧。首先我们看看我们要加载的这张图片是什么样的,如下:

     

这是我从网络张找的一张图片,它的地址是http://android-artworks.25pp.com/fs01/2015/01/05/4/110_416b936f41cb2b73dce64cbaf6bf1e16.png

      下面我们就开始写代码吧。新建一个项目,别忘记给这个项目加上网络权限。然后修改它的activity_main.xml,代码如下:

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    >

    <ImageView
        android:id="@+id/img_url"
        android:layout_width="200dp"
        android:layout_height="200dp" />

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_gravity="center"
       />


</LinearLayout>

       代码很简单,就是放置了一个ImageView用来放我们的这张网络图片的,然后再在中间放置一个进度条,用来显示进程。然后修改MainActivity的代码,如下:

 1 package com.example.asynctasktest;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.net.HttpURLConnection;
 6 import java.net.MalformedURLException;
 7 import java.net.URL;
 8 
 9 import org.apache.http.HttpConnection;
10 
11 import android.os.AsyncTask;
12 import android.os.Bundle;
13 import android.view.View;
14 import android.widget.ImageView;
15 import android.widget.ProgressBar;
16 import android.app.Activity;
17 import android.graphics.Bitmap;
18 import android.graphics.BitmapFactory;
19 
20 
21 public class MainActivity extends Activity {
22 
23    private ImageView img;
24    private ProgressBar progressBar;
25    private Bitmap bmp;
26    private static final String surl =" http://android-artworks.25pp.com/fs01/2015/01/05/4/110_416b936f41cb2b73dce64cbaf6bf1e16.png";
27     protected void onCreate(Bundle savedInstanceState) {
28         super.onCreate(savedInstanceState);
29         setContentView(R.layout.activity_main);
30         
31         img = (ImageView) findViewById(R.id.img_url);
32         progressBar = (ProgressBar) findViewById(R.id.progressbar);
33         MyAsyncTask mTask = new MyAsyncTask();
34         mTask.execute(surl);
35    
36     }
37     
38     class MyAsyncTask extends AsyncTask<String, Void, Bitmap>{
39 
40         
41         protected Bitmap doInBackground(String... params) {
42             
43             String surl = params[0];
44             HttpURLConnection connection = null;
45         
46                 try {
47                     URL url = new URL(surl);//将字符串转化为网址对象
48                     connection =  (HttpURLConnection) url.openConnection();//创建网络接口
49                     connection.setRequestMethod("GET");
50                     connection.setConnectTimeout(8000);
51                     connection.setReadTimeout(8000);
52                     InputStream in = connection.getInputStream();//获取返回的数据流
53                     bmp = BitmapFactory.decodeStream(in);//获取图片
54                     in.close();
55                     
56                 } catch (Exception e) {
57                     
58                     e.printStackTrace();
59                 } 
60                 
61                 
62             
63             
64             return bmp;
65         }
66 
67         @Override
68         protected void onPreExecute() {
69             super.onPreExecute();
70             //显示进度条
71             progressBar.setVisibility(View.VISIBLE);
72         }
73 
74         @Override
75         protected void onPostExecute(Bitmap result) {
76             try {
77                 Thread.sleep(5000);//为了观看效果,休眠5秒
78             } catch (InterruptedException e) {
79                 // TODO Auto-generated catch block
80                 e.printStackTrace();
81             }
82             //关闭进度条和更新UI
83             progressBar.setVisibility(View.GONE);
84             img.setImageBitmap(bmp);
85             super.onPostExecute(result);
86         }
87 
88         
89 
90         
91 
92     }
93 
94   
95 }

      代码也很简单,在这里就用到了AsynTask来异步加载这张图片。doInBackground用来获取到这张图片并转化为Bitmap对象,然后再在onPostExecute方法中更新UI即可。好了,运行程序吧。效果图如下:

                            

      通过这个例子,是不是对怎么使用AsyncTask更加熟悉了呢?那么下面我们再来写一个例子吧,这次用来模拟一个进度条。

二、一个模拟进度条的小例子

      使用的当然就是AsyncTask中的publishProgress和onProgressUpdate方法了。代码其实很简单,直接看吧。新建一个项目,修改它的activity_main.xml代码,如下:

 

 1 <LinearLayout 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:orientation="vertical" 
 6     android:gravity="center">
 7 
 8     <Button
 9         android:id="@+id/button"
10         android:layout_width="match_parent"
11         android:layout_height="wrap_content" 
12         android:onClick="btnProgress"
13         android:text="按钮"/>
14 
15    
16 
17 </LinearLayout>

       先设置一个按钮是为了触发进度条的。然后再编写progressbar.xml,里面放置一个横向的进度条即可。代码如下:

 1 <LinearLayout 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:orientation="vertical" 
 6     android:gravity="center">
 7 
 8     <ProgressBar
 9         android:id="@+id/progressBar"
10         style="?android:attr/progressBarStyleHorizontal"
11         android:layout_width="match_parent"
12         android:layout_height="wrap_content" />
13 
14    
15 
16 </LinearLayout>

      新建活动,用来显示这个进度条,在这个类里面我们就使用AsyncTask让进度条动起来。

 1 package com.example.asynctasktest;
 2 
 3 import android.app.Activity;
 4 import android.os.AsyncTask;
 5 import android.os.Bundle;
 6 import android.widget.ProgressBar;
 7 
 8 public class ProgressbarActivity extends Activity {
 9      private ProgressBar progressBar;
10       
11         protected void onCreate(Bundle savedInstanceState) {
12             super.onCreate(savedInstanceState);
13             setContentView(R.layout.progressbar);
14             progressBar = (ProgressBar) findViewById(R.id.progressBar);
15             MyAsyncTask mTask = new MyAsyncTask();
16             mTask.execute();
17        
18         }
19         
20         //Integer就是制定进度的衡量单位类型
21         class MyAsyncTask extends AsyncTask<Void, Integer, Void>{
22 
23 
24             protected Void doInBackground(Void... params) {
25                 for(int i=0;i<100;i++){
26                     //传递任务执行的当前值
27                     publishProgress(i);
28                     try {
29                         Thread.sleep(300);
30                     } catch (InterruptedException e) {
31                         // TODO Auto-generated catch block
32                         e.printStackTrace();
33                     }
34                 }
35                 return null;
36             }
37 
38 
39     
40             //根据任务执行情况更新UI,其实就是更新进度条
41             protected void onProgressUpdate(Integer... values) {
42                 super.onProgressUpdate(values);
43                 progressBar.setProgress(values[0]);
44             }
45 
46         }    
47 }

      在这个活动中,我们在doInBackground中建立一个循环,然后将循环的值通过publishProgress方法传递给onProgressUpdate方法,用来更新进度条。这样子就到了模拟进度条的效果。

       不要忘记给这个活动注册哈。然后修改MainAcitivity中的代码,添加按钮的点击事件。如下:

 1 package com.example.asynctasktest;
 2 
 3 
 4 import android.os.AsyncTask;
 5 import android.os.Bundle;
 6 import android.view.View;
 7 import android.widget.ProgressBar;
 8 import android.app.Activity;
 9 import android.content.Intent;
10 
11 
12 public class MainActivity extends Activity {
13 
14 
15  
16   
17     protected void onCreate(Bundle savedInstanceState) {
18         super.onCreate(savedInstanceState);
19         setContentView(R.layout.activity_main);
20     }
21     
22     public void btnProgress(View v){
23         Intent intent = new Intent(this,ProgressbarActivity.class);
24         startActivity(intent);
25     }
26 
27   
28 }

      下面我们运行程序,然后点击按钮,就会有下面的效果,如下:

       

三、AsyncTask的取消

    我们以上面的进度条为例子,当进度更新到下面的情况时

 

      我们返回到按钮界面,然后点击按钮,此时重新进入到进度条界面,如下:

      而且等待了好久,才发现进度条才有开始启动,才又动起来。那这是为什么呢?这是因为我们之前的doInBackground里的线程还在进行,循环还在继续,所以AsyncTask还在执行。因此此刻重新进入进度条界面,就不可能立刻启动新的AsyncTask,而旧的呢又因为之前我们返回到按钮界面就没法重新绘制了。所以只有等旧的AsyncTask执行完毕,才会开启新的。因此你等了好久才,进度条才又重新运转起来。

     其实解决这个问题,很简单,我们让AsyncTask的生命周期跟活动的生命周期一样就可以了,即在适当的时候取消AsyncTask即可。那么我们就修改一下代码,如下:

 1 package com.example.asynctasktest;
 2 
 3 import android.app.Activity;
 4 import android.os.AsyncTask;
 5 import android.os.Bundle;
 6 import android.widget.ProgressBar;
 7 
 8 public class ProgressbarActivity extends Activity {
 9      private ProgressBar progressBar;
10      private MyAsyncTask mTask;
11       
12         protected void onCreate(Bundle savedInstanceState) {
13             super.onCreate(savedInstanceState);
14             setContentView(R.layout.progressbar);
15             progressBar = (ProgressBar) findViewById(R.id.progressBar);
16              mTask = new MyAsyncTask();
17             mTask.execute();
18        
19         }
20      
21         //当跳到另外一个活动的时候调用该方法
22         protected void onPause() {
23             //如果mTask不为空,且正在运行
24             if(mTask !=null && mTask.getStatus() == AsyncTask.Status.RUNNING){
25                 mTask.cancel(true);//取消该任务
26             }
27             super.onPause();
28         }
29         
30         //Integer就是制定进度的衡量单位类型
31         class MyAsyncTask extends AsyncTask<Void, Integer, Void>{
32 
33 
34             protected Void doInBackground(Void... params) {
35                 for(int i=0;i<100;i++){
36                     //传递任务执行的当前值
37                     publishProgress(i);
38                     try {
39                         Thread.sleep(300);
40                     } catch (InterruptedException e) {
41                         // TODO Auto-generated catch block
42                         e.printStackTrace();
43                     }
44                 }
45                 return null;
46             }
47 
48 
49     
50             //根据任务执行情况更新UI,其实就是更新进度条
51             protected void onProgressUpdate(Integer... values) {
52                 super.onProgressUpdate(values);
53                 progressBar.setProgress(values[0]);
54             }
55 
56         }    
57 }

       红色部分是我修改的代码,当活动跳转的时候,就取消掉当前正在执行的AsyncTask。然后重新运行程序,然后当进度条启动之后几秒钟,返回到按钮界面,然后再点击按钮。按照我们的逻辑,此时应该是进度条重新启动,但是呢?我就不贴效果图了,跟上面的两张图一样。如果你做了这个实验,你就会发现,根本没什么改变。那是为什么啊??我们明明已经取消了该任务啊!!

      其实原因就是因为AsyncTask的cancel方法,只是将一个AsyncTask对象标记为待取消状态,当它的进程执行完毕才会真的去取消它。所以我们在上面的代码中即使用了这个方法,也没有用。

      因此要想立刻取消AsyncTask任务,必须手动取消。即在进程中,我们时刻检查AsyncTask的状态是否为取消的状态,如果是,立刻人为终止线程即可。再修改代码,如下:

 

 1 package com.example.asynctasktest;
 2 
 3 import android.app.Activity;
 4 import android.os.AsyncTask;
 5 import android.os.Bundle;
 6 import android.widget.ProgressBar;
 7 
 8 public class ProgressbarActivity extends Activity {
 9      private ProgressBar progressBar;
10      private MyAsyncTask mTask;
11       
12         protected void onCreate(Bundle savedInstanceState) {
13             super.onCreate(savedInstanceState);
14             setContentView(R.layout.progressbar);
15             progressBar = (ProgressBar) findViewById(R.id.progressBar);
16              mTask = new MyAsyncTask();
17             mTask.execute();
18        
19         }
20      
21         //当跳到另外一个活动的时候调用该方法
22         protected void onPause() {
23             //如果mTask不为空,且正在运行
24             if(mTask !=null && mTask.getStatus() == AsyncTask.Status.RUNNING){
25                 mTask.cancel(true);//取消该任务
26             }
27             super.onPause();
28         }
29         
30         //Integer就是制定进度的衡量单位类型
31         class MyAsyncTask extends AsyncTask<Void, Integer, Void>{
32 
33 
34             protected Void doInBackground(Void... params) {
35                 for(int i=0;i<100;i++){
36                     if(isCancelled()){//如果为取消状态,立刻break,跳出循环
37                         break;
38                     }
39                     //传递任务执行的当前值
40                     publishProgress(i);
41                     
42                     try {
43                         Thread.sleep(300);
44                     } catch (InterruptedException e) {
45                         // TODO Auto-generated catch block
46                         e.printStackTrace();
47                     }
48                 }
49                 return null;
50             }
51 
52 
53     
54             //根据任务执行情况更新UI,其实就是更新进度条
55             protected void onProgressUpdate(Integer... values) {
56                 super.onProgressUpdate(values);
57                 if(isCancelled()){
58                     return;//如果为 取消状态,就立刻跳出
59                 }
60                 progressBar.setProgress(values[0]);
61             }
62 
63         }    
64 }

      红色地方是我修改的地方,在线程里面合适的地方我们判断当前的AsyncTask任务是不是取消状态,如果是就立刻跳出线程。然后再运行程序,按照上面的流程走一遍。我们发现一切正确了。无论什么情况,只要点击按钮进去,进度条就会立刻重新启动。效果图我就不贴了。

     总结一下:

AsyncTask的cancel()方法并不是真的去立刻取消任务,只是将任务标记为取消状态,如果想立刻取消Async,必须手动根据这个状态去停止相应的进程。

 

posted on 2015-10-19 19:50  fuly  阅读(1211)  评论(0编辑  收藏  举报