Zee*_*han 120 java android kotlin kotlin-coroutines
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> {
Run Code Online (Sandbox Code Playgroud)
如果您在 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) ;
}
}
Run Code Online (Sandbox Code Playgroud)
Epi*_*rce 87
Run Code Online (Sandbox Code Playgroud)private WeakReference<MyActivity> activityReference;
很好,它已被弃用,因为WeakReference<Context>
它总是一个 hack,而不是一个适当的解决方案。
现在人们将有机会清理他们的代码。
Run Code Online (Sandbox Code Playgroud)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);
});
});
}
}
Run Code Online (Sandbox Code Playgroud)
如何传入字符串?像这样:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
和
// 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);
});
}
Run Code Online (Sandbox Code Playgroud)
这个例子使用了一个单线程池,它有利于数据库写入(或序列化网络请求),但如果你想要一些用于数据库读取或多个请求的东西,你可以考虑以下 Executor 配置:
private static final Executor THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(5, 128, 1,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
Run Code Online (Sandbox Code Playgroud)
Kas*_*han 52
您可以直接使用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
}
});
}
});
Run Code Online (Sandbox Code Playgroud)
很简单吧?如果您在项目中使用 Java8,则可以稍微简化一下。
ExecutorService executor = Executors.newSingleThreadExecutor();
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
//Background work here
handler.post(() -> {
//UI Thread work here
});
});
Run Code Online (Sandbox Code Playgroud)
尽管如此,它仍然无法打败 kotlin 代码的简洁性,但比以前的 java 版本要好。
希望这会帮助你。谢谢你
may*_*513 31
最简单的替代方法之一是使用 Thread
new Thread(new Runnable() {
@Override
public void run() {
// do your stuff
runOnUiThread(new Runnable() {
public void run() {
// do onPostExecute stuff
}
});
}
}).start();
Run Code Online (Sandbox Code Playgroud)
如果您的项目支持 JAVA 8,则可以使用 lambda
new Thread(() -> {
// do background stuff here
runOnUiThread(()->{
// OnPostExecute stuff here
});
}).start();
Run Code Online (Sandbox Code Playgroud)
Ser*_*gey 20
根据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
}
Run Code Online (Sandbox Code Playgroud)
将该函数与 any 一起使用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"
})
}
}
Run Code Online (Sandbox Code Playgroud)
在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"
})
Run Code Online (Sandbox Code Playgroud)
要在应用程序的build.gradle文件的依赖项中使用viewModelScope
或lifecycleScope
添加下一行:
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION" // for viewModelScope
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$LIFECYCLE_VERSION" // for lifecycleScope
Run Code Online (Sandbox Code Playgroud)
在撰写本文时 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)
}
Run Code Online (Sandbox Code Playgroud)
使用 any CoroutineScope
(见上面的实现)我们可以调用它:
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
}
)
Run Code Online (Sandbox Code Playgroud)
mil*_*dia 10
使用此类在后台线程中执行后台任务此类适用于包括 Android 11 在内的所有 android API 版本,此代码与使用doInBackground和onPostExecute方法的AsyncTask相同
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();
}
Run Code Online (Sandbox Code Playgroud)
复制上面的类后,您可以使用它:
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();
Run Code Online (Sandbox Code Playgroud)
小智 6
在这里,我使用协程为 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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
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();
Run Code Online (Sandbox Code Playgroud)
InCase 如果您需要发送传递参数
new AsyncTaskCoroutine<Integer, Boolean>() {
@Override
public Boolean doInBackground(Integer... params) {
return null;
}
@Override
public void onPostExecute(@Nullable Boolean result) {
}
@Override
public void onPreExecute() {
}
}.execute();
Run Code Online (Sandbox Code Playgroud)
Android在 Android 11 中弃用了AsyncTask API,以解决一些问题。
协程是 Kotlin 进行异步编程的方式。自 Kotlin 1.3 起,编译器支持稳定,并带有一个
kotlinx.coroutines
库 -
接受的答案很好。但是...我没有看到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;
}
}
Run Code Online (Sandbox Code Playgroud)
使用此类的示例:
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");
Run Code Online (Sandbox Code Playgroud)
AsyncTask
类似乎不会很快被删除,但我们只是简单地取消了它的弃用,因为:
AsyncTask
.只需将以下文件添加到您的项目中,然后搜索“ android.os.AsyncTask
”导入,并将所有内容重新添加到您为所述文件选择的包中。
您可能已经知道,这没什么大不了的,而且基本上是众所周知的AndroidX
图书馆一直在做的事情。
获取AsyncTask.java
文件: https://gist.github.com/top-master/0efddec3e2c35d77e30331e8c3bc725c
归档时间: |
|
查看次数: |
87403 次 |
最近记录: |