![](/img/trans.png)
[英]Android AsyncTask API deprecating in Android 11, using Executor as alternative
[英]The AsyncTask API is deprecated in Android 11. What are the alternatives?
谷歌在 Android 11 中棄用了 Android AsyncTask API,並建議改用java.util.concurrent
。 你可以在這里查看提交
*
* @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 的靜態內部類。 我正在尋找適用於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) ;
}
}
您可以直接使用java.util.concurrent
包中的Executors
。
我還搜索了它,並在這個Android Async API is Deprecated帖子中找到了解決方案。
不幸的是,該帖子使用的是 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 版本要好。
希望這會幫助你。 謝謝你
private WeakReference<MyActivity> activityReference;
很好的擺脫它已被棄用, 因為WeakReference<Context>
總是一個黑客,而不是一個適當的解決方案。
現在人們將有機會凈化他們的代碼。
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);
});
});
}
}
如何傳入字符串? 像這樣:
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>());
最簡單的替代方法之一是使用Thread
new Thread(new Runnable() {
@Override
public void run() {
// do your stuff
runOnUiThread(new Runnable() {
public void run() {
// do onPostExecute stuff
}
});
}
}).start();
如果你的項目支持JAVA 8 ,你可以使用lambda
:
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
根據Android 文檔, AsyncTask
在API 級別 30中被棄用,建議改用標准的 java.util.concurrent 或Kotlin 並發實用程序。
使用后者可以非常簡單地實現:
在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
一起使用:
在ViewModel
中:
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
}
)
使用此類在后台線程中執行后台任務此類適用於所有 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();
}
復制上面的類后,你就可以使用它了:
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();
Android 在 Android 11 中棄用了AsyncTask API,以擺脫一開始的一些問題。
協程是 Kotlin 進行異步編程的方式。 自 Kotlin 1.3 以來編譯器支持穩定,連同
kotlinx.coroutines
庫 -
在這里,我使用協程為 AsyncTask 創建了一個替代方案,它可以與 AsyncTask 一樣使用,而無需更改項目中的太多代碼庫。
創建一個新的抽象類 AsyncTaskCoroutine,它接受輸入參數和輸出參數數據類型——當然這些參數是可選的:)
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();
Google 建議使用 Java 的並發框架或 Kotlin Coroutines。 但是 Rxjava 最終比 Java 並發具有更多的靈活性和特性,因此獲得了相當大的普及。
我實際上寫了兩個關於它的 Medium 故事:
第一個是使用 Java 和 Runnable 的變通方法,第二個是 Kotlin 和協程解決方案。 當然,兩者都有代碼示例。
在這里,我還使用抽象類為 AsyncTask 創建了一個替代方案,它可以作為一個類進行復制。
/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();
}
上述類的實現/使用
new AsyncTasks() {
@Override
public void onPreExecute() {
// before execution
}
@Override
public void doInBackground() {
// background task here
}
@Override
public void onPostExecute() {
// Ui task here
}
}.execute();
我的自定義替換: https ://github.com/JohnyDaDeveloper/AndroidAsync
它僅在應用程序運行時起作用(更具體地說是計划任務的活動),但它能夠在后台任務完成后更新 UI
編輯:我的 AsyncTask 不再需要 Activiy 才能運行。
把整個類換成這個Thread,放在一個方法里傳遞變量就行了
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
並在 Fragment 中將 Context 添加到runOnUiThread()
方法中:
new Thread(() -> {
// do background stuff here
context.runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
接受的答案很好。 但是...我沒有看到 cancel() 方法的實現
所以我有可能取消正在運行的任務(模擬取消)的實現如下。 在任務中斷的情況下,需要取消才能不運行 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;
}
}
使用此類的示例:
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");
您可以使用此自定義類作為 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();
Google 正在棄用 Android 11 中的 Android AsyncTask API 並建議使用java.util.concurrent
。 你可以在這里查看提交
*
* @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的static內部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) ;
}
}
HandlerThread可以用作AsyncTask的替代品。 它們是長時間運行的線程。 HandlerThread 的一個例子如下:
您可以創建兩個處理程序對象。 其中之一將用於將消息從 workerThread 發送到 UI 線程。
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 的 onDestroy() 中使用 quit() 或 quitSafely() 方法來防止線程泄漏。
這是我的代碼
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 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();
AsyncTask此類在 API 級別 30 中已棄用。請改用標准的 java.util.concurrent 或 Kotlin 並發實用程序。
您需要使用Handler
或協程而不是AsyncTask
。
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
// Your Code
}
}, 3000);
Handler(Looper.getMainLooper()).postDelayed({
// Your Code
}, 3000)
我的答案與其他答案相似,但更容易閱讀 imo。
這是類:
public class Async {
private static final ExecutorService executorService = Executors.newCachedThreadPool();
private static final Handler handler = new Handler(Looper.getMainLooper());
public static <T> void execute(Task<T> task) {
executorService.execute(() -> {
T t = task.doAsync();
handler.post(() -> {
task.doSync(t);
});
});
}
public interface Task<T> {
T doAsync();
void doSync(T t);
}
}
這是一個關於如何使用它的例子:
String url;
TextView responseCodeText;
Async.execute(new Async.Task<Integer>() {
@Override
public Integer doAsync() {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
return connection.getResponseCode();
} catch (IOException e) {
return null;
}
}
@Override
public void doSync(Integer responseCode) {
responseCodeText.setText("responseCode=" + responseCode);
}
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.