假设您正在为应用设计线程架构 - >主要目的是你的应用程序将有很多需要在后台线程上完成的任务,有时候是UI线程上的结果任务,或者某些事情没有(尽管更多次,结果需要在UI线程上运行)。为简单起见,假设任务将是这样的:下载文件并显示弹出窗口,登录用户并转到其他页面,处理图像并将结果存储在数据库中(很多流行任务)应用程序))
我已经研究了很多关于细微差别的内容,但是我真的希望深入了解什么样的架构更好,以及考虑的因素。
以下是考虑的三个模型:
new Handler(Looper.getMainLooper());
,每次我需要执行任务时,我使用线程工厂来分离任务,使用UI线程上的处理程序(或任何自定义处理程序) Service
类。有一堆ServiceTask
衍生对象可以执行某些操作,但Service
类在启动/完成任务时与每个ServiceTask
进行通信。我稍微倾向于使用整个服务/线程模型,因为我已经阅读了一些与AsyncTask / Threads相比非常尴尬的细微差别:
private
static
handler
,如果类加载器在错误的时间调用它(例如包含一个在应用程序之前使用它的库)那么你的所有onPostExecute
将在错误的时间发生,因为您的处理程序不是主处理程序onPostExecute
中的一堆内容,例如是否有配置更改,或者您的活动已被销毁,或者在调用onPostExecute
时应用程序是后置/暂停的(导致崩溃)设计强大的线程架构的最佳方法是什么,这种架构不会轻易导致崩溃/意外行为,同时还能保持良好的性能?
如果这个问题过于含糊,如果你需要实际的代码(我害怕发布代码,因为它会超出问题的长度而不是已经过的代码),请在评论中告诉我。
答案 0 :(得分:3)
我认为你不会在这里找到一种适合所有人的方法。
DownloadManager
Service
可能是一个不错的选择,因为您不希望将操作附加到任何特定的Activity
。Handlers
更加棘手,如果它们附加到在后台线程上运行的Looper
,那么当您完成后,需要在quit()
上调用Looper
。当您需要延迟操作时,处理程序很好,postDelayed()
非常适合。当您需要从后台线程回传到UI线程时,它们也很好。但是,你是正确的,每个人都有你提到的陷阱。 Android是一个复杂的野兽,看起来他们可以做得更好,防止开发人员在脚下射击自己,特别是在一个Activity被销毁后调用AsyncTask!
答案 1 :(得分:1)
我使用Java的旧学校方法创建了一个派生自Java的Thread的类(我称之为ThreadRunner)。构造函数看起来像:
public ThreadRunner (Object [] params, AbstractCallback callBack) {...}
AbstractCallback是一个实现单个“onCall”的课程。方法,主要用于通知主叫方有关事件,例如"完成任务的执行"。
我已经用它来从互联网上获取内容并运行其他耗时的操作。它没有造成任何问题并按预期工作。
但是,我多次听说AsyncTask是一种Android-ish方式。我不知道为什么也没有任何改变的意图,因为如果它没有被破坏,我就不会修改它。"方法
我还看到了你需要用AsyncTask编写更少代码的评论,但在我使用传统Java威胁的方法中,编码量也很小,所以我把它排除在外#39;只是个人喜好和经验问题。
关于你的第三种方法 - 我认为你应该在编写一直运行的服务时使用它,监听请求并永不停止。当您只需要异步执行单个任务时,应该使用Java Threads或AsyncTask。
答案 2 :(得分:1)
我认为AsyncTask是列出目的的好工具。但它需要包装AsyncTask以便于使用。我的这种包装的变体(带有进度指示器)如下:
用于在应用程序活动中扩展它的主类AsyncActivity:
public abstract class AsyncActivity extends Activity{
// Поле нужно обязательно объявить как статическое!
private static AsyncConnect asyncConnect = null;
protected void runBackgroundTask(String progressInscription, RequestTask task){
asyncConnect = new AsyncConnect(this, responseListener, progressInscription, task);
asyncConnect.execute();
}
protected abstract void onBackgroundTaskEnd(boolean result);
@Override
protected void onResume(){
super.onResume();
// Перерегистрируем текущий контекст этой формы
// для корректной работы слушателя ответа с сервера
responseListener.registerCurrentContext( this );
if (asyncConnect != null){
asyncConnect.onResume(this);
}
}
@Override
protected void onPause(){
super.onPause();
if (asyncConnect != null){
asyncConnect.onPause();
}
}
/**
* Чтобы диалоги не вызывались из устаревшего контекста
* и по этой причине не исчезали при повороте экрана,
* слушателя ответа с сервера необходимо сделать статическим полем класса,
* в котором должен быть зарегистрирован текущий контекст
*/
private static final OnServerResponseListener responseListener = new OnServerResponseListener(){
private AsyncActivity context = null;
@Override
public void registerCurrentContext(AsyncActivity context){this.context = context; }
@Override
public void onResponse(boolean result){
// Если никакой контекст не был зарегистрирован, ничего не делаем
if (context == null) return;
// Освождаем статическое поле для сборщика мусора (но делать это не обязательно!)
asyncConnect = null;
// Вызываем колбэк о завершении фоновой задачи
context.onBackgroundTaskEnd(result);
}
};
}
附加类和一对接口:
public class AsyncConnect {
private final Activity context;
private final RequestTask task;
private final String progressInscription;
private final OnServerResponseListener responseListener;
private boolean isDone = false;
private ProgressDialog progressDialog;
public AsyncConnect(Activity context, OnServerResponseListener responseListener,
String progressInscription, RequestTask task){
this.context = context;
this.task = task;
this.progressInscription = progressInscription;
this.responseListener = responseListener;
progressDialog = null;
isDone = false;
}
public void execute(){
if (isDone) return;
new ConnectTask().execute();
}
public void onPause(){
if (isDone) return;
if (progressDialog != null){
if (progressDialog.isShowing()){
progressDialog.dismiss();
progressDialog = null;
}
}
}
public void onResume(Activity context){
if (isDone) return;
progressDialog = ProgressDialog.show( context, null, (CharSequence)progressInscription,
true, false);
}
private class ConnectTask extends AsyncTask<Object, Void, Boolean> {
@Override
protected void onPreExecute( ) {
super.onPreExecute();
progressDialog = ProgressDialog.show( context, null,
(CharSequence)progressInscription, true, false);
}
@Override
protected Boolean doInBackground(Object... messages) {
return task.call();
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (progressDialog != null){
if (progressDialog.isShowing()){
progressDialog.dismiss();
progressDialog = null;
}
}
// Делаем невозможным повторное использование этого объекта
isDone = true;
responseListener.onResponse(result);
}
}
}
public interface OnServerResponseListener {
public void registerCurrentContext(AsyncActivity context);
public void onResponse(boolean result);
}
public interface RequestTask {
public boolean call();
}
对于使用AsyncActivity,我们只需要调用runBackgroundTask并在目标活动中实现onBackgroundTaskEnd。根据这个想法,可以创建不同类型的AsyncTask包装。
答案 3 :(得分:1)
您也可以查看Needle;它是一个开源,简单但功能强大的Android多线程库。有了它,你可以说:
Needle.onMainThread().execute(new Runnable() {
@Override
public void run() {
// e.g. change one of the views
}
});
或
Needle.onBackgroundThread().execute(new UiRelatedTask<Integer>() {
@Override
protected Integer doWork() {
int result = 1+2;
return result;
}
@Override
protected void thenDoUiRelatedWork(Integer result) {
mSomeTextView.setText("result: " + result);
}
});
在GitHub上查看:https://github.com/ZsoltSafrany/needle