异步任务中的ArrayList对象无法从doInBackground传递到onPostExecute

5
我有一个AsyncTask,它需要使用上下文(在onPostExecute中使用),并运行doInBackground从服务器返回一个对象的ArrayList。当我执行这个任务时,我可以看到doInBackground正常运行,但它没有将结果传递给onPostExecute。
经过长时间的搜索,我仍然找不到如何在AsyncTask中返回一个对象的ArrayList的答案。
以下是我在doInBackground中创建并在onPostExecute中使用的对象:
public class ServerTimeCard {

    public String eventNameInput;
    Boolean isLocation, isImage, isVoice;

    public ServerTimeCard(String eventNameInput, boolean isLocation, boolean isImage, boolean isVoice) {
        this.eventNameInput = eventNameInput;
        this.isLocation = isLocation;
        this.isImage = isImage;
        this.isVoice = isVoice;
    }

}

我在onCreate中执行AsyncTask,代码为new LoadFriendCards(context).execute();

  • 期望的输出结果:doInBackground应该返回一个ArrayList给onPostExecute

  • 当前的输出结果:onPostExecute中的ArrayList<ServerTimeCard>的大小为零,而在doInBackground中相同的数组列表大小较大。

以下是AsyncTask代码。

public class LoadFriendCards extends AsyncTask<Void, Void, ArrayList<ServerTimeCard>> {

            Context context;
            ArrayList<ServerTimeCard> result;

            public LoadFriendCards(Context context) {
                this.context = context;
            }

            @Override
            protected ArrayList<ServerTimeCard> doInBackground(Void... voids) {

                     result = new ArrayList<ServerTimeCard>();

                     // ...a bunch of data retrieval goes on here...    

                     // querying parse for object info
                     // adding a new object to the local ArrayList for all in db
                     for (String friend : friendsListNames) {
                          ParseQuery<ParseObject> query = ParseQuery.getQuery("TestObject");
                          query.whereEqualTo("accountName", friend+"@gmail.com");
                          query.findInBackground(new FindCallback<ParseObject>() {
                          public void done(List<ParseObject> objects, ParseException e) {
                          if (e == null) {

                               for (ParseObject cardInfo : objects) {

                                   ServerTimeCard item = new ServerTimeCard(
                                      cardInfo.getString("eventName"),
                                      cardInfo.getBoolean("isImage"),
                                      cardInfo.getBoolean("isImage"),
                                      cardInfo.getBoolean("isVoice"));

                                   result.add(item);


                        Log.e("New item called: ", String.valueOf(item.eventNameInput));
                        Log.e("New size of array...", String.valueOf(result.size()));

                    }

                } else {
                    Log.d("info", "Error: " + e.getMessage());
                }
            }
        });
    }

                // returning the new ArrayList<ServerTimeCard> to onPostExecute

                // PROBLEM: THE SIZE OF THE RESULT IS 0
                Log.e("Size of passing array", String.valueOf(result.size()));

                return result;
            }

            @Override
            protected void onPostExecute(ArrayList<ServerTimeCard> result) {

                // PROBLEM: This returns 0
                Log.e("Data list size: ", String.valueOf(result.size())); 

                // trying to use all objects in the arraylist here but it doesn't work
                // due to the size. Something isn't passing correctly.

            }
        }

Log.e 输出的 Logcat 日志:(该日志看起来调用了 doInBackground,然后是 onPostExecute,接着又是 doInBackground)

E/Size of passing array﹕ 0
E/Data list size:﹕ 0
E/New item called:﹕ yah
E/New size of array...﹕ 1
E/New item called:﹕ lplokolol
E/New size of array...﹕ 2
E/New item called:﹕ It works
E/New size of array...﹕ 3

已解决:我最初认为需要使用AsyncTask,但最终我将所有代码都删除并将其全部放入我的Main类中的方法中。在异步任务中同时运行太多东西,导致结构混乱。教训是:保持简单。


你能展示一下实际的循环吗?看起来好像每次迭代都在创建一个新的列表,但是没有循环就无法确定。 - zmbq
对于修改我的帖子并破坏格式的人:我注意到AsyncTask构造函数不喜欢{code}格式工具,并在编辑之前使其正常工作。 - user1889890
以前它(对我来说)就已经破了,现在它仍然破了。对此我很抱歉。我认为是项目符号列表搞乱了它。 - 323go
1
当您在doInBackground中设置断点时,result何时重置? - zmbq
1
此外,在 result.add(item); 之后添加日志以确保 item != null,并立即在添加后查看 result.size() - 323go
显示剩余13条评论
5个回答

2
你的问题在于你正在使用 findInBackground 进行查询。该方法在后台线程中执行。因此,你基本上是在异步任务中运行异步任务。
  1. doInBackground
  2. findInBackground -> 异步运行,因此代码继续执行
  3. onPostExecute 在查询完成之前被调用。
  4. 然后为你的查询调用 done 回调以填充列表
因此,你需要做的是,要么在 AsyncTask 之外使用 findInBackground(该方法不应在 AsyncTask 中使用),要么使用 find 函数。

1
你正在匿名内部类中修改result。你的代码在那里看到的不是你认为的结果,而是一个闭包。这是问题的根源。

我看到了 - 通过使用ParseObject Query方法(获取数据),我正在添加到数组中,但该数组后来被销毁(原因不明)。我正在搜索什么是闭包以理解它:)。有没有解决这个问题的方法? - user1889890

0

另一种更简单的方法是将你的doInBackground声明为List类型。以下是我的示例

    @Override
    protected  ArrayList<ServerTimeCard > doInBackground(String... urls) {
        // Perform the HTTP request for earthquake data and process the response.
        ArrayList<ServerTimeCard > result = QueryUtils.fetchTheData(urls[0]);
        return result;
    }

0

你正在启动一个后台线程(异步任务),并在此处多次调用query.findInBackground(),从而启动更多的后台线程。然而,这不是问题所在。

你遇到问题是因为AsyncTask在所有其他它启动的线程完成之前就已经完成了。只有当每个线程的FindCallback的done()方法被调用时,你才知道其他线程已经完成。

如果你想知道正确的大小,你需要以一种方式编写代码,以便在最后一个done()方法中检查大小。


0
你不必让doInBackground返回一个arraylist,然后在onPostExecute中使用。只需返回"ok"或"error"即可。在你的ask类中声明和创建一个私有arraylist作为成员变量,在doInBackground中填充它并在onPostExecute中使用即可。

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