精华内容
下载资源
问答
  • Asyntask

    2017-11-16 13:44:20
    package com.example.nm.myapplication; import android.graphics.Bitmap; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle;...import android.widget.Lis
    package com.example.nm.myapplication;
    
    import android.graphics.Bitmap;
    import android.os.AsyncTask;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.ListView;
    
    import com.google.gson.Gson;
    import com.nostra13.universalimageloader.core.DisplayImageOptions;
    import com.nostra13.universalimageloader.core.ImageLoader;
    import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        ListView listView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listView=(ListView) findViewById(R.id.list);
    //        实现自己写的类
            asyn asyn = new asyn();
    //     把地址放到execute里执行
            asyn.execute("http://www.93.gov.cn/93app/data.do?channelId=0&startNum=0");
    
    
        }
    //    第一步自己写一个类继承AsyncTask
        class asyn extends AsyncTask<String,Void,String>{
    
            @Override
            protected String doInBackground(String... params) {
    
                StringBuilder builder=null;
                try {
    //                这是主方法里传回来的地址
                    URL url = new URL(params[0]);
                    HttpURLConnection con = (HttpURLConnection)url.openConnection();
                    con.setRequestMethod("GET");
                    con.setReadTimeout(5000);
                    con.setConnectTimeout(5000);
                    if(con.getResponseCode()==200){
                        InputStream stream = con.getInputStream();
                        InputStreamReader reader = new InputStreamReader(stream);
                        BufferedReader buf = new BufferedReader(reader);
                        String s=null;
                        builder = new StringBuilder();
                        while((s=buf.readLine())!=null){
                            builder.append(s);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    //            手动返回值
                  return builder.toString();
            }
    
            @Override
    //        这是手动重写出来的方法用来写解析和适配器的
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
    
                Gson gosn = new Gson();
    //            这里是上面定义过来的s
                bena bena = gosn.fromJson(s, bena.class);
                List<com.example.nm.myapplication.bena.DataBean> list = bena.getData();
                listView.setAdapter(new Adapter(MainActivity.this,list));
    
    
            }
        }
    }
    
    展开全文
  • AsynTask

    2017-08-19 15:15:28
    介绍: AsyncTask是一种轻量级的异步任务类,可以在后台线程池中执行后台的任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler。...

    介绍:
    AsyncTask是一种轻量级的异步任务类,可以在后台线程池中执行后台的任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler。但它并不适合特别耗时的任务,对于特别耗时的任务应该使用线程池。
    它是一个泛型抽象类,Params表示参数的类型,Progress表示后台任务进度的类型,而Result表示结果的返回类。

    使用特点:
    (1)它必须在主线程中创建,execute方法必须在主线程中调用
    (2)execute方法只能执行一次,虽然可以传很多个参数(任务)

    工作原理:
    AsyncTask实际上是对线程池和Handler进行了封装。
    (1)任务执行:
    3.0之前,AsyncTask是并行执行的,而3.0之后就变为了串行执行,并且开发者可以选择进行并行执行。原理是什么呢?实际上它内部有两个线程池,sDefaultExecutor是一个自己实现的串行的线程池,它是static的,说明一个进程内的所有任务都是它来执行,它的任务很简单,就是把任务放进一个队列中,然后提醒另一个并行的线程池THREAD_POOL_EXECUTOR来取出执行,如果有可取的并且当前没有任务在执行就会被这个并行的线程池来执行。如果有任务在执行自然不会执行,当这个任务执行完之后又会重新提醒并行的线程池THREAD_POOL_EXECUTOR来取出队列中的任务进行执行。所以从这个原理我们看出来它是串行执行的,原因就是老版本是串行的并且很多代码依赖于这个逻辑。
    (2)任务结果分发
    它的内部有一个static的handler,所以这也是它必须在UI线程中进行初始化的原因,这样可以保证Handler被正常的初始化。当任务执行完成后,就会将结果发送给Handler,使得其在主线程被执行。

    sdk3.0前,使用内部的线程池,多线程并发执行。线程池大小等于5,最大达128
    sdk3.0后,使用默认的serial线程池,执行完一个线程,再顺序执行下一个线程。sdk3.0<=current version <= sdk4.3时 线程池大小等于5,最大达128
    sdk4.4后线程池大小等于 cpu count + 1,最大值为cpu count * 2 + 1
    sdk3.0后有两种线程池的实现,默认为 Serial 线程池

    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();  
    public static final Executor THREAD_POOL_EXECUTOR  
                = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
                        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;  
    public static void setDefaultExecutor(Executor exec) {//设置默认线程池  
            sDefaultExecutor = exec;  
    }  

    SerialExecutor ,使用同步锁,一次执行一个线程

    private static class SerialExecutor implements Executor {  
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
            Runnable mActive;  
    
            public synchronized void execute(final Runnable r) {  
                mTasks.offer(new Runnable() {  
                    public void run() {  
                        try {  
                            r.run();  
                        } finally {  
                            scheduleNext();  
                        }  
                    }  
                });  
                if (mActive == null) {  
                    scheduleNext();  
                }  
            }  
    
            protected synchronized void scheduleNext() {  
                if ((mActive = mTasks.poll()) != null) {  
                    THREAD_POOL_EXECUTOR.execute(mActive);  
                }  
            }  
        }  

    THREAD_POOL_EXECUTOR 并发线程池
    asynctask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //设置使用 并发线程池
    //params 都是使用在doInBackground(Params… params);
    asynctask.executeOnExecutor(executor, params); //可以自定义 线程池

    可以通过上述两种办法使用并发线程池。

    展开全文
  • AsynTask总结

    2020-04-16 13:20:18
    所以我们可以使用一下AsynTask,它使得异步任务实现起来更加简单。 首先我们介绍一下如何使用: 我在这里实现了一个进度条的加载 //首先需要继承AsynTask这个抽象类,并指定三个参数类型 class MyTask extends ...

    除了我们常用的Handler进行耗时操作,最后更新到UI线程中,虽然Handler比较简单,但是如果有多个任务同时执行代码就会增多。所以我们可以使用一下AsynTask,它使得异步任务实现起来更加简单。

    首先我们介绍一下如何使用:

    我在这里实现了一个进度条的加载

    //首先需要继承AsynTask这个抽象类,并指定三个参数类型
    class MyTask extends AsyncTask<String,Integer,String>{
            //执行线程任务前的操作
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                textView.setText("加载中");
            }
            //耗时操作
            @Override
            protected String doInBackground(String... strings) {
                try {
                    int count=0;
                    int length=1;
                    while (count<99){
                        count+=length;
                        //调用该方法显示进度,之后将执行onProgressUpdate
                        publishProgress(count);
                        Thread.sleep(50);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }
    
            @Override
            protected void onProgressUpdate(Integer... values) {
                progressBar.setProgress(values[0]);
                textView.setText("loading..."+values[0]);
            }
            //执行完毕返回结果
            @Override
            protected void onPostExecute(String s) {
                textView.setText("加载完毕");
            }
            //取消任务
            @Override
            protected void onCancelled() {
                textView.setText("已取消");
                progressBar.setProgress(0);
            }
        }

    然后调用execute()时必须在主线程中调用:

    myTask=new MyTask();

    接下来我们看一看AsynTask源码吧!

    public abstract class AsyncTask<Params, Progress, Result> {
        ...
    }

    三个参数:

    Params:参数类型,一般就是我们需要输入的参数类型

    Progress:任务执行进度的参数

    Result:返回结果的类型

    如果不需要其中的某个参数可将其设为void类型。

    我们一般要实现的方法(这几个方法在源码中都是空实现):

    onPreExecute():任务执行前的准备工作,在主线程执行,则可以进行UI操作。

    doInBackground(Params...params):准备好之后开始进行的耗时任务操作,在线程池中执行,在执行中通过调用publishProgress(Progress...values)来进行更新进度。

    onProgressUpdate(Progress...values)在主线程中执行,当调用publishProgress方法时会将进度更新到UI组件中。

    onPostExecute(Result result):后台任务执行完毕,得到doInBackground中的结果,在主线程执行,能够进行UI操作。

    onCancelled在主线程执行,当需要取消异步任务时调用,需要在ondoInBackground去判断状态

     

    AsynTask在3.0之前的版本与3.0之后的版本有较大改动,我们需要知道主要改动在哪。

    
    private static final int CORE_POOL_SIZE = 5;  
    private static final int MAXIMUM_POOL_SIZE = 128;  
    private static final it KEEP_ALIVE = 10;  
    ……  
    private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,  
            MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);  
    

    Android3.0之前的版本中核心线程数为5,最大线程数为128,非核心线程空闲等待新任务最长时间为10s。

        private static final int CORE_POOL_SIZE = 1;
        private static final int MAXIMUM_POOL_SIZE = 20;
        private static final int BACKUP_POOL_SIZE = 5;
        private static final int KEEP_ALIVE_SECONDS = 3;

    我现在的版本中只有一个核心线程,最大线程数为20,备份池大小为5,非核心线程空闲等待时间为3s。

    我么看一下AsynTask的构造函数:

    public AsyncTask() {
            this((Looper) null);
        }
    
    public AsyncTask(@Nullable Looper callbackLooper) {
            mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
                ? getMainHandler()
                : new Handler(callbackLooper);
            //关键代码1
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
                    Result result = null;
                    try {
                        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                        //noinspection unchecked
                        result = doInBackground(mParams);
                        Binder.flushPendingCommands();
                    } catch (Throwable tr) {
                        mCancelled.set(true);
                        throw tr;
                    } finally {
                        postResult(result);
                    }
                    return result;
                }
            };
            //关键代码2
            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);
                    }
                }
            };
        }

    关键代码1:WorkerRunnable实现了Callable接口,并实现了call方法,在call中调用了doInBackground(mParams)处理任务得到结果,最终调用postResult提交结果。

    关键代码2:FutureTask是一个可管理的异步任务,实现了Runnable和Future这两个接口。因此可以包装Runnable和Callable,并提供给Executor执行。在这里WorkerRunnable作为参数传递给FutureTask,这两个变量会保存到内存中,之后会用到。

     

    在执行时我们在主线程调用execute()方法:

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        //这里传入sDefaultExecutor跟params
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    @MainThread
        public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
                Params... params) {
            if (mStatus != Status.PENDING) {
                switch (mStatus) {
                    case RUNNING:
                        throw new IllegalStateException("Cannot execute task:"
                                + " the task is already running.");
                    case FINISHED:
                        throw new IllegalStateException("Cannot execute task:"
                                + " the task has already been executed "
                                + "(a task can be executed only once)");
                }
            }
    
            mStatus = Status.RUNNING;
    
            onPreExecute();
    
            mWorker.mParams = params;
            //将mFuture传入
            exec.execute(mFuture);
    
            return this;
        }

    在实际执行中先将状态变成RUNNING,之后调用onProExecute(),onProExecute中到底做了什么?,并将Params赋值给WorkerRunnable中。之前我们知道WorkerRunnable又传递给FutureTask,因此参数被封装到FutureTask中。之后会调用exec.execute(mFuture),exec又是什么?

    首先我们看一下onProExecute中的源码:

    @MainThread
    protected void onPreExecute() {
    }

    是一个空实现的方法,这就需要我们重写该方法,并实现准备的操作,运行在主线程,可进行UI操作。

    我们在exectueOnExecutor()中传入了sDefaultExecutor和params。

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
    //sDefaultExecutor实际就是SerialExecutor
    public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    
    
    private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            Runnable mActive;
    
            public synchronized void execute(final Runnable r) {
                //关键代码1
                mTasks.offer(new Runnable() {
                    public void run() {
                        try {
                            //关键代码2
                            r.run();
                        } finally {
                            scheduleNext();
                        }
                    }
                });
                if (mActive == null) {
                    scheduleNext();
                }
            }
    
            protected synchronized void scheduleNext() {
                if ((mActive = mTasks.poll()) != null) {
                    THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }
        }
    

    SerialExector是一个串行的线程池,当调用exectue方法时会将FutureTask加入到mTask中,当前任务执行完或者当前没有任务时会执行scheduleNext方法,会将任务交给THREAD_POOL_EXECUTOR来处理。

    关键代码2处执行了FutureTask的run方法,最终会调用WorkerRunnable的call方法,call又会最终调用postResult。

        public void run() {
            ...
            try {
                Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran;
                    try {
                        //c实际上就是WorkerRunnable
                        result = c.call();
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;
                        ran = false;
                        setException(ex);
                    }
                    if (ran)
                        set(result);
                }
            } finally {
                // runner must be non-null until state is settled to
                // prevent concurrent calls to run()
                runner = null;
                // state must be re-read after nulling runner to prevent
                // leaked interrupts
                int s = state;
                if (s >= INTERRUPTING)
                    handlePossibleCancellationInterrupt(s);
            }
        }

    可以看出FutureTask中的run就是调用传进来的WorkerRunnable的call方法,我们在AsynTask的构造函数中可以看到call中最后有调用的是postResult。

    private final Handler mHandler;
    
    
    private Result postResult(Result result) {
            @SuppressWarnings("unchecked")
            Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                    new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }
    
    private Handler getHandler() {
        return mHandler;
    }

    似乎看到了点Handler的影子,没错,AsyTask内部通过创建消息,并将结果赋值给Message,通过getHandler得到Handler对象,并通过sendToTarget发送消息。

    其实在上面构造函数代码中就已经初始化了Handler:

    //构造函数中获取mHandler
    //如果callbackLooper为null或者==Looper.getMainLooper就直接获取主线程Handler,否则会重新创建
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
                ? getMainHandler()
                : new Handler(callbackLooper);
    
    //获取主线程的Handler
    private static Handler getMainHandler() {
            synchronized (AsyncTask.class) {
                if (sHandler == null) {
                    //关键代码
                    sHandler = new InternalHandler(Looper.getMainLooper());
                }
                return sHandler;
            }
        }

    一般情况下都是调用的getMainHandler(),内部实际创建的是InternalHandler()。

    private static class InternalHandler extends Handler {
            public InternalHandler(Looper looper) {
                super(looper);
            }
    
            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
            @Override
            public void handleMessage(Message msg) {
                AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
                switch (msg.what) {
                    case MESSAGE_POST_RESULT:
                        // There is only one result
                        result.mTask.finish(result.mData[0]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                }
            }
        }

    在AsynTask中定义了一个私有内部类用来处理消息。接收到MESSAGE_POST_RESULT之后会调用AsynTask的finish()方法。

    private void finish(Result result) {
            if (isCancelled()) {
                onCancelled(result);
            } else {
                onPostExecute(result);
            }
            mStatus = Status.FINISHED;
        }

    如果AsynTask任务被取消了则会调用onCancelled方法,否则就调用onPostExecute。最后我们就是同个onPostExectue获取结果并进行更新UI操作。

    private static class SerialExecutor implements Executor {
            final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
            Runnable mActive;
     
            public synchronized void execute(final Runnable r) {
                mTasks.offer(new Runnable() {
                    public void run() {
                        try {
                            r.run();
                        } finally {
                            scheduleNext();
                        }
                    }
                });
                if (mActive == null) {
                    scheduleNext();
                }
            }
    

    在AsynTask中内部有两个线程池,一个就是之前我们说到的SerialExecutor,一般默认情况下都会使用这个线程池,使用时同一时间只能执行一个任务,一个任务执行完之后才会执行另一个任务。它使用了ArrayQueue队列,如果我们一次性启动很多任务,就会调用队列中的offer方法将任务加入到队列的尾部,并判断mActive是否为null,第一次运行时为null会执行scheduleNext,在finally中也调用了sceduleNext,这样就保证了每次执行完一个任务下一个任务才执行,该线程主要是将任务进行排列。

    我么看一下scheduleNext源码:

    protected synchronized void scheduleNext() {
                if ((mActive = mTasks.poll()) != null) {
                    THREAD_POOL_EXECUTOR.execute(mActive);
                }
            }
    实际上使用的THREAD_POOL_EXECUTOR
        private static final int CORE_POOL_SIZE = 1;
        private static final int MAXIMUM_POOL_SIZE = 20;
        private static final int BACKUP_POOL_SIZE = 5;
        private static final int KEEP_ALIVE_SECONDS = 3;
    
        public static final Executor THREAD_POOL_EXECUTOR;
    
        static {
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                    CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>(), sThreadFactory);
            threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
            //赋值
            THREAD_POOL_EXECUTOR = threadPoolExecutor;
        }
        //线程工厂
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
            private final AtomicInteger mCount = new AtomicInteger(1);
    
            public Thread newThread(Runnable r) {
                return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            }
        };

    最后赋值操作将threadPoolExecutor赋值给THREAD_POOL_EXECUTOR。其实该线程池才是任务的真正执行者。

    注意事项

    1.生命周期

    AsynTask不与任何组件生命周期进行绑定,在使用的对象中销毁时最好要调cancel()方法。

    2.内存泄漏

    一般我们声明都是一个内部类形式,内部类默认持有外部类的引用,当外部类使用完毕但是AsynTask中耗时任务还没执行完毕导致外部类无法回收,进而造成内存泄露

    3.结果丢失

    在进行屏幕旋转或者Activity进程被杀死之后会重新创建Activity,之前运行的AsynTask会持有之前Activity的引用,但该引用已经无效,导致onPostExectuor无法更新结果。

    4.AsynTask并行执行

    我们可以通过AsynTask的executeOnExecutor传入我们自定义的线程池,也可以传入AsynTask自身的THREAD_POOL_EXECTOR线程池。

     

    总结

    首先我们要创建AsynTask对象,在创建时会先去获取Handler对象,之后回去创建一个WorkerRunnable对象,之后会将WorkerRunnable当作参数传入到FutureTask中,创建好AsynTask对象之后就可以调用execute方法,实际上调用的是executeOnExecutor(sDefaultExectuor,mParams),内部是一个SerialExecutor对象,SerialExecutor是一个串行线程池,所有任务都在这里排队执行,之后先去执行onPreExecute(),该方法需要我们自己实现,之后线程池开始执行,并将FutureTask传入,并执行SerialExecutor中的execute()内部调用了FutureTask的run方法,实际就是调用了我们之前创建的WorkerRunnable对象的call方法,在call内部执行了doInBackground方法,我们只需要将耗时操作写在ondoInBackground中即可),从这里就从主线程切换到了子线程,首先判断任务中有没有正在活动的任务,如果没有则会调用scheduleNext获取一个任务,当任务执行完毕之后在finally中再去调用scheduleNext,保证了该任务执行完毕之后再调用下一个任务,在scheduleNext内部通过THREAD_POOL_EXECUTOR进行任务执行。而在内部还有一个静态Handler对象,他的作用就是将子线程切换到主线程,为了能够进行更新UI操作,只要保证AsynTask在主线程创建即可。我们在doInBackground中通过publishProgress()创建消息,并通过Handler将消息发送出去,AsynTask中的InternalHandler中handleMessage调用onProgressUpdate()方法进行进度更新。当任务执行完毕doInBackground会返回结果到postResult中,再去发送消息给Handler,handler中会调用finish(),这样任务就执行完毕。

    展开全文
  • Android AsynTask 分析

    2017-05-25 16:53:05
    本次我们将来介绍一下Android的异步任务类AsynTask,相信大家平时在开发的时候经常使用。一般我们在做一些比较耗时的操作任务都会开启一个线程去执行任务,因为这样子不会阻塞UI线程,用户操作起来界面的时候才不会...

          本次我们将来介绍一下Android的异步任务类AsynTask,相信大家平时在开发的时候经常使用。一般我们在做一些比较耗时的操作任务都会开启一个线程去执行任务,因为这样子不会阻塞UI线程,用户操作起来界面的时候才不会卡顿的,大大的增加了用户体验的,但是懒惰的工程师经常嫌弃开启一个线程在更新UI界面的时候还需要再使用Handler。这样子就可能会使得代码不美观。

    使用说明

    具体的使用我这里就不详细的写demo来说明,因为android都这么久了,大家都用的这么久的时间了,网上一大片的使用说明,下面我写一段伪代码来稍微的说明一下用法,最关键的还是看它的内部实现以及为啥不需要使用Handler去更新UI的。

    public class AsynTaskActivity extends Activity {
    
        private DownloadApkTask mDownloadTask;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            this.setContentView(R.layout.activity_web_view);
            mDownloadTask = new DownloadApkTask();
            mDownloadTask.execute("http://www.yy23.com/path/file.apk");
        }
    
        private class DownloadApkTask extends AsyncTask<String, Integer, String> {
    
            @Override
            protected void onPreExecute() {
                //开始准备执行下载操作的,运行在UI线程中
            }
    
            @Override
            protected String doInBackground(String... params) {
                /**
                 * 我们在这里执行下载apk的代码(该方法运行在子线程中,是直接做耗时的操作的,
                 * 所以不能在这里更新UI),如果在下载的过程中我们需要不断的去更新进度的话,
                 * 我们需要在该方法中调用 publishProgress(progress)来将进度发送到 onProgressUpdate()中
                 */
                return "success";
            }
    
            @Override
            protected void onProgressUpdate(Integer... values) {
                //我们可以在这里去更新进度条的进度(运行在UI线程中)
            }
    
            @Override
            protected void onPostExecute(String s) {
                /**
                 * 这里表示我们的任务执行结束,运行在UI线程中,这里参数s是 doInBackground()的返回值
                 * 这个时候我们在 doInBackground来根据有没有抛出异常或者是下载成功,然后返回不同的值
                 * 然后在判断该方法的参数,再做最后的业务逻辑判断
                 */
            }
        }
    }

          上面就是我们在使用AsynTask的时候的一个模版,AsynTask是一个抽象类我们一般都是通过去继承这个类的,在继承该类的时候有三个泛型参数需要我们自己去实现的。AsyncTask

    在使用的时候,有几点需要格外注意:

    • 异步任务的实例必须在UI线程中创建。
    • execute(Params… params)方法必须在UI线程中调用。
    • 不要手动调用onPreExecute(),doInBackground(Params… params),onProgressUpdate(Progress… values),onPostExecute(Result result)这几个方法。
    • 不能在doInBackground(Params… params)中更改UI组件的信息。
    • 一个任务实例只能执行一次,如果执行第二次将会抛出异常。

    实现原理

    AsynTask执行任务的核心就在于线程池,所以在创建AsynTask对象之前首先会有静态的成员变量用于记录创建的线程池信息。我们都知道在创建线程池的具体参数:

    • corePoolSize
      线程池中的核心线程数,当提交一个任务是,线程池创建一个新线程执行任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。

    • maximumPoolSize
      线程池中允许的最大执行任务的线程数。如果提交的任务操作最大任务数,切继续提交任务则新提交的任务会保存在阻塞队列中的。也就是我们下面说的workQueue队列中。

    • keepAliveTime
      线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间;默认情况下,该参数只在线程数大于corePoolSize时才有用;

    • unit
      keepAliveTime的单位,一般单位我可以直接使用 TimeUnit.SECONDS(秒), TimeUnit.MINUTES(分钟)等等

    • workQueue
      用来保存等待被执行的任务的阻塞队列,且任务必须实现Runable接口,在JDK中提供了如下阻塞队列:
      1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务
      2、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene
      3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene
      4、priorityBlockingQuene:具有优先级的无界阻塞队列
    • threadFactory
      创建线程的工厂,通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。
      image_1bgsu94kp14i51gr5gh1fofubh9.png-17.9kB

    当我们解释了线程池的一些参数之后下面我们就来看看AsynTask参数的线程池的一些参数配置

        ........
    
        private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
        private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
        private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
        private static final int KEEP_ALIVE = 1;
    
        private static final ThreadFactory sThreadFactory = new ThreadFactory() {
            private final AtomicInteger mCount = new AtomicInteger(1);
    
            public Thread newThread(Runnable r) {
                return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
            }
        };
    
        private static final BlockingQueue<Runnable> sPoolWorkQueue =
                new LinkedBlockingQueue<Runnable>(128);
    
        public static final Executor THREAD_POOL_EXECUTOR
                = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
    
        .......

    从上面的代码中我们可以看出CORE_POOL_SIZE数目是:虚拟机可用的最大处理器数量(这里并不是CPU的最大个数,这个是表面的字段意思);MAXIMUM_POOL_SIZE是CORE_POOL_SIZE*2+1的,如果当线程池中的任务数目操作了maximum_pool_size的时候,则会保存到workqueue中该缓存队列最多可以缓存128个任务。

    /**
         * Creates a new asynchronous task. This constructor must be invoked on the UI thread.
         */
        public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    return postResult(doInBackground(mParams));
                }
            };
    
            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 occured while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        postResultIfNotInvoked(null);
                    }
                }
            };
        }
    
        private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
            Params[] mParams;
        }

        通过在构造方法中我们看到创建了一个FutureTask以及创建一个Callable对象,这里我们就需要看看我们之前的关于 FutureTask、Callable和Future的关联和使用,因为你只有把这几个东西看懂了之后,你才能看懂这个里面的封装代码。我们这里只是稍微做一个简短的介绍:

    Future(type:interface): 里面定义了很多方法用来判断异步任务的执行状态以及获取执行的结果
    Callable (type:interface): 里面仅仅定义了一个 call方法直接运行在FutureTask的runn方法,其子类主要是通过参数传入到FutureTask构造方法中。
    FutureTask:实现了Runnable接口和 Future的类,然后在构造方法来获取Callable接口的子对象,所以该类可以在线程池中执行,也可以通过Thread类来执行,也是一个线程类。

        通过我们对Callable、Future以及FutureTaskde的理解,我们知道线程池执行FutureTask任务其实也是直接运行FutureTask的run()方法的,而Callable类的call()方法其实也是直接在run方法中运行的,只不过call()方法会有返回值,所以我们也可以在call()方法写我们需要直接的耗时操作,然后将结果返回出去。当任务执行完成的时候就会调用done()方法的,这个时候的done方法其实也还是在run()方法里面的也就是说同样还在子线程中的。所以我们看到的 doInBackground()函数是直接运行在子线程里面的,然后通过call()方法将doInBackground方法执行完成的结果返回出去,

    mWorker = new WorkerRunnable<Params, Result>() {
            public Result call() throws Exception {
                mTaskInvoked.set(true);
    
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                return postResult(doInBackground(mParams));
            }
    };

    通过这个简短的代码中我们可以看的出来doInBackground()是直接运行在子线程中,然后将该函数的返回值当作参数传递到postResult()方法中

    @SuppressWarnings("unchecked")
    private Result postResult(Result result) {
        Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
    }

    从代码中我们可以看出postResult()其实也没有做什么操作,也就只是发送了一个Handler消息出去了,消息类型为MESSAGE_POST_RESULT的,同时封装了一个AsyncTaskResult将当前对象和结果封装起来然后统一发送到Handler中的。

    private static class InternalHandler extends Handler {
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) {
                case MESSAGE_POST_RESULT:
                    // There is only one result
                    result.mTask.finish(result.mData[0]);
                    break;
                    .......
            }
        }
    }
    
    private void finish(Result result) {
        if (isCancelled()) {
            onCancelled(result);
        } else {
            onPostExecute(result);
        }
        mStatus = Status.FINISHED;
    }

          从这几段的代码中可以非常的容易的就看到最后postResult()发送了一个Message消息之后,最后调用了finish()方法,最后判断如果我们没有主动调用cancel方法的话,则会调用onPostExecute(),该方法就是我们之前demo里面的用来处理最后结果状态的函数,从代码中我们可以看到onPostExecute就是直接运行在主线程里面的,原因是在postResult()的时候,使用了handler将doInBackground方法的结果一致发送到主线程里面,然后我们也可以重写onPostExecute方法来处理结束的业务逻辑,如果我们主动的将任务取消之后则会调用onCancelled函数,最后我们只要复写该函数就可以来处理相应的业务逻辑了。
          在上面的时候我们还有一个重要的功能就是更新界面进度条的时候还没有分析:其实我们在doInBackground中使用publishProgress方法来发送消息到UI线程的onProgressUpdate方法的,其实我们啥也不用去看,只要看源代码以及源代码里面的代码注视就行了,因为api文档的生成就是通过代码的注视来生成的,所以看代码和代码的注视是我们学习的一个重要的关键。

    /**
         * This method can be invoked from {@link #doInBackground} to
         * publish updates on the UI thread while the background computation is
         * still running. Each call to this method will trigger the execution of
         * {@link #onProgressUpdate} on the UI thread.
         * {@link #onProgressUpdate} will note be called if the task has been
         * canceled.
         * @param values The progress values to update the UI with.
         * @see #onProgressUpdate
         * @see #doInBackground
         */
        protected final void publishProgress(Progress... values) {
            if (!isCancelled()) {
                sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
                        new AsyncTaskResult<Progress>(this, values)).sendToTarget();
            }
        }

         在代码中,我们发现publishProgress方法中也是将当前进度值和对象封装成一个AsyncTaskResult对象然后发送了一个MESSAGE_POST_PROGRESS的message到InternalHandler中的,在InnerHandler处理消息的时候最后调用的是onProgressUpdate(progress),该函数也是我们在AsynTask复写的方法所以我们也知道了publishProgress和onProgressUpdate联系了吧。

    private static class InternalHandler extends Handler {
        public void handleMessage(Message msg) {
            AsyncTaskResult result = (AsyncTaskResult) msg.obj;
            switch (msg.what) {
                .......
                case MESSAGE_POST_PROGRESS:
                    result.mTask.onProgressUpdate(result.mData);
                    break;
            }
        }
    }
    
    /**
     * Runs on the UI thread after {@link #publishProgress} is invoked.
     * The specified values are the values passed to {@link #publishProgress}.
     *
     * @param values The values indicating progress.
     *
     * @see #publishProgress
     * @see #doInBackground
     */
    protected void onProgressUpdate(Progress... values) {
    }

          当创建完AsynTask对象之后我们就可以执行execute(Params …paras)来触发任务的执行,从实际的代码中我们可以看出是直接将我们在构造方法中创建的mFuture任务直接提交到线程池中执行的,同时也看到了之前的回调方法 onPreExecute(),然后任务的状态置为RUNNING状态,如果当前对象的状态已经是运行或者结束状态的话,再运行的话就会抛出异常的,也就是说我们的任务不能execute两次的。很多的人在这里可能会非常的疑惑就是:这里的执行任务非常非常的简单,只是一个mFutureTask提交到线程池中去执行,在执行之前先调用一个方法,也就是我们所说的调用之前的准备工作。其实最最关键的还是我们之前的构造方法中的。

    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
                Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }
    
        mStatus = Status.RUNNING;
    
        onPreExecute();
    
        mWorker.mParams = params;
        exec.execute(mFuture);
    
        return this;
    }

    总结

          通过上面我们对AsyncTask的分析我们知道在创建该对象的同时也会创建一个线程任务,然后执行的时候会将该内部的任务提交到线程池中去执行,然后内部维护着一个InnerHandler用于将线程中的状态同步到主线程的方法中,我们只要复写该类的指定方法来做相应的操作就可以了,其实这个跟我们 Thread + Handler模式来处理耗时的操作是一样的,只是人家把Thread 和 Handler 都封装到一个类中,然后暴漏出相应的方法让调用者调用就行了,这样子就可以显得代码非常的简洁和易读的,同时我们也可以充分的利用系统暴漏给我们的线程池去执行我们想要的任务,其实很多的时候我们完全不需要使用去创建什么线程池了,比如说我们还可以使用AsyncTask中的execute(Runnable runnable)直接提交一个我们自定义的异步线程任务类,这样子是充分的利用了系统自带的线程池的。

    PS:由于写作水平和对知识的总结水平的有限,所以导致写出来的博客有点记流水账似的,还请大家看的少喷,我也不断的提高自己的,如果大家有什么疑问可以跟我联系;我个人的观点尽所有的可能还原代码的最真实的情况,因为代码才是最最真实的,源代码的阅读比你阅读什么博客都更直接的,博客只是别人的一个总结,但是阅读代码来的体会则是自己来的最真实的。

    展开全文
  • 本文主要介绍了android AsynTask处理返回数据和AsynTask使用get,post请求方法。具有一定的参考价值,下面跟着小编一起来看下吧
  • AsynTask_loading-Test 异步加载的练习demo 主要涉及知识点: 1.解析json格式数据,主要包括图片,文本 2.使用线程和AsynTask俩种异步方式从网络下载图片 3.handler的使用 4.使用Lru缓存算法 5.改进加载:仅在...
  • android asynTask 异步后台线程 各种操作 经典完整 非常经典 非常完整的代码。
  • AsynTask是Android提供的一个轻量级的异步类,使用时可以直接继承AsynTask,在类中可以直接进行UI操作,并将后台计算的结果及时的交给UI线程进行UI界面显示,而这些操作之前是由Thread+Headler进行的,但是由于...
  • hpapp 使用asyntask和php作为Web服务进行注册和登录
  • AsynTask异步任务用法

    2018-03-27 16:32:10
    AsynTask封装了子线程,可以直接用来处理耗时操作。AsyncTask&lt;Params,Progress,Result&gt;是个抽象类,使用时需要继承这个类,然后调用execute()方法。使用三板斧:1创建AsyncTask的子类,并为三个范型...
  • Android Asyntask

    2014-11-12 12:35:55
    Android Asyntask sample code
  • asynTask是activity中的非静态内部类,由于java内部类的特点,asynTask会持有外部类的隐式引用,由于asyntask的生命周期可能比activity的长,当activity销毁的时候而asynTask仍然在执行,这样就造成asynTask持有的...
  • AsynTask解析

    2018-04-22 16:39:42
    主线程调用AsynTask子类实例的execute()方法后,首先会调用onPreExecute()方法。onPreExecute()在主线程中运行,可以用来写一些开始提示代码。 之后启动新线程,调用doInBackground()方法,进行异步数据处理。 处理...
  • AsynTask和打电话的pdf

    2019-03-19 01:14:11
    NULL 博文链接:https://carywei.iteye.com/blog/700123
  • 深入学习AsynTask

    2019-09-23 01:55:02
    基本的参考 : http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html http://www.cnblogs.com/dawei/archive/2011/04/18/2019903.html 深入的: ...
  • AsynTask用法

    2015-09-01 09:39:00
      在Android中实现异步任务机制有两种方式,Handler和AsyncTask。 Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较...
  • 异步任务asyntask android的demo,实现从网络下载图片,亲测可用,改了bug
  • 自定义AsynTask实现在子线程中加载图片,并将下载进度通过ProgressDialog显示,然后加载到ImageView上。
  • 异步任务代码示例程序
  • Android AsynTask

    2016-03-24 21:56:00
    这两天研究android网络图片加载,一般意义上加载网络图片时大家都会从创建线程与加载异步任务这两种方法中选择,这篇文章关于这两种方法的使用特征以及方法都做了很好的讲解。... AsyncTask和Handler对比 ...
  • AsynTask的使用

    2016-05-23 17:23:17
    详解Android中AsyncTask的使用 标签: android任务layoutbuttonthreadasynchronous 2011-06-08 19:00 202566人阅读 评论(120) 收藏 举报 本文章已收录于: ...版权声明:本文为
  • 在Android中实现异步任务机制有两种方式,Handler和AsyncTask。 Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较...
  • AsynTask是Android SDK中自带的网络请求API,今天来分析下AsynTask的源代码,顺便说一下AsynTask的用法和优缺点。 先来看看AsynTask是怎么用的:
  • 其实,AsynTask类就是对Thread类的一个封装,并且加入了一些新的方法。编程时,两者都可以实现同样的功能。本文后面将对AsynTask和Thread进行比较。 1、AsynTask类结构 asysTask类主要用到的几个内部回调函数有...
  • AsynTask方便在后台线程中执行操作,然后将结果发给主线程,从而在主线程更新UI,无需关心Thread和Handler;AsynTask只能执行短暂的后台任务,如果需要执行长时间耗时任务,推荐使用java.util.concurrent包中的...
  • 通过一个进度条的使用,模拟下载文件时的状态,在下载文件时动态改变UI显示状态

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,580
精华内容 632
关键字:

asyntask

友情链接: ZHY-PARKING.zip