androidasynctaskapi不推荐使用有哪些替代方案?

vmpqdwk3  于 2021-07-11  发布在  Java
关注(0)|答案(14)|浏览(453)

谷歌不赞成android11中的androidasynctaskapi,并建议使用 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 . 它是活动的静态内部类。我在找一种适合我的 minSdkVersion 16 ```
private static class LongRunningTask extends AsyncTask<String, Void, MyPojo> {
private static final String TAG = MyActivity.LongRunningTask.class.getSimpleName();
private WeakReference 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) ;
    }     

}
mzaanser

mzaanser1#

android弃用了android11中的asynctask api来解决一部分问题。

那么,现在怎么办?

线程
执行者
rxjava公司
可上市期货
合作?

为什么要合作?

协同程序是kotlin进行异步编程的方式。自从kotlin1.3和 kotlinx.coroutines 图书馆-
结构化并发
非阻塞顺序码
对消传播
自然异常处理

juud5qan

juud5qan2#

google建议使用java的并发框架或kotlin协程。但是rxjava最终拥有了比java并发更大的灵活性和特性,因此获得了相当多的流行。

tyky79it

tyky79it3#

在这里,我为asynctask创建了一个替代方案,它使用协同程序,可以与asynctask一样使用,而无需更改项目中的大量代码库。
创建一个新的抽象类AsyncTaskCorroutine,它接受输入参数和输出参数数据类型当然这些参数是可选的:)

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 . 内部活动使用这个和你以前的asycontask一样

new AsyncTaskCoroutine() {
                @Override
                public Object doInBackground(Object[] params) {
                    return null;
                }

                @Override
                public void onPostExecute(@Nullable Object result) {

                }

                @Override
                public void onPreExecute() {

                }
            }.execute();

如果您需要发送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();
pprl5pva

pprl5pva4#

您可以使用此自定义类作为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() {

    }
});

注意:不要忘记关闭executors服务

TaskRunner.getInstance().shutdownService();
jutyujz0

jutyujz05#

使用这个类在后台线程中执行后台任务这个类适用于所有的android api版本包括android 11,这个代码与使用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();

}

复制完这个类之后就这样简单的使用

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();
hs1ihplo

hs1ihplo6#

您可以根据需要迁移到下一种方法
线程+处理程序
遗嘱执行人
未来
异步任务
内部服务
作业调度器
rxjava公司
协同程序(kotlin)
[android异步变体]

3pvhb19x

3pvhb19x7#

我的自定义替换:https://github.com/johnydadeveloper/androidasync
它只在应用程序运行时起作用(更具体地说是安排任务的活动),但它能够在后台任务完成后更新ui
编辑:我的asynctask不再需要活动才能运行。

ncgqoxb0

ncgqoxb08#

只需用这个线程替换整个类,并将其放入一个传递变量的方法中

new Thread(() -> {
            // do background stuff here
            runOnUiThread(()->{
                // OnPostExecute stuff here

            });
        }).start();

在片段中,将上下文添加到 runOnUiThread() 方法:

new Thread(() -> {
            // do background stuff here
            context.runOnUiThread(()->{
                // OnPostExecute stuff here
            });
        }).start();
7tofc5zh

7tofc5zh9#

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()或quitsaffely()方法来防止线程泄漏。

e5nqia27

e5nqia2710#

这是android.os.asynctask类的替代方法:

abstract class AsyncTask<Params, Progress, Result>(
        private val scope: LifecycleCoroutineScope,
        private var coroutineContext: CoroutineContext = Dispatchers.Default,
) {
    private var job: Job? = null
    private var result: Result? = null

    open fun onPreExecute() {}

    fun execute(params: Params) {
        job = scope.executeAsyncTask(
                onPreExecute = {
                    onPreExecute()
                },
                doInBackground = { publishProgress: suspend (progress: Progress) -> Unit ->
                    result = doInBackGround(publishProgress, params)
                    result
                },
                onPostExecute = {
                    onPostExecute(it)
                },
                onProgressUpdate = {
                    onProgressUpdate(it)
                },
                coroutineContext)
    }

    open fun onPostExecute(result: Result?) {}

    abstract suspend fun doInBackGround(publishProgress: suspend (progress: Progress) -> Unit, params: Params): Result?

    open fun onProgressUpdate(progress: Progress) {}

    fun cancel() = job?.let {
        if (it.isActive) {
            it.cancel()
            onCancelled(result)
        }
    }

    open fun onCancelled(result: Result?) {}

    private fun <Progress, Result> CoroutineScope.executeAsyncTask(
            onPreExecute: () -> Unit,
            doInBackground: suspend (suspend (Progress) -> Unit) -> Result,
            onPostExecute: (Result) -> Unit,
            onProgressUpdate: (Progress) -> Unit,
            coroutineContext: CoroutineContext,
    ) = launch(Dispatchers.Main) {
        onPreExecute()
        val result = withContext(coroutineContext) {
            doInBackground {
                withContext(Dispatchers.Main) { onProgressUpdate(it) }
            }
        }
        onPostExecute(result)
    }
}
rryofs0p

rryofs0p11#

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);
    }); 
}

此示例使用了一个单线程池,该池适用于db写入(或序列化的网络请求),但如果您需要db读取或多个请求,则可以考虑以下执行器配置:

private static final Executor THREAD_POOL_EXECUTOR =
        new ThreadPoolExecutor(5, 128, 1,
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
bkhjykvo

bkhjykvo12#

最简单的替代方法之一是使用 Thread ```
new Thread(new Runnable({
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();

5cg8jx4n

5cg8jx4n13#

根据android文档 AsyncTask 在api级别30中已弃用,建议改用标准java.util.concurrent或kotlin concurrency实用程序。
使用后者可以很简单地实现:
在上创建泛型扩展函数 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
 }

将函数与任何 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 (参见上面的实现)我们可以称之为:

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
    }
)
wd2eg0qa

wd2eg0qa14#

您可以直接使用 java.util.concurrent 包裹。
我也搜索了一下,在这个android异步api中找到了一个解决方案。
不幸的是,这篇文章使用的是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版本要好。
希望这对你有帮助。谢谢您

相关问题