• 异步任务(AsyncTask)


    •       前面已经介绍过,Android的UI线程主要负责处理用户的按键事件、用户触屏事件及屏幕绘图事件等,因此开发者的其他操作不应该、也不能阻塞UI线程,否则UI界面将会变得停止响应——用户感觉非常糟糕。

          为了避免UI线程失去响应的问题,Android建议将耗时操作放在信息新线程中完成,但新线程也可能需要动态更新UI组件:比如需要从网上获取一个网页,然后在TextView中将其源代码显示出来,此时就应该将连接网络、获取网络数据的操作放在新线程中完成。问题是:获取网络数据之后,新线程不允许直接更新UI组件。

          为了解决新线程不能更新UI组件的问题,Android提供了如下几种解决方案。

    • 使用Handler实现线程之间的通信。
    • Activity.runOnUiThread(Runnable)。
    • View.post(Runnable)。
    • View.postDelayed(Runnable,long)。

         上一节已经见到了使用Handler的示例,后面三种方式可能导致编程略显烦琐,而异步任务(AsyncTask)则可能进一步简化这种操作。

         AsyncTask<>是一个抽象类,通常用于被继承,继承AsyncTask时需要指定如下三个泛型参数。

         相对来说AsyncTask更加轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。

         AsyncTask<Params,Progress,Result>是抽象类,它定义了如下三种泛型类型。

    • Params:启动任务执行的输入参数的类型。
    • Progress:后台任务完成的进度值的类型。
    • Result:后台执行任务完成后返回结果的类型。

        使用AsyncTask只要如下三步即可。

    1.  使用AsyncTask的子类,并为三个泛型参数指定类型。如果某个泛型参数不需要指定类型,可将它指定为Void。
    2.  根据需要,实现AsyncTask的如下方法。
    • doInBackground(Params...):重写该方法就是后程序将要完成的任务。该方法可以调用publicProgress(Progress...values)方法更新任务的执行进度。
    • onProgressUpdate(Progress... values):在doInBackground()方法中调用publishProgress()方法更新任务的执行进度后,将会触发该方法。
    • onPreExecute():该方法将在执行后台耗时操作前被调用。通常该方法用于完成一些初始化的准备工作,比如在界面上显示进度条等。
    • onPostExecute(Result result):当doInBackground()完成后,系统会自动调用onPostExecute()方法,并将doInBackground()方法的返回值传给该方法。

         3.   调用AsyncTask子类的实例的execute(Params...params)开始执行耗时操作。使用AsyncTask时必须遵守如下规则。

    •   必须在UI线程中创建AsyncTask的实例。
    •   必须在UI线程中调用AsyncTask的execute()方法。
    •  AsyncTask的onPreExecute()、onPostExecute(Result result)、doInBackground(Params...params),onProgressUpdate(Progress... values)方法,不应该由程序员写代码调用,而是由Android系统负责调用。
    • 每个AsyncTask只能被执行一次,多次调用将会引发异常。  

        实例:使用异步任务下载

         下面的实例示范如何使用异步任务下载网络资源。该实例的界面布局文件包含两个组件:一个文本框用于显示从网络下载的页面代码;一个按钮用于激发下载任务。

         该实例的界面布局文件如下:

    <RelativeLayout
        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"
        tools:context=".AsyncTaskTest">
        <TextView
            android:id="@+id/show"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="14dp" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:text="下载"
            android:onClick="download" />
    </RelativeLayout>

    该程序的Activity代码如下:

    package com.example.studyevent;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.app.Activity;
    import android.app.ProgressDialog;
    import android.content.Context;
    import android.view.Menu;
    import android.view.View;
    import android.widget.TextView;
    
    public class AsyncTaskTest extends Activity {
        private TextView show;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_async_task_test);
            show=(TextView)findViewById(R.id.show);
        }
       //重写该方法,为界面的按钮提供事件响应方法
        public void download(View source) throws MalformedURLException
        {
            DownTask task=new DownTask(this);
            task.execute(new URL("http://www.crazyit.org/ethos.php"));
            
        }
         class DownTask extends AsyncTask<URL,Integer,String>
         {
             //可变长的输入参数,与AsyncTask.exucute()对应
             ProgressDialog pdialog;
             //定义记录已经读取行的数量
             int hasRead=0;
             Context mContext;
             public DownTask(Context ctx)
             {
                 mContext=ctx;
             }
            @Override
            protected String doInBackground(URL... params) {
                // TODO Auto-generated method stub
                StringBuilder sb=new StringBuilder();
                try
                {
                    URLConnection conn=params[0].openConnection();
                    //打开conn对应的输入流,并把它包装成BufferedReader
                    BufferedReader br=new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
                    String line=null;
                    while((line=br.readLine())!=null)
                    {
                        sb.append(line+"
    ");
                        hasRead++;
                        publishProgress(hasRead);
                    }
                    return sb.toString();
                }
                catch(Exception e)
                {
                    e.printStackTrace();
                }
                return null;
            }
            @Override
            protected void onProgressUpdate(Integer... values) {
                // TODO Auto-generated method stub
                //更新进度
                show.setText("已经读取了【"+values[0]+"】行!");
                pdialog.setProgress(values[0]);
            }
            @Override
            protected void onPostExecute(String result) {
                // TODO Auto-generated method stub
                //返回HTML页面的内容
                show.setText(result);
                pdialog.dismiss();
            }
            @Override
            protected void onPreExecute() {
                // TODO Auto-generated method stub
                pdialog=new ProgressDialog(mContext);
                //设置对话框的标题
                pdialog.setTitle("任务正在执行中");
                //设置对话框显示的内容
                pdialog.setMessage("任务正在执行中,敬请等待...");
                //设置对话框不能用"取消"按钮关闭
                pdialog.setCancelable(false);
                //设置该进度条的最大值
                pdialog.setMax(202);
                //设置对话框的进度条风格
                pdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                //设置对话框的进度条是否显示进度
                pdialog.setIndeterminate(false);
                pdialog.show();
                super.onPreExecute();
            }
            
         }
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.async_task_test, menu);
            return true;
        }
    
    }

      上面程序的download()方法很简单,它只是创建了DownTask(AsyncTask 的子类)实例,并调用它的execute()方法开始执行异步任务。

       该程序的重点是实现AsyncTask的子类,实现该子类时实现了如下4个方法。

    • doInBackground:该方法的代码完成实际的下载任务。
    • onPreExecute():该方法的代码负责在下载开始的时候显示一个进度条。
    • onProgressUpdate():该方法的代码负责随着下载进度的改变更新进度条的进度值。
    • onPostExecute():该方法的代码负责当下载完成后、将下载的代码显示出来。 

         提示:本程序需要访问网络,因此还需要在AndroidManifest.xml文件中声明如下权限;

       <uses-permission android:name="android.permission.INTERNET" />

     运行该代码将会出现如下效果:

     

  • 相关阅读:
    docker容器的时间同步
    Java中的各种bean对应的意义(VO,PO,BO,QO, DAO,POJO,DTO)
    Vue-admin工作整理(十九):从数字渐变组件谈第三方JS库Count-to的使用
    HTTP 方法:Get与Post分析
    Java核心知识盘点(三)- 框架篇-Spring
    Java核心知识盘点(二)- 缓存使用
    Java核心知识盘点(一)- 数据存储
    Java基础知识盘点(三)- 线程篇
    Java基础知识盘点(二)- 集合篇
    Java基础知识盘点(一)- 基础篇
  • 原文地址:https://www.cnblogs.com/wolipengbo/p/3410820.html
Copyright © 2020-2023  润新知