• AsyncTask实现异步线程通信


      AsyncTask是Android1.5开始提供的一个封装了Thread与Handler可以实现异步线程的简单方式,不需要再自己实现子线程,然后在主线程处接受数据。

    因为AsyncTask是用线程池,所以呢效率比Thread、Handler的要高。(怎么理解这句话呢,个人感觉Message里的机制,在实例化Message的时候是没有用通常意义

    上的构造函数方式Message msg = new Message(),而是通过Message.obtain(..)来实现的,具体的方式就是先在消息池里找已经实例化没有使用的消息,池是空的,

    那么最后还是要new的。所以这里的效率高应该是这个意思),使用AsyncTask很方便,主要步骤如下:

      1、必须通过子类来继承AsyncTask来使用,看看这段源码的注释

     * <h2>Usage</h2>
     * <p>AsyncTask must be subclassed to be used. The subclass will override at least
     * one method ({@link #doInBackground}), and most often will override a
     * second one ({@link #onPostExecute}.)</p>

      2、通过execute(..)方法启动线程

      3、必须重写doInBackground(..)方法,(这个方法是个抽象方法所以在写子类的时候会提示),这个方法主要进行耗时工作,

      4、子线程执行完毕会调用onPostExecute(Result result)方法,这个方法不要主动调用,这是一个回调,主要用于更新UI线程的内容,传入的result参数是doInBackground回传的,

        而Result是AsyncTask三个泛型参数中的最后一个。另外还注意一点如果子线程被cancel掉了那么这个方法是不会被执行的,下面是源码里的注释

     <p>Runs on the UI thread after {@link #doInBackground}. The
         * specified result is the value returned by {@link #doInBackground}.</p>
         * 
         * <p>This method won't be invoked if the task was cancelled.</p>

    除此之外还有其他功能,比如在主线程实现进度条显示子线程工作进度:1、在子线程里调用publishProgress(Progress...values)  这个参数是不定长的,而且是第二个泛型指定类型

                                    2、主线程里在方法onProgressUpdate(Progress...values) 这个是个回调方法,也不要主动调用。只要在这里更新UI就可以了。

    要注意的问题:

    1.异步任务的实例必须在UI线程中创建。

    2.execute(Params... params)方法必须在UI线程中调用。

    3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。

    4.一个任务实例只能执行一次,如果执行第二次将会抛出异常。

    5.当子线程任务被取消onPostExecute(..)方法不会被执行,onCancelled()会被执行。

    6.指定泛型的参数时候要注意:params 指定的传入的是doInBackground(params...params)的参数,

                  Progress指定的是publishProgress(Progress...progress)的参数,

                  Result指定的是Result doInBackground(params...params)的参数

     在写AsyncTask子类的时候先确定好这几个参数,那么Andriod Studio会自动生成这几个函数的形参的

       另外如果定义了这几个泛型,那么在实例化的时候一定要注意用如下的方式:

    AsyncTask<String,Integer,Long> mAt = new myAsyncTask();

    如果用:AsyncTask mAt = new myAsyncTask();的方式编译器不会报错,但是执行的时候会包 Object[] cast to String[] 出错,这里报什么错跟params定义的对象类型

    有关如果定义的是Integer 就是cast to Integer[] 出错。后来看源码才知道如果用下面的定义执行的构造函数是:

    public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    Result result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                    return postResult(result);
                }
            };
    
            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                protected void done() {
                    try {
                        postResultIfNotInvoked(get());
                    } catch (InterruptedException e) {
                        android.util.Log.w(LOG_TAG, e);
                    } catch (ExecutionException e) {
                        throw new RuntimeException("An error occurred while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        postResultIfNotInvoked(null);
                    }
                }
            };
        }
    View Code

    这里会抛出

    An error occurred while executing doInBackground()
    

    这段异常。

     下面是一个实例:

    public class MainActivity extends AppCompatActivity {
        private Button btn_show,btn_cancel;
        private ProgressBar pb;
        private TextView tv_show;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btn_show = (Button)findViewById(R.id.btn_show);
            btn_cancel = (Button)findViewById(R.id.btn_cancel);
            tv_show = (TextView)findViewById(R.id.tv_show);
            pb = (ProgressBar)findViewById(R.id.pb);
    
            final AsyncTask<String,Integer,Long> mAt = new myAsyncTask();
            AsyncTask matt = new myAsyncTask();
            btn_show.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mAt.getStatus() == AsyncTask.Status.RUNNING) {
                        return;
                    }else if(mAt.getStatus() == AsyncTask.Status.FINISHED){
                        return;
                    }else{
                        mAt.execute("Loading...", "sercond pararms");
                    }
                }
            });
    
            btn_cancel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mAt.cancel(false);
    
                    Toast.makeText(MainActivity.this,"取消",Toast.LENGTH_SHORT)
                            .show();
                }
            });
        }
        //params progress result
        private class myAsyncTask extends AsyncTask <String,Integer,Long>{
            @Override
            protected Long doInBackground(String... params) {
                Integer i = 0;
                try {
                    for(;i<11;i++){
                        Thread.sleep(1000);
                        publishProgress(i);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Long ret = Long.valueOf(i.toString());
                System.out.println(params[1]);
                return ret;
            }
    
            @Override
            protected void onPreExecute() {
                tv_show.setText("Loading...");
                System.out.println("onPreExecute");
            }
    
            @Override
            protected void onProgressUpdate(Integer... values) {
                //更新进度条
                pb.setProgress(Integer.valueOf(values[0].toString()));
            }
    
            @Override
            protected void onPostExecute(Long s) {
                Toast.makeText(MainActivity.this,"完成进度: "+ s.toString(), Toast.LENGTH_SHORT)
                        .show();
                tv_show.setText("finished");
            }
    
            @Override
            protected void onCancelled(Long aLong) {
                Toast.makeText(MainActivity.this,"进度: "+aLong.toString(),Toast.LENGTH_SHORT)
                        .show();
                System.out.println("onCancelled: " + aLong.toString());
            }
        }
    }
    View Code
    <?xml version="1.0" encoding="utf-8"?>
    <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="com.skymaster.hs.progressbar.MainActivity">
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="ProgressBar"
            android:layout_centerVertical="true"
            android:layout_centerHorizontal="true"
            android:id="@+id/btn_show"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp"
            android:text="CANCEL"
            android:layout_centerHorizontal="true"
            android:layout_below="@id/btn_show"
            android:id="@+id/btn_cancel"/>
        <ProgressBar
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            style="@android:style/Widget.ProgressBar.Horizontal"
            android:layout_margin="5dp"
            android:id="@+id/pb"
            android:max="10"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:layout_centerHorizontal="true"
            android:id="@+id/tv_show"/>
    </RelativeLayout>
    View Code

                  

    这个只不过是自己的流水账,偶尔有一些心得,错误的地方概不负责
  • 相关阅读:
    Java并发编程(二)线程任务的中断(interrupt)
    Java并发编程(一) 两种实现多线程的方法(Thread,Runnable)
    青蛙跳台阶(Fibonacci数列)
    旋转数组的最小值
    用两个栈实现队列
    重建二叉树
    二维数组中的查找
    Lab 3-1
    Lab 1-4
    Lab 1-3
  • 原文地址:https://www.cnblogs.com/ashitaka/p/5849759.html
Copyright © 2020-2023  润新知