在公共类中从AsyncTask更新UI线程

6
我正在尝试将一些AsyncTask类分离成公共(单独的)函数,以便不必重写太多代码。我几乎做到了,除了一个非常重要的方面。 AsyncTask函数通过向服务器发出php调用来编译ArrayList。当该列表完成时,我需要在主UI线程上更新一个Spinner。 我找到了一个非常好的答案here,但是我在使其工作时遇到了一些困难。
这是我所拥有的简化版本:(请注意,在此时,我正在尝试调用Toast消息以证明往返工作)
这是调用Activity:
public class MyActivity extends Activity implements OnTaskCompleted {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sg_list = new ArrayList<String>();
        new GetSuperGroups(UpdateAffiliationsPreferences.this, context, "Retrieving Group List...").execute();
    }

    public void onTaskCompleted(ArrayList<String> list) {
        Toast.makeText(getApplicationContext(), "hello from async", Toast.LENGTH_SHORT).show();
    }

}

这是界面:
public interface OnTaskCompleted {
    void onTaskCompleted(ArrayList<String> list);
}

最后,这里是AsyncTask。请注意它是一个公共类:

public class GetSuperGroups extends AsyncTask<String, String, ArrayList<String>> {

    private Activity activity;
    private Context context;
    private String progressMsg;
    private ProgressDialog pDialog;
    private ArrayList<String> sg_list;
    private OnTaskCompleted listener;

    public GetSuperGroups(Activity activity, Context context, String progressMsg) {
        this.activity = activity;
        this.context = context;
        this.progressMsg = progressMsg;
    }

    public void setSuperGroupList (OnTaskCompleted listener){
        this.listener = listener;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(context);
        pDialog.setMessage(progressMsg);
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    @Override
    protected ArrayList<String> doInBackground(String... args) {

        sg_list = new ArrayList<String>();
        //make a php call, compile the ArrayList    
        return sg_list;
    }

    protected void onPostExecute(ArrayList<String> sg_list) {
        pDialog.dismiss();
        //this next line causes a null pointer error
        //note that I am throwing away the array list for now
        //all I want to do is prove that I can call the Toast back in the calling Activity
        listener.onTaskCompleted(new ArrayList<String>());
    }
}
4个回答

7

只需在您的asyncTask构造函数GetSuperGroups中添加OnTaskCompleted listener参数。然后在执行asyncTask时传递this

public class MyActivity extends Activity implements OnTaskCompleted {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            sg_list = new ArrayList<String>();
            new GetSuperGroups(UpdateAffiliationsPreferences.this, context, "Retrieving Group List...", this).execute();
        }

        public void onTaskCompleted(ArrayList<String> list) {
            Toast.makeText(getApplicationContext(), "hello from async", Toast.LENGTH_SHORT).show();
        }

    }

并且

  public class GetSuperGroups extends AsyncTask<String, String, ArrayList<String>> {

        private Activity activity;
        private Context context;
        private String progressMsg;
        private ProgressDialog pDialog;
        private ArrayList<String> sg_list;
        private OnTaskCompleted listener;

        public GetSuperGroups(Activity activity, Context context, String progressMsg, OnTaskCompleted listener) {
            this.activity = activity;
            this.context = context;
            this.progressMsg = progressMsg;
            this.listener = listener;
        }

我认为这个程序可能会泄露内存,因为你将活动实例传递给任务,如果活动旋转或由于某些原因必须被销毁,直到任务完成它才不会被垃圾回收... - Feras

2

你从未调用setSuperGroupList(),因此listener保持为null。最好将listener放入任务的构造函数中。


谢谢。我头晕了。我想不出从哪里调用它。 - AndroidDev
这并不重要,因为它不会启动任何操作。因此,将监听器作为构造函数参数添加似乎很好,因为它保证了监听器的设置。您可能希望考虑使用android.os.Handler而不是自己的监听接口。 - Alexander Kulyakhtin

0
你需要添加一个名为setListener的函数:
public class TaskComplete {
    public OnTaskCompleted onTaskListenerComplete;

    public interface OnTaskCompleted {
        void onTaskCompleted(ArrayList<String> list);
    }

    public void setOnTaskComplete(OnTaskCompleted onTaskListenerComplete){
        this.onTaskListenerComplete = onTaskListenerComplete;
    }
}

在Activity中,定义并设置它:

public class MyActivity extends Activity implements OnTaskCompleted {
    public TaskComplete task;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sg_list = new ArrayList<String>();
        task.setOnTaskComplete(this);
        new GetSuperGroups(UpdateAffiliationsPreferences.this, context, "Retrieving Group List...").execute();
    }

    public void onTaskCompleted(ArrayList<String> list) {
        Toast.makeText(getApplicationContext(), "hello from async", Toast.LENGTH_SHORT).show();
    }

}

在AsyncTask中:

protected void onPostExecute(ArrayList<String> sg_list) {
    pDialog.dismiss();
    //this next line causes a null pointer error
    //note that I am throwing away the array list for now
    //all I want to do is prove that I can call the Toast back in the calling Activity
    activity.onTaskCompleted(new ArrayList<String>());
}

希望它有用。


0

你正在走正确的道路。但我不清楚onPostExecute(..)方法中的问题是关于null pDialog还是null sg_list。如果sg_list出现问题,请检查php方法是否正常工作?可能是manifest文件中php服务权限的问题。
所以我的建议是首先在UI线程上检查您的方法。然后将其更改为在后台线程中执行。
此外,您可以在onPostExecute方法中放置toast以检查sg_list内容。


这不是 sg_list 的问题。请注意,尽管我构建了它并最终打算使用它,但现在我甚至没有引用它。问题出在监听器为空,但我不知道如何实例化它。 - AndroidDev

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