AsyncTask 详解

android 编程原则:

//必须遵守单线程模型的原则:
//1. 不要阻塞UI线程
//  当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,
//  如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
// 2. 确保只在UI线程中访问Android UI工具包

只有主线程才能操纵界面上的组件。


当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
      比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后,是不能直接在网络操作线程中调用TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员 。

android提供了几种在其他线程中访问UI线程的方法。
Activity.runOnUiThread( Runnable )
View.post( Runnable )

例如在按钮点击事件中,new Thread(new Runnable ()

{

      public void run()

{

          mimageview.post(new Runnable()   //这里就是异步操作。

{

           public void run()

{

         mimageview.setImageDrawable();//这里更新UI上的组件。

})

}

})
View.postDelayed( Runnable, long )
Hanlder

在开发Android移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验。但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI线程会出现错误。因此android提供了一个类Handler来在子线程中来更新UI线程,用发消息的机制更新UI界面,呈现给用户。这样就解决了子线程更新UI的问题。但是费时的任务操作总会启动一些匿名的子线程,太多的子线程给系统带来巨大的负担,随之带来一些性能问题。因此android提供了一个工具类AsyncTask,顾名思义异步执行任务

android的类AsyncTask对线程间通讯进行了包装,提供了简易的编程方式来使后台线程和UI线程进行通讯:后台线程执行异步任务,并把操作结果通知UI线程

//适用于简单的异步处理,不需要借助线程和Handler即可实现  ,asynctask带了三个泛型参数:Params, Progress, Result


Params 启动任务执行的输入参数,比如HTTP请求的URL。
   * Progress 后台任务执行的百分比。
    * Result 后台执行任务最终返回的结果,比如String,Integer等。

 class AsyncSetApprove extends AsyncTask<String, Integer, String> {

AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,开发者需要实现这些方法。

   * 1) 继承AsyncTask
    * 2) 实现AsyncTask中定义的下面一个或几个方法
       * onPreExecute(), 该方法将在执行实际的后台操作前被UI 线程调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条,或者一些控件的实例化,这个方法可以不用实现。
       * doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台处理工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
      * onProgressUpdate(Progress...),在publishProgress方法被调用后,UI 线程将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
      * onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI 线程调用,后台的计算结果将通过该方法传递到UI 线程,并且在界面上展示给用户.

      * onCancelled(),在用户取消线程操作的时候调用。在主线程中调用onCancelled()的时候调用。

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

      1) Task的实例必须在UI 线程中创建

      2) execute方法必须在UI 线程中调用

      3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法,需要在UI线程中实例化这个task来调用。

      4) 该task只能被执行一次,否则多次调用时将会出现异常

      doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

  1. class DownloadTask extends AsyncTask<Integer, Integer, String>
  2.         //后面尖括号内分别是参数(例子里是线程休息时间),进度(publishProgress用到),返回值 类型 
  3.          
  4.         @Override 
  5.         protected void onPreExecute() { 
  6.             //第一个执行方法 
  7.             super.onPreExecute(); 
  8.         } 
  9.          
  10.         @Override 
  11.         protected String doInBackground(Integer... params) { 
  12.             //第二个执行方法,onPreExecute()执行完后执行 
  13.             for(int i=0;i<=100;i++){ 
  14.                 pb.setProgress(i); 
  15.                 publishProgress(i);  //这里必须调用才能
  16.                 try { 
  17.                     Thread.sleep(params[0]); 
  18.                 } catch (InterruptedException e) { 
  19.                     e.printStackTrace(); 
  20.                 } 
  21.             } 
  22.             return "执行完毕"; 
  23.         } 
  1.         @Override 
  2.         protected void onProgressUpdate(Integer... progress) { 
  3.             //这个函数在doInBackground调用publishProgress时触发,虽然调用时只有一个参数 
  4.             //但是这里取到的是一个数组,所以要用progesss[0]来取值 
  5.             //第n个参数就用progress[n]来取值 
  6.             tv.setText(progress[0]+"%"); 
  7.             super.onProgressUpdate(progress); 
  8.         } 
  9.  
  10.         @Override 
  11.         protected void onPostExecute(String result) { 
  12.             //doInBackground返回时触发,换句话说,就是doInBackground执行完后触发 
  13.             //这里的result就是上面doInBackground执行后的返回值,所以这里是"执行完毕" 
  14.             setTitle(result); 
  15.             super.onPostExecute(result); 
  16.         } 
  17.          
  18.     } 

doInBackground 一般包含的操作有I/O,网络通讯等:一下是实例:
@Override
        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= newbyte[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();

            }

           
returnnull;

        }

I/O操作:

class AsyncSetApprove extends AsyncTask<String, Integer, String> {

  @Override
  protected String doInBackground(String... params) {//...可变参数
   if (!isInit) {
    File path = getFilesDir();
    String[] strings = getResources().getStringArray(R.array.bookid);// 获取assets目录下的文件列表
    for (int i = 0; i < strings.length; i++) {
     try {
      FileOutputStream out = new FileOutputStream(path + "/" + strings[i]);
      BufferedInputStream bufferedIn = new BufferedInputStream(getResources().openRawResource(R.raw.book0 + i));
      BufferedOutputStream bufferedOut = new BufferedOutputStream(out);
      byte[] data = new byte[2048];
      int length = 0;
      while ((length = bufferedIn.read(data)) != -1) {
       bufferedOut.write(data, 0, length);
      }
      // 将缓冲区中的数据全部写出
      bufferedOut.flush();
      // 关闭流
      bufferedIn.close();
      bufferedOut.close();
      sp.edit().putBoolean("isInit", true).commit();
     } catch (Exception e) {
      e.printStackTrace();
     }
    }

    ArrayList<HashMap<String, String>> insertList = new ArrayList<HashMap<String, String>>();
    File[] f1 = path.listFiles();
    int len = f1.length;
    for (int i = 0; i < len; i++) {
     if (f1[i].isFile()) {
      if (f1[i].toString().contains(".txt")) {
       HashMap<String, String> insertMap = new HashMap<String, String>();
       insertMap.put("parent", f1[i].getParent());
       insertMap.put("path", f1[i].toString());
       insertList.add(insertMap);
      }
     }
    }
    SQLiteDatabase db = localbook.getWritableDatabase();
    db.delete("localbook", "type='" + 2 + "'", null);

    for (int i = 0; i < insertList.size(); i++) {
     try {
      if (insertList.get(i) != null) {
       String s = insertList.get(i).get("parent");
       String s1 = insertList.get(i).get("path");
       String sql1 = "insert into " + "localbook" + " (parent,path" + ", type" + ",now,ready) values('" + s + "','" + s1 + "',2,0,null" + ");";
       db.execSQL(sql1);
      }
     } catch (SQLException e) {
      Log.e(TAG, "setApprove SQLException", e);
     } catch (Exception e) {
      Log.e(TAG, "setApprove Exception", e);
     }
    }
    db.close();
   }
   isInit = true;
   sp.edit().putBoolean("isInit", true).commit();
   return null;
  }

 

你可能感兴趣的:(AsyncTask 详解)