Android AsyncTask

在Android开发中必须遵守单线程模型的原则:Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。Android开发的两条准则:

1、不要阻塞UI线程

2、确保只在UI线程中访问Android UI工具包

android规定:

1、主线程不能做耗时操作(阻塞UI线程5s以上会报ANR)

2、主线程不能做联网操作(android4.0之后的规定)

3、子线程不能直接更新UI

当一个程序第一次启动时,Android同时开启UI线程(Main Thread),Main Thread主要负责处理与UI相关的事件,例如:用户按键时间,用户触摸屏幕事件等,并把相关的事件分发到对应的组组件进行处理。

对于一些耗时的操作,比如:从网上下载图片,数据库的访问等,一般需要开启一个线程完成,获得结果之后,不能直接在子线程中调用改变界面的方法(例如:Text

package enbir.test;     
import java.io.ByteArrayOutputStream;     
import java.io.InputStream;     
import java.util.ArrayList;     
    
import org.apache.http.HttpEntity;     
import org.apache.http.HttpResponse;     
import org.apache.http.client.HttpClient;     
import org.apache.http.client.methods.HttpGet;     
import org.apache.http.impl.client.DefaultHttpClient;     
    
import android.app.Activity;     
import android.app.ProgressDialog;     
import android.content.Context;     
import android.content.DialogInterface;     
import android.os.AsyncTask;     
import android.os.Bundle;     
import android.os.Handler;     
import android.os.Message;     
import android.view.View;     
import android.widget.Button;     
import android.widget.EditText;     
import android.widget.TextView;     
    
public class NetworkActivity extends Activity{     
    private TextView message;     
    private Button open;     
    private EditText url;     
    
    @Override    
    public void onCreate(Bundle savedInstanceState) {     
       super.onCreate(savedInstanceState);     
       setContentView(R.layout.network);     
       message= (TextView) findViewById(R.id.message);     
       url= (EditText) findViewById(R.id.url);     
       open= (Button) findViewById(R.id.open);     
       open.setOnClickListener(new View.OnClickListener() {     
           public void onClick(View arg0) {     
              connect();     
           }     
       });     
    
    }     
    
    private void connect() {     
        PageTask task = new PageTask(this);     
        task.execute(url.getText().toString());     
    }     
    
    
    class PageTask extends AsyncTask
   
   
    
     {     
        // 可变长的输入参数,与AsyncTask.exucute()对应     
        ProgressDialog pdialog;     
        public PageTask(Context context){     
            pdialog = new ProgressDialog(context, 0);        
            pdialog.setButton("cancel", new DialogInterface.OnClickListener() {     
             public void onClick(DialogInterface dialog, int i) {     
              dialog.cancel();     
             }     
            });     
            pdialog.setOnCancelListener(new DialogInterface.OnCancelListener() {     
             public void onCancel(DialogInterface dialog) {     
              finish();     
             }     
            });     
            pdialog.setCancelable(true);     
            pdialog.setMax(100);     
            pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);     
            pdialog.show();     
    
    
        }     
        @Override  
        // params[0]代表AsyncTask.execute方法传的第一个参数    
        protected String doInBackground(String... params) {     
    
            try{     
    
               HttpClient client = new DefaultHttpClient();     
               // params[0]代表连接的url     
               HttpGet get = new HttpGet(params[0]);     
               HttpResponse response = client.execute(get);     
               HttpEntity entity = response.getEntity();     
               long length = entity.getContentLength();     
               InputStream is = entity.getContent();     
               String s = null;     
               if(is != null) {     
                   ByteArrayOutputStream baos = new ByteArrayOutputStream();     
    
                   byte[] buf = new byte[128];     
    
                   int ch = -1;     
    
                   int count = 0;     
    
                   while((ch = is.read(buf)) != -1) {     
    
                      baos.write(buf, 0, ch);     
    
                      count += ch;     
    
                      if(length > 0) {     
                          // 如果知道响应的长度,调用publishProgress()更新进度     
                          publishProgress((int) ((count / (float) length) * 100));     
                      }     
    
                      // 让线程休眠100ms     
                      Thread.sleep(100);     
                   }     
                   s = new String(baos.toByteArray());              }     
               // 返回结果     
               return s;     
            } catch(Exception e) {     
               e.printStackTrace();     
    
            }     
    
            return null;     
    
        }     
    
        @Override    
        protected void onCancelled() {     
            super.onCancelled();     
        }     
    
        @Override    
        protected void onPostExecute(String result) {     
            // 返回HTML页面的内容     
            message.setText(result);     
            pdialog.dismiss();      
        }     
    
        @Override    
        protected void onPreExecute() {     
            // 任务启动,可以在这里显示一个对话框,这里简单处理     
            message.setText(R.string.task_started);     
        }     
    
        @Override    
        protected void onProgressUpdate(Integer... values) {     
            // 更新进度     
              System.out.println(""+values[0]);     
              message.setText(""+values[0]);     
              pdialog.setProgress(values[0]);     
        }     
    
     }     
    
}    
   
   
View1..setText()),因为 除了UI线程,其他线程不能直接访问UI线程成员,否则会报:

