android异步任务api有哪些替代方案?

lnxxn5zx  于 2021-09-13  发布在  Java
关注(0)|答案(16)|浏览(561)

谷歌反对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 . 它是活动的静态内部类。我正在寻找一些可以与之合作的东西 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) ;
    }     

}
ulmd4ohb

ulmd4ohb1#

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

vwkv1x7d2#

您可以从中直接使用执行器 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版本要好。
希望这对你有帮助。非常感谢。

inn6fuwd

inn6fuwd3#

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

z0qdvdin

z0qdvdin4#

根据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
 }

将该函数与任何 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"
        })
    }
}

在里面 ActivityFragment :

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

使用 viewModelScopelifecycleScope 将下一行添加到应用程序的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
    }
)
jrcvhitl

jrcvhitl5#

使用该类在后台线程中执行后台任务该类适用于所有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();
7gyucuyw

7gyucuyw6#

在这里,我使用协程为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.“内部活动”现在将其与旧AsycntTask一样使用

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

jpfvwuh47#

android弃用了android 11中的AsyncTaskAPI,以解决一部分问题。

那么,现在是什么?

线程
执行者
rxjava
可倾听的未来
协同程序🔥

为什么要合作?

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

thtygnil

thtygnil8#

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

vlju58qv

vlju58qv9#

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

ui7jx7zq10#

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

jtoj6r0c

jtoj6r0c11#

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

5jdjgkvh

5jdjgkvh12#

实际上,我写了两个关于它的中间故事:
现在不推荐使用asynctas什么
现在不推荐使用asynctas,第2部分是什么
第一个是java和runnable解决方案,第二个是kotlin和协程解决方案。当然,这两者都有代码示例。

rkue9o1l

rkue9o1l13#

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

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

            });
        }).start();

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

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

ktecyv1j14#

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

5rgfhyps

5rgfhyps15#

这是我的密码

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

相关问题