【问题标题】:android: using arrayadapter<Custom object> that was created in AsyncTask in the MainActivityandroid:使用在 MainActivity 的 AsyncTask 中创建的 arrayadapter<Custom object>
【发布时间】:2012-07-10 05:30:43
【问题描述】:

我遇到了以下问题,希望有人能给我提示。

我有一个执行AsyncTask&lt; String, Void, ArrayList&lt;Custom object &gt;&gt; 的活动。 在doInBackground() 函数中,我设置了一个新的自定义对象ArrayList,它也是返回值。 在onPostExecute() 方法中,ArrayList 用于新创建的ArrayAdapter&lt;Custom object&gt;,它也设置为ListView 和lv.setAdapter(adapter). 到目前为止一切顺利!

现在的事情是:回到 MainActivity 我将再次需要那个适配器,因为我想通过调用 adapter.add(items). 向它添加新项目 现在,我将 AsyncTask 作为 MainActivity 的内部类,并且可以使用同样的 ListView 和同样的 ArrayAdapter,,效果非常好!

但是因为我还有另一个类也需要执行 AsyncTask,所以我将内部类 AsyncTask 更改为独立的 .java 文件 (CustomAsyncTask.java)

-> 现在,当我尝试向 ArrayAdapter 添加新项目时,它会抛出 NullPointerException! 当然就是,因为ArrayAdapter 属于AsyncTask 并在那里创建 所以我尝试将 MainActivity 中的 ListView 和 ArrayAdapter 作为 CustomAsyncTask 构造函数的参数,以便在其中使用它 但这不起作用,MainActivity 中的 ArrayAdapter 始终为 null 导致异常

任何想法如何解决? 我真的很感激。

这里是MainActivity.java的代码:

// global variables
ArrayAdapter<Custom object> arrayadapter;
ListView listview;
ProgressBar progressbar;

...

protected void myMethod() {
    CustomAsyncTask hTask = new CustomAsyncTask(this, listview, progressbar, arrayadapter);
    hTaskPlaylist.execute(String sth);
}

...

protected void anotherMethod() {
    arrayadapter.add(item);
}

以及CustomAsyncTask.java的代码:

package com.mypackage.test;

import java.util.ArrayList;

import android.content.Context;
import android.os.AsyncTask;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;

public class CustomAsyncTask extends AsyncTask<String, Void, ArrayList<Custom object>>{

    Context context;
    ListView listview;
    ProgressBar progressbar;
    ArrayAdapter<Custom object> arrayadapter;

    public CustomAsyncTask(Context con, ListView lv, ProgressBar pb, ArrayAdapter<Custom object> aa) {
        this.context = con;
        this.listview = lv;
        this.progressbar = pb;
        this.arrayadapter = aa;
    }

    @Override
    protected void onPreExecute() {
        listview.setVisibility(ListView.GONE);
        progressbar.setVisibility(ProgressBar.VISIBLE);
        super.onPreExecute();
    }

    @Override
    protected ArrayList<Custom object> doInBackground(String... params) {
            ArrayList<Custom object> list = new ArrayList<Custom object>();

            ... doing something and populating list
            return list;
    }

    @Override
    protected void onPostExecute(ArrayList<Custom object> list) {
        super.onPostExecute(list);

        arrayadapter = new ArrayAdapter<Custom object>(context, android.R.layout.simple_list_item_1, list);
        listview.setAdapter(arrayadapter);

        progressbar.setVisibility(ProgressBar.GONE);
                listview.setVisibility(ListView.VISIBLE);
    }

    }
}

