【问题标题】:How to update a ListView from an AsyncTask before it completes如何在完成之前从 AsyncTask 更新 ListView
【发布时间】:2013-10-13 21:51:41
【问题描述】:

我有一个客户端应用程序,它使用套接字和输入/输出流与服务器通信并请求一些数据。我创建了一个 AsyncTask 并在它的 doInBackground() 上建立连接并发送/接收数据。
doInBackground():

@Override
        protected Object doInBackground(Object... objIn) {

            // we create a TCPClient object and
            client = new T_Client(new T_Client.OnMessageReceived() {
                @Override
                // here the messageReceived method is implemented
                public void messageReceived(Object objIn) {
                    Log.v(tagTask, "Object Received: " + objIn);                        
                        Log.w(tagTask, "Object returned: " + objIn);
                        mapReturn = (Map<String, Integer>) objIn;
                        Log.i(tagTask, "Map Object Returned: " + mapReturn);
                        onProgressUpdate();                     
                }
            });
            client.run();

            return objIn;
        }

User 是一个简单的类,可以帮助我处理从服务器获取的数据。 我从服务器获取一个地图作为“用户列表”,我想在我的主活动的 ListView 中显示它,带有用户名(字符串)和在线状态(整数),然后我将它传递给本地地图对象。然后我调用 AsyncTask 的 onProgressUpdate() 方法。
onProgressUpdate():

@Override
        protected void onProgressUpdate(Void... voids) {
            super.onProgressUpdate();

            for (Entry<String, Integer> entry : mapReturn.entrySet()) {
                if (entry.getValue() == 1) {
                    User user = new User(entry.getKey(), "YES");
                    Log.v(tagTask, "UserName: " + user.getUser());
                    Log.v(tagTask, "Online Status : " + user.getOnLine());
                    listUsers.add(user);
                } else if (entry.getValue() == 0) {
                    User user = new User(entry.getKey(), "NO");
                    Log.v(tagTask, "UserName: " + user.getUser());
                    Log.v(tagTask, "Online Status : " + user.getOnLine());
                    listUsers.add(user);
                }
            }

             mAdapter.notifyDataSetChanged();
        }

    }

在这里,我遍历 Map 对象的条目,并为每个条目创建一个用户对象,然后将用户对象添加到我的 ArrayList“listUsers”,这是我用于 ListView 适配器的数组列表。现在,当我运行 mAdapter.notifyDataSetChanged() 时,我当然会收到一个错误,因为我正在尝试更新我的主 UI,而不是从主 UI 线程。 我不能使用 onPostExecute() 方法的原因是因为我保持 doInBackground() 运行(client.run())。我这样做的原因是因为我必须保持服务器和客户端之间的连接处于活动状态,以便我可以从服务器和服务器请求数据以发送这些数据。

所以我问你们是否有办法在 AsyncTask 完成之前更新我的 ListView(在这种情况下,它永远不会到达 onPostExecute);

附:我注意到一些我无法解释的奇怪现象。当我点击我活动中的 EditText 并弹出键盘时,ListView 会更新并且我可以看到我的数据。

【问题讨论】:

    标签: java android android-listview android-asynctask


    【解决方案1】:

    我不能使用 onPostExecute() 方法的原因是因为我一直在运行 doInBackground()(client.run())。

    恕我直言,这是对AsyncTask 的不当使用。当您不是创建和管理资源池的人时,不要无限期地占用资源池中的资源。

    相反,创建您自己的线程。然后使用Handler 将消息传递给您在主应用程序线程上运行的代码,以更新您的列表。

    【讨论】:

    • 当您说“当您不是创建和管理池的人时”是什么意思?
    • @akafortes:AsyncTask 维护一个线程池 (en.wikipedia.org/wiki/Thread_pool_pattern)。通常,您不会创建此池。 AsyncTask 为您创建它。在某些情况下,该池中将只有 一个 线程。如果您无限期地绑定该线程,您将无法将AsyncTask 用于其他任何事情。在这种情况下,您没有创建资源池,也没有管理资源池,因此您不应无限期地占用该池中的资源。
    • 好的,所以我应该在 Handler 中创建并保持连接,并使用该 Handler 进行所有通信(发送数据请求并接收实际数据)?你会建议这样做,当我收到一个对象然后调用 AsyncTask 来处理它? 编辑: 甚至完全跳过 AsyncTask?
    • @akafortes:“好的,所以我应该在 Handler 中创建并保持连接,并使用该 Handler 进行所有通信(发送数据请求并接收实际数据)?” - 不。您可以将您的AsyncTask 转换为Thread。而不是onProgressUpdate()onPostExecute(),您将Message 对象发送到HandlerHandlerhandleMessage() 方法将更新您的UI。请参阅 developer.android.com/training/multiple-threads/… 以获得稍微过于复杂的演示。
    • 好的,非常感谢。我会看看,如果有帮助,我会回来接受答案:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    相关资源
    最近更新 更多