• AsyncTask使用实例,异步加载图片


           在上一篇,详细介绍了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,必须手动根据这个状态去停止相应的进程。
  • 相关阅读:
    iOS 9适配技巧(更新版)
    VC/MFC 在ListCtl 控件中随鼠标移动提示单元格信息
    VC++ 编译libcurl 支持SSL,GZIP
    qt使用动态库(DLL)
    解决修改mysql的data_dir所引发的错误
    Mybatis实战之TypeHandler高级进阶
    Mybatis实战之自定义TypeHandler处理枚举
    shell编程其实真的很简单(五)
    shell编程其实真的很简单(四)
    shell编程其实真的很简单(三)
  • 原文地址:https://www.cnblogs.com/fuly550871915/p/4892668.html
Copyright © 2020-2023  润新知