【问题标题】:How to update UI from a Runnable?如何从 Runnable 更新 UI?
【发布时间】:2014-12-11 04:10:58
【问题描述】:

我需要从 runnable 更新 ui。我的逻辑如下。 我从片段生命周期的 onCreate 开始运行。可运行实例负责请求网络。问题是可运行实例从网络获取数据后,我不知道如何更新片段。

在 CustomFragment.java 中的片段中开始运行的代码。

public void onCreate(Bundle savedInstanceState) {
    Log.d(DEBUG_TAG, "onCreate");
    super.onCreate(savedInstanceState);

    accountMgr.requestAccountInfo();

}

在 AccountManager.java 中开始运行的代码

/**
 * request Account info from server
 */
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void requestAccountInfo() {
    Account act = getCurrentAccount();
    Thread t = new Thread(new RequestAccountInfoTask(act));
    t.start();
}

/**
 * automatically update Account info, like space usage, total space size, from background.
 */
 class RequestAccountInfoTask implements Runnable {

    private Account account;

    public RequestAccountInfoTask(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
        doRequestAccountInfo(account);

    }
}

【问题讨论】:

    标签: java android multithreading android-fragments


    【解决方案1】:

    runOnUiThread() 需要 Activity 引用。有替代方案。您不需要 Activity 引用您的 Thread。您始终可以使用主循环器获取 UI 处理程序。传递其他参数,例如您的界面,以在任务完成后更新片段。

    class RequestAccountInfoTask implements Runnable {
    
        private Account account;
        private Handler mHandler;
        public RequestAccountInfoTask(Account account) {
            this.account = account;
            mHandler = new Handler(Looper.getMainLooper());
        }
    
        @Override
        public void run() {
            doRequestAccountInfo(account);
            //use the handler
        }
    }
    

    您在实例化的Handler 上运行的任何内容都将在 UI 线程上。

    当然,使用runOnUiThread() 是完全合理的。

    【讨论】:

    • 我已经实现了这条评论,一些参考here
    【解决方案2】:

    你可以使用活动的runOnUIThread方法。

    这里的代码可能对你有帮助:

    class RequestAccountInfoTask implements Runnable {
    
        private Account account;
    
        public RequestAccountInfoTask(Account account) {
            this.account = account;
        }
    
        @Override
        public void run() {
            doRequestAccountInfo(account);
            if (getActivity() != null) {
                getActivity().runOnUiThread(new Runnable() {
    
                    @Override
                    public void run() {
                        // you can update fragment UI at here
                    }
                });
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      请查看 AsyncTask 以从线程更新 UI:

      http://developer.android.com/reference/android/os/AsyncTask.html

      以下是上述链接的亮点:

      类概述 AsyncTask 允许正确和轻松地使用 UI 线程。 此类允许执行后台操作并发布结果 在 UI 线程上,无需操作线程和/或处理程序。

      AsyncTask 被设计成一个围绕 Thread 和 Handler 的辅助类 并且不构成通用线程框架。异步任务 理想情况下应用于短操作(几秒钟在 大多数。)如果您需要保持线程长时间运行, 强烈建议您使用由 java.util.concurrent 包,例如 Executor、ThreadPoolExecutor 和 未来任务。

      异步任务由运行在 后台线程,其结果发布在 UI 线程上。一个 异步任务由 3 种泛型类型定义,称为 Params, Progress 和 Result,以及 4 个步骤,分别称为 onPreExecute、doInBackground、 onProgressUpdate 和 onPostExecute。

      【讨论】:

        【解决方案4】:

        您无法从 runnable 更新 UI。您需要更新 UI 的处理程序。请参阅this 了解更多信息。

        【讨论】:

        【解决方案5】:

        UI 只能由创建它的线程修改。在大多数情况下是由 UI 线程。所以你需要使用 runOnUiThread 方法更新。祝你好运

        【讨论】:

          【解决方案6】:

          我知道答案有点不同。但我想让你看看 Android 注释。其中非常容易使用。我只将它们用于背景和 Ui 线程。通过在您的方法名称上写 @Background 来完成后台线程中的每个任务。并在 UI 线程中进行所有 UI 更新。我建议你只检查一次。 http://androidannotations.org/ 谢谢 至于你的回答是关注。您无法从可运行状态更新您的 UI。请参阅用于更新 Ui 的异步任务。

          【讨论】:

            【解决方案7】:

            我推荐使用 AsynTask 或者你可以试试这个

            getActivity().runOnUiThread(new Runnable() {
            
                            @Override
                            public void run() {
                                Toast.makeText(getActivity(), "ON UI Thread", Toast.LENGTH_LONG).show();
                            }
                        });
            

            【讨论】:

              【解决方案8】:

              您可以使用事件总线来做到这一点 - http://square.github.io/otto/ 这很简单。当您需要像这样更新 UI 时,只需从您的线程发送事件:

              ...
              //in the end of your heavy job:
              bus.post(new YourEvent());
              

              并在您的 Activity 创建方法中:

              @Subscribe
              public void onYourEvent(YourEvent event) {
                  //do what you want there
              }
              

              顺便说一句,你可以通过事件传递任何数据,它是你的自定义类!请阅读手册如何设置这个库,为总线注册活动。它非常有用且易于使用

              【讨论】:

                【解决方案9】:

                您可以创建一个 Runnable,然后发布到主线程。来自 Google 的开发者页面Processes and Threads

                这个实现是线程安全的:后台操作已经完成 来自一个单独的线程,而 ImageView 总是从 UI 线程。

                public void onClick(View v) {
                    new Thread(new Runnable() {
                        public void run() {
                            // a potentially  time consuming task
                            final Bitmap bitmap =
                                    processBitMap("image.png");
                            mImageView.post(new Runnable() {
                                public void run() {
                                    mImageView.setImageBitmap(bitmap);
                                }
                            });
                        }
                    }).start();
                }
                

                【讨论】:

                  猜你喜欢
                  • 2020-12-11
                  • 2015-11-11
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多