• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.dialer.common.concurrent;
18 
19 import android.app.FragmentManager;
20 import android.support.annotation.NonNull;
21 import com.android.dialer.common.Assert;
22 import com.android.dialer.common.concurrent.DialerExecutor.Worker;
23 
24 /**
25  * Factory methods for creating {@link DialerExecutor} objects for doing background work.
26  *
27  * <p>You may create an executor from a UI component (activity or fragment) or a non-UI component.
28  * Using this class provides a number of benefits:
29  *
30  * <ul>
31  *   <li>Ensures that UI tasks keep running across configuration changes by using a headless
32  *       fragment.
33  *   <li>Forces exceptions to crash the application, unless the user implements their own onFailure
34  *       method.
35  *   <li>Checks for dead UI components which can be encountered if a UI task runs longer than its
36  *       UI. If a dead UI component is encountered, onSuccess/onFailure are not called (because they
37  *       can't be) but a message is logged.
38  *   <li>Helps prevents memory leaks in UI tasks by ensuring that callbacks are nulled out when the
39  *       headless fragment is detached.
40  *   <li>UI and non-UI threads are shared across the application and run at reasonable priorities
41  * </ul>
42  *
43  * <p>Executors accept a single input and output parameter which should be immutable data objects.
44  * If you don't require an input or output, use Void and null as needed.
45  *
46  * <p>You may optionally specify onSuccess and onFailure listeners; the default behavior on success
47  * is a no-op and the default behavior on failure is to crash the application.
48  *
49  * <p>To use an executor from a UI component, you must create it in your onCreate method and then
50  * use it from anywhere:
51  *
52  * <pre><code>
53  *
54  * public class MyActivity extends Activity {
55  *
56  *   private final DialerExecutor&lt;MyInputType&gt; myExecutor;
57  *
58  *   public void onCreate(Bundle state) {
59  *     super.onCreate(bundle);
60  *
61  *     // Must be called in onCreate; don't use non-static or anonymous inner classes for worker!
62  *     myExecutor = DialerExecutors.createUiTaskBuilder(fragmentManager, taskId, worker)
63  *         .onSuccess(this::onSuccess)  // Lambdas, anonymous, or non-static inner classes all fine
64  *         .onFailure(this::onFailure)  // Lambdas, anonymous, or non-static inner classes all fine
65  *         .build();
66  *     );
67  *   }
68  *
69  *   private static class MyWorker implements Worker&lt;MyInputType, MyOutputType&gt; {
70  *     MyOutputType doInBackground(MyInputType input) { ... }
71  *   }
72  *   private void onSuccess(MyOutputType output) { ... }
73  *   private void onFailure(Throwable throwable) { ... }
74  *
75  *   private void userDidSomething() { myExecutor.executeParallel(input); }
76  * }
77  * </code></pre>
78  *
79  * <p>Usage for non-UI tasks is the same, except that tasks can be created from anywhere instead of
80  * in onCreate. Non-UI tasks use low-priority threads separate from the UI task threads so as not to
81  * compete with more critical UI tasks.
82  *
83  * <pre><code>
84  *
85  * public class MyManager {
86  *
87  *   private final DialerExecutor&lt;MyInputType&gt; myExecutor;
88  *
89  *   public void init() {
90  *     // Don't use non-static or anonymous inner classes for worker!
91  *     myExecutor = DialerExecutors.createNonUiTaskBuilder(worker)
92  *         .onSuccess(this::onSuccess)  // Lambdas, anonymous, or non-static inner classes all fine
93  *         .onFailure(this::onFailure)  // Lambdas, anonymous, or non-static inner classes all fine
94  *         .build();
95  *     );
96  *   }
97  *
98  *   private static class MyWorker implements Worker&lt;MyInputType, MyOutputType&gt; {
99  *     MyOutputType doInBackground(MyInputType input) { ... }
100  *   }
101  *   private void onSuccess(MyOutputType output) { ... }
102  *   private void onFailure(Throwable throwable) { ... }
103  *
104  *   private void userDidSomething() { myExecutor.executeParallel(input); }
105  * }
106  * </code></pre>
107  *
108  * Note that non-UI tasks are intended to be relatively quick; for example reading/writing shared
109  * preferences or doing simple database work. If you submit long running non-UI tasks you may
110  * saturate the shared application threads and block other tasks. Also, this class does not create
111  * any wakelocks, so a long running task could be killed if the device goes to sleep while your task
112  * is still running. If you have to do long running or periodic work, consider using a job
113  * scheduler.
114  */
115 public final class DialerExecutors {
116 
117   /** @see DialerExecutorFactory#createUiTaskBuilder(FragmentManager, String, Worker) */
118   @NonNull
createUiTaskBuilder( @onNull FragmentManager fragmentManager, @NonNull String taskId, @NonNull Worker<InputT, OutputT> worker)119   public static <InputT, OutputT> DialerExecutor.Builder<InputT, OutputT> createUiTaskBuilder(
120       @NonNull FragmentManager fragmentManager,
121       @NonNull String taskId,
122       @NonNull Worker<InputT, OutputT> worker) {
123     return new DefaultDialerExecutorFactory()
124         .createUiTaskBuilder(
125             Assert.isNotNull(fragmentManager), Assert.isNotNull(taskId), Assert.isNotNull(worker));
126   }
127 
128   /** @see DialerExecutorFactory#createNonUiTaskBuilder(Worker) */
129   @NonNull
createNonUiTaskBuilder( @onNull Worker<InputT, OutputT> worker)130   public static <InputT, OutputT> DialerExecutor.Builder<InputT, OutputT> createNonUiTaskBuilder(
131       @NonNull Worker<InputT, OutputT> worker) {
132     return new DefaultDialerExecutorFactory().createNonUiTaskBuilder(Assert.isNotNull(worker));
133   }
134 }
135