Java Android 11中不推荐使用Android AsyncTask API。有哪些替代方案?
谷歌反对Android 11中的Android AsyncTaskAPI,并建议改用Java Android 11中不推荐使用Android AsyncTask API。有哪些替代方案?,java,android,kotlin,kotlin-coroutines,Java,Android,Kotlin,Kotlin Coroutines,谷歌反对Android 11中的Android AsyncTaskAPI,并建议改用java.util.concurrent。您可以检查提交 如果您在Android中使用异步任务维护一个较旧的代码库,那么将来可能需要对其进行更改。我的问题是,使用java.util.concurrent正确替换下面显示的代码段应该是什么。它是活动的静态内部类。我正在寻找能与minSdkVersion 16一起工作的东西 private static class LongRunningTask extends As
java.util.concurrent
。您可以检查提交
如果您在Android中使用异步任务维护一个较旧的代码库,那么将来可能需要对其进行更改。我的问题是,使用java.util.concurrent
正确替换下面显示的代码段应该是什么。它是活动的静态内部类。我正在寻找能与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) ;
}
}
私有静态类LongRunningTask扩展了AsyncTask{
私有静态最终字符串标记=MyActivity.LongRunningTask.class.getSimpleName();
私人财富参考活动参考;
LongRunningTask(MyActivity上下文){
activityReference=新的WeakReference(上下文);
}
@凌驾
受保护的MyPojo doInBackground(字符串…参数){
//一些长时间运行的任务
}
@凌驾
受保护的void onPostExecute(MyPojo数据){
MyActivity=activityReference.get();
activity.progressBar.setVisibility(View.GONE);
填充数据(活动、数据);
}
}
如何传入字符串?像这样:
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;
}
}
此示例使用了一个单线程池,它对DB编写(或序列化的网络请求)很有好处,但是如果您希望获得DB读取或多个请求的某些内容,可以考虑以下执行器配置:
private static final Executor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(5, 128, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
私有静态最终执行器线程\u池\u执行器=
新的线程池执行器(5128,1,
TimeUnit.SECONDS,新的LinkedBlockingQueue());
谷歌建议使用Java的并发框架或Kotlin协程。但是Rxjava最终拥有了比java并发更大的灵活性和功能,因此获得了相当大的普及。Android不推荐Android 11中的AsyncTask API,以摆脱一开始的部分问题
那么,现在是什么?
- 线程
- 执行者
- RxJava
- 可倾听的未来
- 根据
AsyncTask
,协同程序在API级别30中被弃用,建议使用标准java.util.concurrent或
使用后者可以非常简单地实现:
- 在
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
}
- 在
活动
或片段
中:
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\u 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)
}
在这里,我使用协程为AsyncTask创建了一个替代方案,该方案可以与AsyncTask一样使用,而无需更改项目中的许多代码库
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
//Background work here
handler.post(() -> {
//UI Thread work here
});
});
创建一个新的抽象类AsyncTaskCorroutine,它接受输入参数和输出参数数据类型。当然,这些参数是可选的:)
如果您需要发送pass参数
new AsyncTaskCoroutine<Integer, Boolean>() {
@Override
public Boolean doInBackground(Integer... params) {
return null;
}
@Override
public void onPostExecute(@Nullable Boolean result) {
}
@Override
public void onPreExecute() {
}
}.execute();
new AsyncTaskCoroutine(){
@凌驾
公共布尔doInBackground(整数…参数){
返回null;
}
@凌驾
public void onPostExecute(@Nullable Boolean result){
}
@凌驾
公共无效onPreExecute(){
}
}.execute();
我的自定义替换:
它仅在应用程序正在运行时(更具体地说是安排任务的活动)起作用,但它能够在后台任务完成后更新UI
编辑:我的异步任务不再需要活动才能运行。最简单的替代方法之一是使用线程
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();
您可以使用此自定义类作为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(() -> {
});
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() {
}
});
只需用这个线程替换整个类,并将其放入一个传递变量的方法中
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
在片段中,将上下文添加到runOnUiThread()
methode:
new Thread(() -> {
// do background stuff here
context.runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
您可以直接使用java.util.concurrent
包中的执行器
我也搜索了一下,在这篇文章中找到了一个解决方案
不幸的是,这篇文章使用的是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
}
});
}
});
很简单吧?如果您在项目中使用Java8,则可以将其简化一点
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
//Background work here
handler.post(() -> {
//UI Thread work here
});
});
尽管如此,它无法在代码简洁性方面击败kotlin,但它比以前的java版本要好
希望这对你有帮助。谢谢使用该类在后台线程中执行后台任务该类适用于包括android 11在内的所有android API版本而且该代码与异步任务和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();
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在活动的生命周期之外运行,因此需要正确清理它们,否则会出现线程泄漏。您可以在活动的onDestroy()中使用quit()或quitsafety()方法来防止线程泄漏。您可以根据需要迁移到下一个方法
- 线程+处理程序
- 执行人
- 未来
- 意向服务
- 乔
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();
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
new Thread(() -> {
// do background stuff here
context.runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
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
}
});
}
});
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
//Background work here
handler.post(() -> {
//UI Thread work here
});
});
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();
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
});