如何从异步任务更新用户界面

19

我看过很多这方面的例子,但是我不知道如何在我的代码中实现它。

我正在使用这个代码。 我已经更新了url,所以它会接收带有动态数据的json。 我想要做的是用这段代码每30秒自动更新列表。

Handler handler = new Handler();
    Runnable refresh = new Runnable() {
        public void run() {
            new GetContacts().execute();
            handler.postDelayed(refresh, 30000); 
        }
    };

它会刷新并调用url以获取数据,但UI未更新。

感谢任何提示以指引我正确方向。

http://www.androidhive.info/2012/01/android-json-parsing-tutorial/


GetContacts的postExecute()正在更新UI,如果是这样,它已经在UI线程上运行并且应该正常工作。尝试提供更多的代码。 - Nativ
我是想问,第一句话是一个问题吗? - Nativ
听起来你正在尝试更新一个ListView。如果是这样的话,你应该更新你的数据结构,并使用类似下面这样的方法将其传递给你的适配器:`public synchronized void refreshAdapter(List itemList) { this.itemList = itemList; notifyDataSetChanged(); }` - Jeremy W
您是每隔30秒更新URL还是每次都请求同一个URL? - umerk44
3个回答

23

在 AsyncTask 中有三个受保护的方法可以与 UI 进行交互。

  • onPreExecute()
    • doInBackground() 之前运行
  • onPostExecute()
    • doInBackground() 完成后运行
  • onProgressUpdate()
    • 只有当 doInBackground() 使用 publishProgress() 调用它时才会运行

如果您的任务运行时间比您想要刷新的30秒长得多,则应使用 onProgressUpdate()publishProgress()。否则,onPostExecute() 应该能够解决问题。

请参阅官方文档以了解如何实现它。


9
您可以使用 AsycTask,并在任务结束后在 onPostExecute 中更新 list ui
    new AsyncTask<String, String, String>() {
        /**
         * Before starting background do some work.
         * */
        @Override
        protected void onPreExecute() {
        }

        @Override
        protected String doInBackground(String... params) {
            // TODO fetch url data do bg process.
            return null;
        }

        /**
         * Update list ui after process finished.
         */
        protected void onPostExecute(String result) {
               // NO NEED to use activity.runOnUiThread(), code execute here under UI thread. 

                 // Updating parsed JSON data into ListView
                 final List data = new Gson().fromJson(result);
                // updating listview
                ((ListActivity) activity).updateUI(data);
        }

    };
}

更新onPostExecute函数中不需要使用runOnUiThread,因为它已经在UIThread下被调用并执行。


21
onPostExecute()中,你不需要使用runOnUiThread(),因为它已经包含了此功能。 - indivisible

2

首先,使用postdelayed()不会重复运行您的代码。如果您想以重复模式运行代码,请使用以下代码。这将在每5秒后运行。

  ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(5);

    /*This schedules a runnable task every second*/
    scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
      public void run() 
      {
        runOnUiThread(new Runnable(){

            @Override
            public void run() {
                // TODO Auto-generated method stub
                new GetContacts().execute();
            }

        });
      }
    }, 0, 5, TimeUnit.SECONDS);

您正在遵循的代码在postExecute()中每次创建SimpleAdapter的新实例,因此您将一遍又一遍地看到相同的数据。因此,如果要更新适配器,请将SimpleAdapter实例作为类成员创建,并将postExecute()替换为此内容。
@Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            // Dismiss the progress dialog
            if (pDialog.isShowing())
                pDialog.dismiss();
            /**
             * Updating parsed JSON data into ListView
             * */
            if(adapter == null)
            {
                adapter = new SimpleAdapter(
                    MainActivity.this, contactList,
                    R.layout.list_item, new String[] { TAG_NAME, TAG_EMAIL,
                            TAG_PHONE_MOBILE }, new int[] { R.id.name,
                            R.id.email, R.id.mobile });

                            setListAdapter(adapter);
            }
            else
            {
                adapter.notifyDataSetChanged();
            }


        }

现在这会更新适配器,但会添加相同的联系人。

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