码迷,mamicode.com
首页 > 移动开发 > 详细

Android中8种异步处理与计算的方法

时间:2016-01-11 21:58:02      阅读:507      评论:0      收藏:0      [点我收藏+]

标签:

注:该文章翻译自Ali Muzaffar的文章8 ways to do asynchronous processing in Android and counting》

 

  Android提供了许多API来支持异步处理的功能,结合着Java提供的方法和你手上拥有的,估计目前已经有数十种进行异步任务的方法。

    目前的趋势是仅使用Java的threads或者Android的AsyncTask来处理各种问题。虽然上述两种方法拥有较高的知名度,但是并非所有的API都适合,为你的需求选择最合适的方法能够使你的代码稳定,整洁,高可读而且更加的直观。
    所以,下面将展示7种在Android中常用的开展异步任务的方法。依据Android API ->Java的顺序以及我使用的频次来排序。
 

    AsyncTask

    AsyncTask肯能是Android中最出名的异步处理API,它容易实现并且在主线程中返回结果。但是,AsyncTask也有不少的问题,例如:它们不清楚activity和fragment的生命周期,因此当activity被销毁的时候开发人员需要处理AsyncTask的响应。这就意味着它并非处理长时运行任务的最佳选择,如果app在后台运行,当app被Android结束的时候你的后台任务也会被终结。
 1 new AsyncTask<URL, Integer, Long>() {
 2      protected Long doInBackground(URL... urls) {
 3          int count = urls.length;
 4          long totalSize = 0;
 5          for (int i = 0; i < count; i++) {
 6              totalSize += Downloader.downloadFile(urls[i]);
 7              publishProgress((int) ((i / (float) count) * 100));
 8              // Escape early if cancel() is called 
 9              if (isCancelled()) break;
10          } 
11          return totalSize;
12      } 
13 
14      protected void onProgressUpdate(Integer... progress) {
15          setProgressPercent(progress[0]);
16      } 
17 
18      protected void onPostExecute(Long result) {
19          showDialog("Downloaded " + result + " bytes");
20      } 
21  }.execute(url1, url2, url3);
22 // Modified Code from google Android API

 

    IntentService
   实际上IntentService是Android中长时运行任务的常用选择,通常被用于实现大文件的上传与下载。上传与下载可能会在用户退出app之后继续执行,同样的你肯定也不希望在上传、下载大文件的时候用于不能操作app。
 1 public class RSSPullService extends IntentService {
 2     @Override 
 3     protected void onHandleIntent(Intent workIntent) {
 4         // Gets data from the incoming Intent 
 5         String dataString = workIntent.getDataString();
 6         ... 
 7         // Do work here, based on the contents of dataString 
 8         ... 
 9     } 
10 }
 1 // AndroidManifest.xml
 2 <application
 3     android:icon="@drawable/icon"
 4     android:label="@string/app_name">
 5     ...
 6     <!--
 7        Because android:exported is set to "false",
 8        the service is only available to this app.
 9     -->