android.view.ViewRoot$CalledFromWrongThreadException:Only the Original thread that created a view hierarchy can touch its views.

针对此,Android提供了几种在其他线程与UI线程通信的方法:

Activity.runOnUiThread(Runable);

View.post(Runable);

View.postDelaed(Runable,long);

Handler(另起一个Handler,将改变UI的代码封装,子线程调用此Handler,完成工作之后发送一个消息到消息队列中,主线程在空闲的时候更新UI状态(大部分时间是即时的))

这些类和方法会使你的代码很复杂,当你需要实现一些很复杂的操作并需要频繁的更新UI时,变得很糟糕。

为了解决这个问题,Android1.5提供了一个工具类:AsyncTask,它使穿件需要与UI界面交互的长时间与你系那个的任务变得更简单。不需要直接借助线程和Handler即可实现。

相对于线程+Handler来说,AsyncTask对于简单任务的处理更安全,其内部实现方法使用了Android的Handler机制。

AsyncTask介绍

抽象类AsyncTask定义了三种泛型类型Params、Progress和Result。
Params启动任务执行的输入参数,比如HTTP请求的URL。
Progress后台任务执行的百分比
Result后台执行任务最终返回的结果,比如String。


AsyncTask的执行分为四个步骤,每一步对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。
1、实现AsyncTask:三个泛型参数
Param 任务执行器需要的数据类型
Progress后台计算中使用的进度单位数据类型
Result 后台计算返回结果的数据类型

2、实现AsyncTask定义的下面一个或者几个方法
onPreExcute():该方法将在执行实际的后台操作之前被UI Thread调用。可以在该方法中做一些准备工作,比如初始化进度条。(运行于UI线程)
doInBackground(Params...):将在onPreExcute()方法执行后马上执行,该方法运行在后台线程中,这里主要负责耗时的后台操作。可以调用publishProgress方法实时更新任务进度,如果在doInBackground()方法中使用了publishProgress()就会触发这个方法,在这里可以对进度条空间根据进度只做出具体响应。该方法是抽线方法,子类必须实现。(子线程)
onProgressUpdate(Progress....):在doInBackground执行完成后,onPostExcute方法将被UI Thread调用,后台的计算结果将通过该方法传递到UI Thread。如果Result为null,表明后台任务没有完成(被取消或者出现异常)(UI线程)

这4个方法都不能手动调用。而且除了doInBackground(Param..)方法,其余3个方法都是被UI线程调用,所以要求:
1、AsyncTask的实例必须在UI Thread中创建;
2、AsyncTask.execute方法必须在UI Thread中调用;
3、不要手动调用onPreExcute(),onPostExcute(Result),doINBackground(Params...),onProgressUpdate(Progress)这几个方法
4、该task只能被执行一次,否则多次调用时将会出现异常

package test.list;     
import java.io.ByteArrayOutputStream;     
import java.io.InputStream;     
import java.util.ArrayList;     
    
