Android:除了AsyncTask,还有哪些替代方案?

22

为了我的应用程序,我为所有对外部API的网络调用制作了一个框架。 我将一切都放在“服务”中,例如:UserServiceMessageService等。 现在当我想调用网络方法时,我不能在我的Activity的UI线程中这样做,所以我创建了一个AsyncTask ,一切都很好 =)

但现在我希望像将要执行的方法提供给AsyncTask,这样我就不需要为我的网络框架的每个方法编写一个AsyncTask。 所以,我不再需要像下面这样:

public class NetworkTask extends AsyncTask<UserService, Void, Void> {

    @Override
    protected Void doInBackground(UserService... params) {
        UserService userService = params[0];
        userService.getUser();
        return null;
    }
}

我希望有一种更加 "抽象" 的方法,这样 AsyncTask 就不需要知道 "getUser" 方法的存在?但是我找不到任何想法来做到这一点...也许 AsyncTask 对于这个问题并不好?


1
我不完全清楚你在问什么,但是IntentService通常被用作AsyncTask的替代方案。 - pathfinderelite
1
我也不确定我正确理解了你的意思,但是与AsyncTask的替代方案是loader,实际上你应该更喜欢使用它们。http://developer.android.com/guide/components/loaders.html - Bojan Kseneman
对不起,我不知道应该如何恰当地表达这个问题,所以在网上搜索也没有帮助。我再试着解释一下:在"doInBackground"方法中,我不想明确调用"userService.getUser",因为有许多其他的方法和服务都需要进行网络调用,而且我不能在主/UI线程上执行它们,所以我需要一个例如AsyncTask。但是我只想为每个网络方法拥有一个AsyncTask... - cherry-wave
你可以创建自己的接口并将其传递给你的通用Asynctask。我建议你检查来自Square的Retrofit或来自Google的Volley进行网络操作,根据这篇文章http://instructure.github.io/blog/2013/12/09/volley-vs-retrofit/,它们在网络操作方面更快。 - M090009
嗯,我不认为可以使用我的网络框架来做这个(这个框架只知道所有的 URL 并解析 JSON 成漂亮的对象返回到我的安卓应用程序)。 - cherry-wave
我正在考虑使用反射,但那不太好,是吧^^ - cherry-wave
9个回答

12

5

也许你可以使用第三方库,比如Retrofit。如果你需要处理图片,我强烈推荐picasso


5

3

RxJAVA是最佳选择

在Web服务调用、文件上传、文件下载等方面,可使用Android Fast Networking Lib代替Asynctask。

对于其他情况,您可以使用以下方法

 Disposable d = Observable.fromCallable(new Callable<HashMap<String, String>>() {
            @Override
            public HashMap<String, String> call() throws Exception {
            // will run in background thread (same as doinBackground)
                return postParam;
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<HashMap<String, String>>() {
                    @Override
                    public void accept(final HashMap<String, String> data) throws Exception {

        // will run in UI thread. write down code for on PostExecute
                    }

                });
    // write down code for on preExecute
        DisposableManager.add(d);

// 处理对象

@Override
    protected void onDestroy() {
        super.onDestroy();
        DisposableManager.dispose();
    }
        // Dispose manager class


 import io.reactivex.disposables.CompositeDisposable;
    import io.reactivex.disposables.Disposable;

    public class DisposableManager {

        private static CompositeDisposable compositeDisposable;

        public static void add(Disposable disposable) {
            getCompositeDisposable().add(disposable);
        }

        public static void dispose() {
            getCompositeDisposable().dispose();
        }

        private static CompositeDisposable getCompositeDisposable() {
            if (compositeDisposable == null || compositeDisposable.isDisposed()) {
                compositeDisposable = new CompositeDisposable();
            }
            return compositeDisposable;
        }

        private DisposableManager() {}
    }

这里并不固定使用HashMap<String,String>,您可以根据需要使用任何数据类型。 - Rajesh N

2
如果您不喜欢第三方库,而是喜欢简单易懂、有良好文档和支持的库,那么Loaders就是最好的选择。
让我们高兴的是,AsyncTaskLoader(Loaders的子类)执行与AsyncTask相同的功能,但更好,并且可以更轻松地处理Activity配置更改。最好的事情是它在Fragment和Activity的生命周期内运行。
要了解更多信息和子类,请查看此文档

1
只是一点小提醒,自API 28以来,该方法已被弃用。 - Rock_Artist

0

我有一个帖子,关于替换asynctask的多种解决方案,例如使用:

  1. Executors Service
  2. RxJava
  3. Listenable Futures
  4. Kotlin中的协程

这是我的实现:

点击下面的链接查看实现


0

应该使用Loader而不是直接使用Async任务。有特定的Loader API用于特定操作,如在sqlite数据库中执行事务等。


0
使用Kotlin和协程,自己实现它非常简单:
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)
}

executeAsyncTask 是在 CoroutineScope 上的扩展函数。只要有任何一个带有 Dispatchers.Main 上下文的 CoroutineScope 实例,例如 viewModelScope,我们就可以像下面这样调用该函数:

viewModelScope.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
    }
)

主要条件是 CoroutineScope 必须具有 Dispatchers.Main 上下文。 viewModelScope 默认情况下具有此上下文。

-1
你可以使用 Volley 库,它可以在后台线程上执行任务,并在完成时将控制权交还给主线程。

我曾经使用Volley进行数千条记录的调用,但它导致应用程序挂起/延迟。因此,我不建议在有大量响应数据时使用Volley。否则,Volley是非常优秀的。 - Naitik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接