10     <service
11         android:name=".RSSPullService"
12         android:exported="false"/>
13     ...
14 <application/>

 

    Loader
   加载器是一个复杂的主题,任何一个单独实现的加载器都可能为它自身应用到多种情况。目前,需要指出加载器在Android Honeycomb中被引入的概念,它是一个复杂库的组成部分。它们清楚activity和fragment的生命周期,而且能够缓存加载的数据。
    需要重点介绍的是异步加载器,它们解决了很多继承AysncTask之后出现的问题。Android中的设计模式一文中有对加载器的详细描写,我建议大家阅读,对于加载器会有更深的了解。(文章地址:Android Design Patterns has an amazing write-up on Loaders )
    
    JobScheduler and GcmNetworkManager
    我将它们两个放在一起介绍的原因是因为它们的功能特性是相似的。
    Job Scheduler在API 21中被发布出来,目前谷歌暂时没有提供官方的兼容版本。(Evan Tatarka 填补了Job Scheduler的空白,详情请见JobSchedulerCompat
    然而,GcmNetworkManager被绑定在Google Play 7.5中使用,提供了与Job Scheduler相似的特性,但是它被设计用于网络操作。
    使用Job Scheduler有一点复杂,好消息是谷歌有一个如何使用Job Scheduler的例子(JobScheduler )。实际上,你需要使用JobInfo.Builder来创建服务和Job,指定你运行服务的标准;例如运行在为计量的网络,或者是当设备在充电时app的反应。需要注意的是,不能保证你的代码在上述情况发生时就被执行,以及会按照顺序执行。下面为大家展示一段谷歌提供的如何使用Job Scheduler的样例代码:
 1 JobInfo.Builder builder = new JobInfo.Builder(kJobId++, 
 2                                                 mServiceComponent);
 3 String delay = mDelayEditText.getText().toString();
 4 if (delay != null && !TextUtils.isEmpty(delay)) {
 5   builder.setMinimumLatency(Long.valueOf(delay) * 1000);
 6 }
 7 String deadline = mDeadlineEditText.getText().toString();
 8 if (deadline != null && !TextUtils.isEmpty(deadline)) {
 9   builder.setOverrideDeadline(Long.valueOf(deadline) * 1000);
10 }
11 boolean requiresUnmetered =
12                         mWiFiConnectivityRadioButton.isChecked();
13 boolean requiresAnyConnectivity = 
14                         .mAnyConnectivityRadioButton.isChecked();
15 if (requiresUnmetered) {
16   builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
17 } else if (requiresAnyConnectivity) {
18   builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
19 }
20 builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked());
21 builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked());mTestService.scheduleJob(builder.build());
22 // CANCEL JOBS
23 JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
24 tm.cancelAll();
    下面的链接将展示出如何使用GcmNetworkManager,在GcmNetworkManager的示例页面。( GcmNetworkManager page for example code )GcmNetworkManager的主要思想是制定何时,何种情况被满足时你的服务会被调度。同样可以参考。(Scheduled Tasks can be One-off or Periodic

    CountDownTimer    

    不用猜都可以知道CountDownTimer会被用于哪里。它非常容易被使用,然而它对于上下文是敏感的,因此如果你退出你的activity或者是fragment,你需要取消CountDownTimer来清空它占用的空间。进一步说明,实际上CountDownTimer中确实没有异步任务,如果你看它的源码,它仅仅是发送需要延迟的消息给Handler,这就意味着不管你为她指定哪个线程它都会被执行,onTick(),onFinish()方法也会被执行,如此一来你就可以在CountDownTimer内部刷新UI界面。正式因为如此在onTick()和onFinish()方法中不适合做复杂运算。之所以把CountDownTimer加入在这个清单里面,是因为使用该类不会阻塞用户使用app,不管CountDownTimer是不是在主线程中被初始化,这样就有效的提供了一异步的效果。需要注意的是,如果你的更新操作的间隔很短、里面有很多耗时操作,你可能会遇到back-pressure问题,这样可能会拜你的执行线程阻塞了。
1 new CountDownTimer() {
2             @Override
3             public void onFinish() {
4             }
5 @Override
6             public void onTick(long millisUntilFinished) {
7             }
8     }.start();

    Java Threads or Android HandlerThread

    尽管Java的线程能够更直截了当地被实现,但是在Android中应该尽量避免使用它。我见过它们在被限制的情况下依然被用于各种实例中,同时Android不允许在后台进程中进行UI更新。可能使用AsyncTask是一个更好的选择。
1 new Thread(new Runnable(){
2   public void run() {
3     // do something here
4   }
5 }).start();

    Android的HandlerThread可以被用于在后台线程中handle Message。使用它会被消息处理机制限制,因为消息处理更倾向于重定向而不是处理任务,尽管这样也为我们提供了一个将一些任务放在后台进程运行的方法。一个使用HandlerThread的可行方法是在一个后台进程中运行一个服务。

 1 public class TickTockService extends Service {
 2 public void onCreate() {
 3   // Start up the thread running the service. Note that we create a
 4   // separate thread because the service normally runs in the process‘s
 5 // main thread, which we don‘t want to block. We also make it
 6 // background priority so CPU-intensive work will not disrupt our UI.
 7             mThread = new HandlerThread("ServiceArguments", 
 8                                Process.THREAD_PRIORITY_BACKGROUND); 
 9             mThread.start();
10     // Get the HandlerThread‘s Looper and use it for  our Handler
11             mServiceLooper = mThread.getLooper();
12             mServiceHandler = new Handler(mServiceLooper);
13   }
14 }

      FutureTask

    FutureTask提供异步处理的功能,但是,当运算还没有结束或者是结果没有被准备好的时候调用get()方法会阻塞线程。

    我居然在不少地方使用了FutureTask,例如:当你想要在谷歌的Volley中采用阻塞的方式执行请求的时候就可以用FutureTask。下面是如何使用FutrueTask的例子,在你使用FutureTask的时候你必须确保UI线程不会被阻塞。

1 RequestFuture<JSONObject> future = RequestFuture.newFuture();
2 JsonObjectRequest request = new JsonObjectRequest(URL, null, future, future);
3 requestQueue.add(request);
    通常都会阻塞UI线程,你可以使用future.get(30,TimeUnit.SECONDS);在30秒过后会抛出timeout的异常,而非无限期得等待。

 

 1 try { 
 2   JSONObject response = future.get(); // this will block (forever)
 3 } catch (InterruptedException e) {
 4   // exception handling 
 5 } catch (ExecutionException e) {
 6   // exception handling 
 7 }
 8     Java Timer / ScheduledThreadPoolExecutor
 9 
10  

    下面是一个使用Java Timer的例子,功能是在5秒后做一些工作。它们两个类可以被用于调度一些运行于后台的线程。在Android中还有一些类似的处理方法,你可以使用带有postDelayed的Handler或者是Handler 结合调用sendMessageDelayed()方法,这样handler就会运行在后台正如上面展示的一样。同样,你要清楚这两个API对于Android的生命周期不清楚,很难在Activity、Fragment或者是View中引用它们,因为这样可能会导致内存泄露。

1 Timer timer = new Timer();
2 timer.schedule(new TimerTask(){
3   public void run() {
4     // time ran out.
5     timer.cancel(); 
6   }
7 }, 5000);

 

    Java API中的解释:ThreadPoolExecutor可以通过延迟执行或者是定期执行来调度进程。该类在许多工作线程需要被创建、或者是需要ThreadPoolExecutor更加的可扩展和可用的时候比Timer类更加适用。延迟任务的执行不会早于它们被创建,但是关于它们何时可用并不提供实时性的保证。任务被安排了近乎相同的执行时间,并且采用先进先出(FIFO)的机制来调度子任务。

 1 public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
 2    static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
 3    protected <V> RunnableScheduledFuture<V> decorateTask(
 4                 Runnable r, RunnableScheduledFuture<V> task) {
 5        return new CustomTask<V>(r, task);
 6    }
 7    protected <V> RunnableScheduledFuture<V> decorateTask(
 8                 Callable<V> c, RunnableScheduledFuture<V> task) {
 9        return new CustomTask<V>(c, task);
10    }
11    // ... add constructors, etc.
12  }
13 // Code from Java API

 

    在Android中使用ScheduledThreadPoolExecutor会如同Timer和Java的Threads一样遇到相同的问题:如果你需要更行UI界面,你需要使用Handler来发送消息给UI线程,或者是通过一个Listener来传递。ScheduledThreadPoolExecutor是Java的一部分,它同样对于Activity、Fragment的生命周期不明感,因此大量的Listener需要被手动地清理或者是换,否则很有可能会导致内存泄露。

 

Android中8种异步处理与计算的方法

标签:

原文地址:http://www.cnblogs.com/xlk0101/p/5122432.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!