import org.apache.http.HttpEntity;     
import org.apache.http.HttpResponse;     
import org.apache.http.client.HttpClient;     
import org.apache.http.client.methods.HttpGet;     
import org.apache.http.impl.client.DefaultHttpClient;     
    
import android.app.Activity;     
import android.app.ProgressDialog;     
import android.content.Context;     
import android.content.DialogInterface;     
import android.os.AsyncTask;     
import android.os.Bundle;     
import android.os.Handler;     
import android.os.Message;     
import android.view.View;     
import android.widget.Button;     
import android.widget.EditText;     
import android.widget.TextView;     
    
public class NetworkActivity extends Activity{     
    private TextView message;     
    private Button open;     
    private EditText url;     
    
    @Override    
    public void onCreate(Bundle savedInstanceState) {     
       super.onCreate(savedInstanceState);     
       setContentView(R.layout.network);     
       message= (TextView) findViewById(R.id.message);     
       url= (EditText) findViewById(R.id.url);     
       open= (Button) findViewById(R.id.open);     
       open.setOnClickListener(new View.OnClickListener() {     
           public void onClick(View arg0) {     
              connect();     
           }     
       });     
    
    }     
    
    private void connect() {     
        PageTask task = new PageTask(this);     
        task.execute(url.getText().toString());     
    }     
    
    
    class PageTask extends AsyncTask<String, Integer, String> {     
        // 可变长的输入参数,与AsyncTask.exucute()对应     
        ProgressDialog pdialog;     
        public PageTask(Context context){     
            pdialog = new ProgressDialog(context, 0);        
            pdialog.setButton("cancel", new DialogInterface.OnClickListener() {     
             public void onClick(DialogInterface dialog, int i) {     
              dialog.cancel();     
             }     
            });     
            pdialog.setOnCancelListener(new DialogInterface.OnCancelListener() {     
             public void onCancel(DialogInterface dialog) {     
              finish();     
             }     
            });     
            pdialog.setCancelable(true);     
            pdialog.setMax(100);     
            pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);     
            pdialog.show();     
    
    
        }     
        @Override  
        // params[0]代表AsyncTask.execute方法传的第一个参数    
        protected String doInBackground(String... params) {     
    
            try{     
    
               HttpClient client = new DefaultHttpClient();     
               // params[0]代表连接的url     
               HttpGet get = new HttpGet(params[0]);     
               HttpResponse response = client.execute(get);     
               HttpEntity entity = response.getEntity();     
               long length = entity.getContentLength();     
               InputStream is = entity.getContent();     
               String s = null;     
               if(is != null) {     
                   ByteArrayOutputStream baos = new ByteArrayOutputStream();     
    
                   byte[] buf = new byte[128];     
    
                   int ch = -1;     
    
                   int count = 0;     
    
                   while((ch = is.read(buf)) != -1) {     
    
                      baos.write(buf, 0, ch);     
    
                      count += ch;     
    
                      if(length > 0) {     
                          // 如果知道响应的长度,调用publishProgress()更新进度     
                          publishProgress((int) ((count / (float) length) * 100));     
                      }     
    
                      // 让线程休眠100ms     
                      Thread.sleep(100);     
                   }     
                   s = new String(baos.toByteArray());              }     
               // 返回结果     
               return s;     
            } catch(Exception e) {     
               e.printStackTrace();     
    
            }     
    
            return null;     
    
        }     
    
        @Override    
        protected void onCancelled() {     
            super.onCancelled();     
        }     
    
        @Override    
        protected void onPostExecute(String result) {     
            // 返回HTML页面的内容     
            message.setText(result);     
            pdialog.dismiss();      
        }     
    
        @Override    
        protected void onPreExecute() {     
            // 任务启动,可以在这里显示一个对话框,这里简单处理     
            message.setText(R.string.task_started);     
        }     
    
        @Override    
        protected void onProgressUpdate(Integer... values) {     
            // 更新进度     
              System.out.println(""+values[0]);     
              message.setText(""+values[0]);     
              pdialog.setProgress(values[0]);     
        }     
    
     }     
    
}    


从网上获取一个网页,在一个TextView中将其源代码显示出来:












  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值