【问题讨论】:

    标签: android arraylist android-asynctask return-value android-arrayadapter


    【解决方案1】:

    您可以将 ArrayAdapter 设为静态。然后,您可以随时访问它,只需说 CustomAsyncTask.arrayadapter.add(items);您还可以将自己的函数添加到自定义 asynctask 类中。您可以创建类似 public ArrayAdapter getAdapter() 的东西。但请注意,无论如何,您将有多个线程访问/更改该对象,因此同步访问是个好主意。

    你可以试试这样的……

    ArrayAdapter globalAdapter;
    globalAdapter = new CustomAsyncTask().execute(/*your parameters here*/).get();
    

    【讨论】:

    • 谢谢.. 但是没有办法将值返回给 MainActivity(不仅仅是在 onPostExecute() 中)吗?-> 因为当 AsyncTask 是MainActivity,如果它也是一个外部类,它应该可以工作,不是吗?
    • 适配器原本是主活动中的变量吗?因为内部类可以访问外部类的实例变量......是的,它应该可以让你的异步任务返回一个数组适配器;但是,您对该返回值所做的任何更改都不会保留在其他实例中。
    • ArrayAdapter arrayadapter 是在 MainActivity 中全局定义的(所以当 Activity 启动时适配器为空),然后我创建一个新的 AsyncTask 对象,其中 arrayadapter & listview 作为参数并执行它。在 CustomAsyncTask 中,我使用 arrayadapter 填充列表视图,其中填充了 arraylist。 (在 onPostExecute() 中)来自 MainActivity 的列表视图已正确设置,只有当我尝试调用 arrayadapter.add(item) 时它才会抛出 NullPointerException
    • 好吧,如果它们在您的活动中声明,它们就不是全局的,因为全局意味着所有类和子类都可以访问它们。当您将 arrayadapter 提供给 AsyncTask 时,它是按值传递的。这意味着您对该 arrayadapter 所做的任何更改都不会影响您的主要活动中的那个。
    • sry,全局我的意思是 MainActivity 类。但是如何解释我可以在 MainActivity 和 AsyncTask 中使用传递的列表视图是不是有点奇怪,JAVA 通过引用处理对象,但是当通过值传递方法参数时?那么有没有办法通过引用传入arrayadapter?
    【解决方案2】:

    现在我尝试了,并将MainActivity 作为参数而不是Context 传递, 这是我改变的:

    public class CustomAsyncTask extends AsyncTask<String, Void, ArrayList<Custom object>>{
    
        **MainActivity activity**;
        ListView listview;
        ProgressBar progressbar;
        ArrayAdapter<Custom object> arrayadapter;
    
        public CustomAsyncTask(**MainActivity act**, ListView lv, ProgressBar pb, ArrayAdapter<Custom object> aa) {
            **this.activity = act;**
            this.listview = lv;
            this.progressbar = pb;
            this.arrayadapter = aa;
        }
    
        ...
    
        @Override
        protected void onPostExecute(ArrayList<Custom object> list) {
            super.onPostExecute(list);
    
            arrayadapter = new ArrayAdapter<Custom object>(context, android.R.layout.simple_list_item_1, list);
            listview.setAdapter(arrayadapter);
            **activity.arrayadapter = arrayadapter;**
    
            progressbar.setVisibility(ProgressBar.GONE);
            listview.setVisibility(ListView.VISIBLE);
        }
    
    }
    

    是的,它成功了! 谢谢乔尔, 但我仍然想知道为什么我可以从MainActivity 传递listview,在AsyncTask 中调用该列表视图上的函数,并且通常在MainActivity 中使用该列表视图,有什么想法吗?

    还有一个问题:传递Activity 对象而不是Context 对象的唯一区别是您是否可以访问您在Activity 中定义的可用变量和方法?

    【讨论】:

    • 不客气!当您将列表视图传递给 AsyncTask 时,该任务将获得您活动中的列表视图的副本。所以它可以用那个列表视图做任何它想做的事情,它不会改变你活动中的那个。是的,本质上就是这样。有了上下文,你永远不会真正知道它代表的是哪种对象。如果需要,您可以通过执行“MainActivity activity = (MainActivity) context;”将上下文转换为活动的实例。然后你就可以完全访问 MainActivity 类中的任何功能了!
    • 但是如果你尝试转换一个不是你的活动实例的上下文,它会抛出一个空指针异常。
    • 在你说完之后,我假设上下文通常是多余的还是我错过了什么?
    • 某种...例如,在 Toast.makeText(this,...); 这样的调用中这里指的是一项活动。活动实际上是上下文的子类,因此您可以将其作为上下文参数传递,就像在 make text 方法中一样。上下文是模棱两可的,并且有几个子类。所以如果你有一个上下文的实例,它也很可能暗中是它的子类之一的实例(例如活动)。如果您认为这可能会有所帮助,也许可以阅读开发人员关于上下文的说明
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多