AsyncTask API 在 Android 中被弃用 11. 有哪些替代方案?
The AsyncTask API is deprecated in Android 11. What are the alternatives?
Google 在 Android 11 中弃用 Android AsyncTask API 并建议改用 java.util.concurrent
。你可以查看提交 here
*
* @deprecated Use the standard <code>java.util.concurrent</code> or
* <a href="https://developer.android.com/topic/libraries/architecture/coroutines">
* Kotlin concurrency utilities</a> instead.
*/
@Deprecated
public abstract class AsyncTask<Params, Progress, Result> {
如果您在 Android 中维护带有异步任务的旧代码库,您将来可能不得不更改它。我的问题是应该使用 java.util.concurrent
正确替换下面显示的代码片段。它是 Activity 的静态内部 class。我正在寻找可以与 minSdkVersion 16
一起使用的东西
private static class LongRunningTask extends AsyncTask<String, Void, MyPojo> {
private static final String TAG = MyActivity.LongRunningTask.class.getSimpleName();
private WeakReference<MyActivity> activityReference;
LongRunningTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
@Override
protected MyPojo doInBackground(String... params) {
// Some long running task
}
@Override
protected void onPostExecute(MyPojo data) {
MyActivity activity = activityReference.get();
activity.progressBar.setVisibility(View.GONE);
populateData(activity, data) ;
}
}
private WeakReference<MyActivity> activityReference;
很高兴它已被弃用,because the WeakReference<Context>
was always a hack, and not a proper solution。
现在人们将有机会净化他们的代码。
AsyncTask<String, Void, MyPojo>
基于这段代码,其实不需要Progress
,还有一个String
输入+MyPojo
输出。
这实际上很容易完成,无需使用任何 AsyncTask。
public class TaskRunner {
private final Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements
private final Handler handler = new Handler(Looper.getMainLooper());
public interface Callback<R> {
void onComplete(R result);
}
public <R> void executeAsync(Callable<R> callable, Callback<R> callback) {
executor.execute(() -> {
final R result = callable.call();
handler.post(() -> {
callback.onComplete(result);
});
});
}
}
如何传入String?像这样:
class LongRunningTask implements Callable<MyPojo> {
private final String input;
public LongRunningTask(String input) {
this.input = input;
}
@Override
public MyPojo call() {
// Some long running task
return myPojo;
}
}
和
// in ViewModel
taskRunner.executeAsync(new LongRunningTask(input), (data) -> {
// MyActivity activity = activityReference.get();
// activity.progressBar.setVisibility(View.GONE);
// populateData(activity, data) ;
loadingLiveData.setValue(false);
dataLiveData.setValue(data);
});
// in Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
viewModel.loadingLiveData.observe(this, (loading) -> {
if(loading) {
progressBar.setVisibility(View.VISIBLE);
} else {
progressBar.setVisibility(View.GONE);
}
});
viewModel.dataLiveData.observe(this, (data) -> {
populateData(data);
});
}
这个例子使用了一个单线程池,适合数据库写入(或序列化网络请求),但如果你想要数据库读取或多个请求的东西,你可以考虑以下执行器配置:
private static final Executor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(5, 128, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
Google 建议使用 Java 的并发框架或 Kotlin Coroutines。但是 Rxjava 最终具有比 java 并发性更多的灵活性和特性,因此获得了相当多的人气。
Android 在 Android 11 中弃用了 AsyncTask API 以摆脱一部分问题。
那么,现在怎么样了?
- 线程
- 执行者
- RxJava
- 可听期货
- 协程
为什么要协程?
Coroutines are the Kotlin way to do asynchronous programming. Compiler
support is stable since Kotlin 1.3, together with a
kotlinx.coroutines
library -
- 结构化并发
- 非阻塞,顺序代码
- 取消传播
- 自然异常处理
按照Android documentation AsyncTask
was deprecated in API level 30 and it is suggested to use the standard java.util.concurrent or Kotlin concurrency utilities代替。
使用后者可以非常简单地实现:
在 CoroutineScope
上创建通用扩展函数:
fun <R> CoroutineScope.executeAsyncTask(
onPreExecute: () -> Unit,
doInBackground: () -> R,
onPostExecute: (R) -> Unit
) = launch {
onPreExecute() // runs in Main Thread
val result = withContext(Dispatchers.IO) {
doInBackground() // runs in background thread without blocking the Main Thread
}
onPostExecute(result) // runs in Main Thread
}
将函数与具有 Dispatchers.Main
上下文的任何 CoroutineScope
一起使用:
-
class MyViewModel : ViewModel() {
fun someFun() {
viewModelScope.executeAsyncTask(onPreExecute = {
// ... runs in Main Thread
}, doInBackground = {
// ... runs in Worker(Background) Thread
"Result" // send data to "onPostExecute"
}, onPostExecute = {
// runs in Main Thread
// ... here "it" is the data returned from "doInBackground"
})
}
}
在Activity
或Fragment
中:
lifecycleScope.executeAsyncTask(onPreExecute = {
// ... runs in Main Thread
}, doInBackground = {
// ... runs in Worker(Background) Thread
"Result" // send data to "onPostExecute"
}, onPostExecute = {
// runs in Main Thread
// ... here "it" is the data returned from "doInBackground"
})
要使用 viewModelScope
或 lifecycleScope
将下一行添加到应用程序的 build.gradle 文件的依赖项中:
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
撰写本文时 final LIFECYCLE_VERSION = "2.3.0-alpha05"
更新:
我们也可以使用onProgressUpdate
函数实现进度更新:
fun <P, R> CoroutineScope.executeAsyncTask(
onPreExecute: () -> Unit,
doInBackground: suspend (suspend (P) -> Unit) -> R,
onPostExecute: (R) -> Unit,
onProgressUpdate: (P) -> Unit
) = launch {
onPreExecute()
val result = withContext(Dispatchers.IO) {
doInBackground {
withContext(Dispatchers.Main) { onProgressUpdate(it) }
}
}
onPostExecute(result)
}
使用任何 CoroutineScope
(viewModelScope
/lifecycleScope
,见上面的实现)和 Dispatchers.Main
我们可以调用它的上下文:
someScope.executeAsyncTask(
onPreExecute = {
// ... runs in Main Thread
}, doInBackground = { publishProgress: suspend (progress: Int) -> Unit ->
// ... runs in Background Thread
// simulate progress update
publishProgress(50) // call `publishProgress` to update progress, `onProgressUpdate` will be called
delay(1000)
publishProgress(100)
"Result" // send data to "onPostExecute"
}, onPostExecute = {
// runs in Main Thread
// ... here "it" is a data returned from "doInBackground"
}, onProgressUpdate = {
// runs in Main Thread
// ... here "it" contains progress
}
)
在这里,我使用协程为 AsyncTask 创建了一个替代方案,它可以与 AsyncTask 一样使用,而无需更改项目中的很多代码库。
创建一个新的抽象class AsyncTaskCoroutine 接受输入参数和输出参数数据类型of-course这些参数是可选的:)
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
abstract class AsyncTaskCoroutine<I, O> {
var result: O? = null
//private var result: O
open fun onPreExecute() {}
open fun onPostExecute(result: O?) {}
abstract fun doInBackground(vararg params: I): O
fun <T> execute(vararg input: I) {
GlobalScope.launch(Dispatchers.Main) {
onPreExecute()
callAsync(*input)
}
}
private suspend fun callAsync(vararg input: I) {
GlobalScope.async(Dispatchers.IO) {
result = doInBackground(*input)
}.await()
GlobalScope.launch(Dispatchers.Main) {
onPostExecute(result)
}
}
}
2。在 Activity 中,现在将其与旧的 AsycnTask 一样使用
new AsyncTaskCoroutine() {
@Override
public Object doInBackground(Object[] params) {
return null;
}
@Override
public void onPostExecute(@Nullable Object result) {
}
@Override
public void onPreExecute() {
}
}.execute();
万一你需要发送传递参数
new AsyncTaskCoroutine<Integer, Boolean>() {
@Override
public Boolean doInBackground(Integer... params) {
return null;
}
@Override
public void onPostExecute(@Nullable Boolean result) {
}
@Override
public void onPreExecute() {
}
}.execute();
我的自定义替换:https://github.com/JohnyDaDeveloper/AndroidAsync
它仅在应用 运行(更具体地说是计划任务的 activity 时有效),但它能够在后台任务完成后更新 UI
编辑:我的 AsyncTask 不再需要 Activiy 才能运行。
最简单的替代方法之一是使用 Thread
new Thread(new Runnable() {
@Override
public void run() {
// do your stuff
runOnUiThread(new Runnable() {
public void run() {
// do onPostExecute stuff
}
});
}
}).start();
如果你的项目支持JAVA8,你可以使用lambda
:
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
您可以使用此自定义 class 作为 AsyncTask<> 的替代方案,这与 AsyncTask 相同,因此您无需为此付出额外的努力。
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TaskRunner {
private static final int CORE_THREADS = 3;
private static final long KEEP_ALIVE_SECONDS = 60L;
private static TaskRunner taskRunner = null;
private Handler handler = new Handler(Looper.getMainLooper());
private ThreadPoolExecutor executor;
private TaskRunner() {
executor = newThreadPoolExecutor();
}
public static TaskRunner getInstance() {
if (taskRunner == null) {
taskRunner = new TaskRunner();
}
return taskRunner;
}
public void shutdownService() {
if (executor != null) {
executor.shutdown();
}
}
public void execute(Runnable command) {
executor.execute(command);
}
public ExecutorService getExecutor() {
return executor;
}
public <R> void executeCallable(@NonNull Callable<R> callable, @NonNull OnCompletedCallback<R> callback) {
executor.execute(() -> {
R result = null;
try {
result = callable.call();
} catch (Exception e) {
e.printStackTrace(); // log this exception
} finally {
final R finalResult = result;
handler.post(() -> callback.onComplete(finalResult));
}
});
}
private ThreadPoolExecutor newThreadPoolExecutor() {
return new ThreadPoolExecutor(
CORE_THREADS,
Integer.MAX_VALUE,
KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS,
new SynchronousQueue<>()
);
}
public interface OnCompletedCallback<R> {
void onComplete(@Nullable R result);
}
}
如何使用?请按照以下示例进行操作。
使用 lambda 表达式
TaskRunner.getInstance().executeCallable(() -> 1, result -> {
});
TaskRunner.getInstance().execute(() -> {
});
没有 lambda 表达式
TaskRunner.getInstance().executeCallable(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 1;
}
}, new TaskRunner.OnCompletedCallback<Integer>() {
@Override
public void onComplete(@Nullable Integer result) {
}
});
TaskRunner.getInstance().execute(new Runnable() {
@Override
public void run() {
}
});
注意:不要忘记关闭执行程序服务
TaskRunner.getInstance().shutdownService();
就把整个class换成这个Thread,放在一个方法里传变量
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
并在 Fragment 中将上下文添加到 runOnUiThread()
方法:
new Thread(() -> {
// do background stuff here
context.runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
您可以直接使用 java.util.concurrent
包中的 Executors
。
我也搜索了一下,在这个 Android Async API is Deprecated post.
中找到了解决方案
不幸的是,post 使用的是 Kotlin,但经过一些努力我将其转换为 Java。所以这是解决方案。
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(new Runnable() {
@Override
public void run() {
//Background work here
handler.post(new Runnable() {
@Override
public void run() {
//UI Thread work here
}
});
}
});
很简单吧?如果您在项目中使用 Java 8,则可以进一步简化它。
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
//Background work here
handler.post(() -> {
//UI Thread work here
});
});
虽然在代码的简洁性上还是比不上kotlin,但是比之前的java版本要好。
希望这对您有所帮助。谢谢
使用此 class 在后台线程中执行后台任务此 class 适用于所有 android API 版本包括 Android 11 此代码也与 AsyncTask 和 doInBackground 和 onPostExecute 方法相同
public abstract class BackgroundTask {
private Activity activity;
public BackgroundTask(Activity activity) {
this.activity = activity;
}
private void startBackground() {
new Thread(new Runnable() {
public void run() {
doInBackground();
activity.runOnUiThread(new Runnable() {
public void run() {
onPostExecute();
}
});
}
}).start();
}
public void execute(){
startBackground();
}
public abstract void doInBackground();
public abstract void onPostExecute();
}
复制上面的class后,你就可以用这个了:
new BackgroundTask(MainActivity.this) {
@Override
public void doInBackground() {
//put you background code
//same like doingBackground
//Background Thread
}
@Override
public void onPostExecute() {
//hear is result part same
//same like post execute
//UI Thread(update your UI widget)
}
}.execute();
HandlerThread 可以替代 AsyncTask。它们是 long-运行ning 线程。 HandlerThread 的示例如下:
您可以创建两个处理程序对象。其中之一将用于将消息从 workerThread 发送到 UI Thread.
Handler uiHandler,workerHandler;
Message msg;
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler.Callback callback=new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
// handle messages sent from working thread (like updating UI)...
return true;
}
}
uiHandler=new Handler(callback);
workerHandler = new Handler(handlerThread.getLooper());
workerHandler.post(new Runnable(){
// Perform required task
uiHandler.sendMessage(msg); // this message will be sent to and handled by UI Thread
});
此外,请记住 HandlerThreads 运行 在 activity 的生命周期之外,因此需要正确清理它们,否则会出现线程泄漏。您可以在 Activity 的 onDestroy() 中使用 quit() 或 quitSafely() 方法来防止线程泄漏。
您可以根据需要迁移到下一个方法
- 线程 + 处理程序
- 执行者
- 未来
- 意图服务
- JobScheduler
- RxJava
- 协程 (Kotlin)
[Android async variants]
我实际上写了两个关于它的 Medium 故事:
第一个是 Java 和 Runnable 的解决方法,第二个是 Kotlin 和协程解决方案。
当然,两者都带有代码示例。
这是我的代码
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public abstract class AsyncTaskRunner<T> {
private ExecutorService executorService = null;
private Set<Callable<T>> tasks = new HashSet<>();
public AsyncTaskRunner() {
this.executorService = Executors.newSingleThreadExecutor();
}
public AsyncTaskRunner(int threadNum) {
this.executorService = Executors.newFixedThreadPool(threadNum);
}
public void addTask(Callable<T> task) {
tasks.add(task);
}
public void execute() {
try {
List<Future<T>> features = executorService.invokeAll(tasks);
List<T> results = new ArrayList<>();
for (Future<T> feature : features) {
results.add(feature.get());
}
this.onPostExecute(results);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
this.onCancelled();
} finally {
executorService.shutdown();
}
}
protected abstract void onPostExecute(List<T> results);
protected void onCancelled() {
// stub
}
}
和用法示例。
扩展 AsyncTaskRunner
class,
class AsyncCalc extends AsyncTaskRunner<Integer> {
public void addRequest(final Integer int1, final Integer int2) {
this.addTask(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// Do something in background
return int1 + int2;
}
});
}
@Override
protected void onPostExecute(List<Integer> results) {
for (Integer answer: results) {
Log.d("AsyncCalc", answer.toString());
}
}
}
那就用吧!
AsyncCalc calc = new AsyncCalc();
calc.addRequest(1, 2);
calc.addRequest(2, 3);
calc.addRequest(3, 4);
calc.execute();
接受的答案很好。但...
我没有看到 cancel() 方法实现
所以我的实现有可能取消 运行ning 任务(模拟取消)如下。
在任务中断的情况下,需要取消而不是 运行 postExecute() 方法。
public abstract class AsyncTaskExecutor<Params> {
public static final String TAG = "AsyncTaskRunner";
private static final Executor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(5, 128, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
private final Handler mHandler = new Handler(Looper.getMainLooper());
private boolean mIsInterrupted = false;
protected void onPreExecute(){}
protected abstract Void doInBackground(Params... params);
protected void onPostExecute(){}
protected void onCancelled() {}
@SafeVarargs
public final void executeAsync(Params... params) {
THREAD_POOL_EXECUTOR.execute(() -> {
try {
checkInterrupted();
mHandler.post(this::onPreExecute);
checkInterrupted();
doInBackground(params);
checkInterrupted();
mHandler.post(this::onPostExecute);
} catch (InterruptedException ex) {
mHandler.post(this::onCancelled);
} catch (Exception ex) {
Log.e(TAG, "executeAsync: " + ex.getMessage() + "\n" + Debug.getStackTrace(ex));
}
});
}
private void checkInterrupted() throws InterruptedException {
if (isInterrupted()){
throw new InterruptedException();
}
}
public void cancel(boolean mayInterruptIfRunning){
setInterrupted(mayInterruptIfRunning);
}
public boolean isInterrupted() {
return mIsInterrupted;
}
public void setInterrupted(boolean interrupted) {
mIsInterrupted = interrupted;
}
}
使用此 class 的示例:
public class MySearchTask extends AsyncTaskExecutor<String> {
public MySearchTask(){
}
@Override
protected Void doInBackground(String... params) {
// Your long running task
return null;
}
@Override
protected void onPostExecute() {
// update UI on task completed
}
@Override
protected void onCancelled() {
// update UI on task cancelled
}
}
MySearchTask searchTask = new MySearchTask();
searchTask.executeAsync("Test");
在这里,我还使用抽象 class 创建了 AsyncTask 的替代方案,它可以直接复制为 class。
/app/src/main/java/../AsyncTasks.java
public abstract class AsyncTasks {
private final ExecutorService executors;
public AsyncTasks() {
this.executors = Executors.newSingleThreadExecutor();
}
private void startBackground() {
onPreExecute();
executors.execute(new Runnable() {
@Override
public void run() {
doInBackground();
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
onPostExecute();
}
});
}
});
}
public void execute() {
startBackground();
}
public void shutdown() {
executors.shutdown();
}
public boolean isShutdown() {
return executors.isShutdown();
}
public abstract void onPreExecute();
public abstract void doInBackground();
public abstract void onPostExecute();
}
上面的实现/使用class
new AsyncTasks() {
@Override
public void onPreExecute() {
// before execution
}
@Override
public void doInBackground() {
// background task here
}
@Override
public void onPostExecute() {
// Ui task here
}
}.execute();
Google 在 Android 11 中弃用 Android AsyncTask API 并建议改用 java.util.concurrent
。你可以查看提交 here
*
* @deprecated Use the standard <code>java.util.concurrent</code> or
* <a href="https://developer.android.com/topic/libraries/architecture/coroutines">
* Kotlin concurrency utilities</a> instead.
*/
@Deprecated
public abstract class AsyncTask<Params, Progress, Result> {
如果您在 Android 中维护带有异步任务的旧代码库,您将来可能不得不更改它。我的问题是应该使用 java.util.concurrent
正确替换下面显示的代码片段。它是 Activity 的静态内部 class。我正在寻找可以与 minSdkVersion 16
private static class LongRunningTask extends AsyncTask<String, Void, MyPojo> {
private static final String TAG = MyActivity.LongRunningTask.class.getSimpleName();
private WeakReference<MyActivity> activityReference;
LongRunningTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
@Override
protected MyPojo doInBackground(String... params) {
// Some long running task
}
@Override
protected void onPostExecute(MyPojo data) {
MyActivity activity = activityReference.get();
activity.progressBar.setVisibility(View.GONE);
populateData(activity, data) ;
}
}
private WeakReference<MyActivity> activityReference;
很高兴它已被弃用,because the WeakReference<Context>
was always a hack, and not a proper solution。
现在人们将有机会净化他们的代码。
AsyncTask<String, Void, MyPojo>
基于这段代码,其实不需要Progress
,还有一个String
输入+MyPojo
输出。
这实际上很容易完成,无需使用任何 AsyncTask。
public class TaskRunner {
private final Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements
private final Handler handler = new Handler(Looper.getMainLooper());
public interface Callback<R> {
void onComplete(R result);
}
public <R> void executeAsync(Callable<R> callable, Callback<R> callback) {
executor.execute(() -> {
final R result = callable.call();
handler.post(() -> {
callback.onComplete(result);
});
});
}
}
如何传入String?像这样:
class LongRunningTask implements Callable<MyPojo> {
private final String input;
public LongRunningTask(String input) {
this.input = input;
}
@Override
public MyPojo call() {
// Some long running task
return myPojo;
}
}
和
// in ViewModel
taskRunner.executeAsync(new LongRunningTask(input), (data) -> {
// MyActivity activity = activityReference.get();
// activity.progressBar.setVisibility(View.GONE);
// populateData(activity, data) ;
loadingLiveData.setValue(false);
dataLiveData.setValue(data);
});
// in Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
viewModel.loadingLiveData.observe(this, (loading) -> {
if(loading) {
progressBar.setVisibility(View.VISIBLE);
} else {
progressBar.setVisibility(View.GONE);
}
});
viewModel.dataLiveData.observe(this, (data) -> {
populateData(data);
});
}
这个例子使用了一个单线程池,适合数据库写入(或序列化网络请求),但如果你想要数据库读取或多个请求的东西,你可以考虑以下执行器配置:
private static final Executor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(5, 128, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
Google 建议使用 Java 的并发框架或 Kotlin Coroutines。但是 Rxjava 最终具有比 java 并发性更多的灵活性和特性,因此获得了相当多的人气。
Android 在 Android 11 中弃用了 AsyncTask API 以摆脱一部分问题。
那么,现在怎么样了?
- 线程
- 执行者
- RxJava
- 可听期货
- 协程
为什么要协程?
Coroutines are the Kotlin way to do asynchronous programming. Compiler support is stable since Kotlin 1.3, together with a
kotlinx.coroutines
library -
- 结构化并发
- 非阻塞,顺序代码
- 取消传播
- 自然异常处理
按照Android documentation AsyncTask
was deprecated in API level 30 and it is suggested to use the standard java.util.concurrent or Kotlin concurrency utilities代替。
使用后者可以非常简单地实现:
在
CoroutineScope
上创建通用扩展函数:fun <R> CoroutineScope.executeAsyncTask( onPreExecute: () -> Unit, doInBackground: () -> R, onPostExecute: (R) -> Unit ) = launch { onPreExecute() // runs in Main Thread val result = withContext(Dispatchers.IO) { doInBackground() // runs in background thread without blocking the Main Thread } onPostExecute(result) // runs in Main Thread }
将函数与具有
Dispatchers.Main
上下文的任何CoroutineScope
一起使用:-
class MyViewModel : ViewModel() { fun someFun() { viewModelScope.executeAsyncTask(onPreExecute = { // ... runs in Main Thread }, doInBackground = { // ... runs in Worker(Background) Thread "Result" // send data to "onPostExecute" }, onPostExecute = { // runs in Main Thread // ... here "it" is the data returned from "doInBackground" }) } }
在
Activity
或Fragment
中:lifecycleScope.executeAsyncTask(onPreExecute = { // ... runs in Main Thread }, doInBackground = { // ... runs in Worker(Background) Thread "Result" // send data to "onPostExecute" }, onPostExecute = { // runs in Main Thread // ... here "it" is the data returned from "doInBackground" })
要使用
viewModelScope
或lifecycleScope
将下一行添加到应用程序的 build.gradle 文件的依赖项中:implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
撰写本文时
final LIFECYCLE_VERSION = "2.3.0-alpha05"
-
更新:
我们也可以使用onProgressUpdate
函数实现进度更新:
fun <P, R> CoroutineScope.executeAsyncTask(
onPreExecute: () -> Unit,
doInBackground: suspend (suspend (P) -> Unit) -> R,
onPostExecute: (R) -> Unit,
onProgressUpdate: (P) -> Unit
) = launch {
onPreExecute()
val result = withContext(Dispatchers.IO) {
doInBackground {
withContext(Dispatchers.Main) { onProgressUpdate(it) }
}
}
onPostExecute(result)
}
使用任何 CoroutineScope
(viewModelScope
/lifecycleScope
,见上面的实现)和 Dispatchers.Main
我们可以调用它的上下文:
someScope.executeAsyncTask(
onPreExecute = {
// ... runs in Main Thread
}, doInBackground = { publishProgress: suspend (progress: Int) -> Unit ->
// ... runs in Background Thread
// simulate progress update
publishProgress(50) // call `publishProgress` to update progress, `onProgressUpdate` will be called
delay(1000)
publishProgress(100)
"Result" // send data to "onPostExecute"
}, onPostExecute = {
// runs in Main Thread
// ... here "it" is a data returned from "doInBackground"
}, onProgressUpdate = {
// runs in Main Thread
// ... here "it" contains progress
}
)
在这里,我使用协程为 AsyncTask 创建了一个替代方案,它可以与 AsyncTask 一样使用,而无需更改项目中的很多代码库。
创建一个新的抽象class AsyncTaskCoroutine 接受输入参数和输出参数数据类型of-course这些参数是可选的:)
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch abstract class AsyncTaskCoroutine<I, O> { var result: O? = null //private var result: O open fun onPreExecute() {} open fun onPostExecute(result: O?) {} abstract fun doInBackground(vararg params: I): O fun <T> execute(vararg input: I) { GlobalScope.launch(Dispatchers.Main) { onPreExecute() callAsync(*input) } } private suspend fun callAsync(vararg input: I) { GlobalScope.async(Dispatchers.IO) { result = doInBackground(*input) }.await() GlobalScope.launch(Dispatchers.Main) { onPostExecute(result) } } }
2。在 Activity 中,现在将其与旧的 AsycnTask 一样使用
new AsyncTaskCoroutine() {
@Override
public Object doInBackground(Object[] params) {
return null;
}
@Override
public void onPostExecute(@Nullable Object result) {
}
@Override
public void onPreExecute() {
}
}.execute();
万一你需要发送传递参数
new AsyncTaskCoroutine<Integer, Boolean>() { @Override public Boolean doInBackground(Integer... params) { return null; } @Override public void onPostExecute(@Nullable Boolean result) { } @Override public void onPreExecute() { } }.execute();
我的自定义替换:https://github.com/JohnyDaDeveloper/AndroidAsync
它仅在应用 运行(更具体地说是计划任务的 activity 时有效),但它能够在后台任务完成后更新 UI
编辑:我的 AsyncTask 不再需要 Activiy 才能运行。
最简单的替代方法之一是使用 Thread
new Thread(new Runnable() {
@Override
public void run() {
// do your stuff
runOnUiThread(new Runnable() {
public void run() {
// do onPostExecute stuff
}
});
}
}).start();
如果你的项目支持JAVA8,你可以使用lambda
:
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
您可以使用此自定义 class 作为 AsyncTask<> 的替代方案,这与 AsyncTask 相同,因此您无需为此付出额外的努力。
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class TaskRunner {
private static final int CORE_THREADS = 3;
private static final long KEEP_ALIVE_SECONDS = 60L;
private static TaskRunner taskRunner = null;
private Handler handler = new Handler(Looper.getMainLooper());
private ThreadPoolExecutor executor;
private TaskRunner() {
executor = newThreadPoolExecutor();
}
public static TaskRunner getInstance() {
if (taskRunner == null) {
taskRunner = new TaskRunner();
}
return taskRunner;
}
public void shutdownService() {
if (executor != null) {
executor.shutdown();
}
}
public void execute(Runnable command) {
executor.execute(command);
}
public ExecutorService getExecutor() {
return executor;
}
public <R> void executeCallable(@NonNull Callable<R> callable, @NonNull OnCompletedCallback<R> callback) {
executor.execute(() -> {
R result = null;
try {
result = callable.call();
} catch (Exception e) {
e.printStackTrace(); // log this exception
} finally {
final R finalResult = result;
handler.post(() -> callback.onComplete(finalResult));
}
});
}
private ThreadPoolExecutor newThreadPoolExecutor() {
return new ThreadPoolExecutor(
CORE_THREADS,
Integer.MAX_VALUE,
KEEP_ALIVE_SECONDS,
TimeUnit.SECONDS,
new SynchronousQueue<>()
);
}
public interface OnCompletedCallback<R> {
void onComplete(@Nullable R result);
}
}
如何使用?请按照以下示例进行操作。
使用 lambda 表达式
TaskRunner.getInstance().executeCallable(() -> 1, result -> {
});
TaskRunner.getInstance().execute(() -> {
});
没有 lambda 表达式
TaskRunner.getInstance().executeCallable(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 1;
}
}, new TaskRunner.OnCompletedCallback<Integer>() {
@Override
public void onComplete(@Nullable Integer result) {
}
});
TaskRunner.getInstance().execute(new Runnable() {
@Override
public void run() {
}
});
注意:不要忘记关闭执行程序服务
TaskRunner.getInstance().shutdownService();
就把整个class换成这个Thread,放在一个方法里传变量
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
并在 Fragment 中将上下文添加到 runOnUiThread()
方法:
new Thread(() -> {
// do background stuff here
context.runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
您可以直接使用 java.util.concurrent
包中的 Executors
。
我也搜索了一下,在这个 Android Async API is Deprecated post.
中找到了解决方案不幸的是,post 使用的是 Kotlin,但经过一些努力我将其转换为 Java。所以这是解决方案。
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(new Runnable() {
@Override
public void run() {
//Background work here
handler.post(new Runnable() {
@Override
public void run() {
//UI Thread work here
}
});
}
});
很简单吧?如果您在项目中使用 Java 8,则可以进一步简化它。
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
//Background work here
handler.post(() -> {
//UI Thread work here
});
});
虽然在代码的简洁性上还是比不上kotlin,但是比之前的java版本要好。
希望这对您有所帮助。谢谢
使用此 class 在后台线程中执行后台任务此 class 适用于所有 android API 版本包括 Android 11 此代码也与 AsyncTask 和 doInBackground 和 onPostExecute 方法相同
public abstract class BackgroundTask {
private Activity activity;
public BackgroundTask(Activity activity) {
this.activity = activity;
}
private void startBackground() {
new Thread(new Runnable() {
public void run() {
doInBackground();
activity.runOnUiThread(new Runnable() {
public void run() {
onPostExecute();
}
});
}
}).start();
}
public void execute(){
startBackground();
}
public abstract void doInBackground();
public abstract void onPostExecute();
}
复制上面的class后,你就可以用这个了:
new BackgroundTask(MainActivity.this) {
@Override
public void doInBackground() {
//put you background code
//same like doingBackground
//Background Thread
}
@Override
public void onPostExecute() {
//hear is result part same
//same like post execute
//UI Thread(update your UI widget)
}
}.execute();
HandlerThread 可以替代 AsyncTask。它们是 long-运行ning 线程。 HandlerThread 的示例如下:
您可以创建两个处理程序对象。其中之一将用于将消息从 workerThread 发送到 UI Thread.
Handler uiHandler,workerHandler;
Message msg;
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
Handler.Callback callback=new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
// handle messages sent from working thread (like updating UI)...
return true;
}
}
uiHandler=new Handler(callback);
workerHandler = new Handler(handlerThread.getLooper());
workerHandler.post(new Runnable(){
// Perform required task
uiHandler.sendMessage(msg); // this message will be sent to and handled by UI Thread
});
此外,请记住 HandlerThreads 运行 在 activity 的生命周期之外,因此需要正确清理它们,否则会出现线程泄漏。您可以在 Activity 的 onDestroy() 中使用 quit() 或 quitSafely() 方法来防止线程泄漏。
您可以根据需要迁移到下一个方法
- 线程 + 处理程序
- 执行者
- 未来
- 意图服务
- JobScheduler
- RxJava
- 协程 (Kotlin)
[Android async variants]
我实际上写了两个关于它的 Medium 故事:
第一个是 Java 和 Runnable 的解决方法,第二个是 Kotlin 和协程解决方案。 当然,两者都带有代码示例。
这是我的代码
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public abstract class AsyncTaskRunner<T> {
private ExecutorService executorService = null;
private Set<Callable<T>> tasks = new HashSet<>();
public AsyncTaskRunner() {
this.executorService = Executors.newSingleThreadExecutor();
}
public AsyncTaskRunner(int threadNum) {
this.executorService = Executors.newFixedThreadPool(threadNum);
}
public void addTask(Callable<T> task) {
tasks.add(task);
}
public void execute() {
try {
List<Future<T>> features = executorService.invokeAll(tasks);
List<T> results = new ArrayList<>();
for (Future<T> feature : features) {
results.add(feature.get());
}
this.onPostExecute(results);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
this.onCancelled();
} finally {
executorService.shutdown();
}
}
protected abstract void onPostExecute(List<T> results);
protected void onCancelled() {
// stub
}
}
和用法示例。
扩展 AsyncTaskRunner
class,
class AsyncCalc extends AsyncTaskRunner<Integer> {
public void addRequest(final Integer int1, final Integer int2) {
this.addTask(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// Do something in background
return int1 + int2;
}
});
}
@Override
protected void onPostExecute(List<Integer> results) {
for (Integer answer: results) {
Log.d("AsyncCalc", answer.toString());
}
}
}
那就用吧!
AsyncCalc calc = new AsyncCalc();
calc.addRequest(1, 2);
calc.addRequest(2, 3);
calc.addRequest(3, 4);
calc.execute();
接受的答案很好。但... 我没有看到 cancel() 方法实现
所以我的实现有可能取消 运行ning 任务(模拟取消)如下。 在任务中断的情况下,需要取消而不是 运行 postExecute() 方法。
public abstract class AsyncTaskExecutor<Params> {
public static final String TAG = "AsyncTaskRunner";
private static final Executor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(5, 128, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
private final Handler mHandler = new Handler(Looper.getMainLooper());
private boolean mIsInterrupted = false;
protected void onPreExecute(){}
protected abstract Void doInBackground(Params... params);
protected void onPostExecute(){}
protected void onCancelled() {}
@SafeVarargs
public final void executeAsync(Params... params) {
THREAD_POOL_EXECUTOR.execute(() -> {
try {
checkInterrupted();
mHandler.post(this::onPreExecute);
checkInterrupted();
doInBackground(params);
checkInterrupted();
mHandler.post(this::onPostExecute);
} catch (InterruptedException ex) {
mHandler.post(this::onCancelled);
} catch (Exception ex) {
Log.e(TAG, "executeAsync: " + ex.getMessage() + "\n" + Debug.getStackTrace(ex));
}
});
}
private void checkInterrupted() throws InterruptedException {
if (isInterrupted()){
throw new InterruptedException();
}
}
public void cancel(boolean mayInterruptIfRunning){
setInterrupted(mayInterruptIfRunning);
}
public boolean isInterrupted() {
return mIsInterrupted;
}
public void setInterrupted(boolean interrupted) {
mIsInterrupted = interrupted;
}
}
使用此 class 的示例:
public class MySearchTask extends AsyncTaskExecutor<String> {
public MySearchTask(){
}
@Override
protected Void doInBackground(String... params) {
// Your long running task
return null;
}
@Override
protected void onPostExecute() {
// update UI on task completed
}
@Override
protected void onCancelled() {
// update UI on task cancelled
}
}
MySearchTask searchTask = new MySearchTask();
searchTask.executeAsync("Test");
在这里,我还使用抽象 class 创建了 AsyncTask 的替代方案,它可以直接复制为 class。
/app/src/main/java/../AsyncTasks.java
public abstract class AsyncTasks {
private final ExecutorService executors;
public AsyncTasks() {
this.executors = Executors.newSingleThreadExecutor();
}
private void startBackground() {
onPreExecute();
executors.execute(new Runnable() {
@Override
public void run() {
doInBackground();
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
onPostExecute();
}
});
}
});
}
public void execute() {
startBackground();
}
public void shutdown() {
executors.shutdown();
}
public boolean isShutdown() {
return executors.isShutdown();
}
public abstract void onPreExecute();
public abstract void doInBackground();
public abstract void onPostExecute();
}
上面的实现/使用class
new AsyncTasks() {
@Override
public void onPreExecute() {
// before execution
}
@Override
public void doInBackground() {
// background task here
}
@Override
public void onPostExecute() {
// Ui task here
}
}.execute();