【问题标题】:Progress bar fails when loaded second time第二次加载时进度条失败
【发布时间】:2012-04-10 14:11:00
【问题描述】:

我有一个简单的函数,显示在获取数据时加载微调器(通常需要 7 秒左右)

private void load_data(View v)
{
    task_complete = false;
    progressBar = new ProgressDialog(v.getContext());
    progressBar.setCancelable(false);
    progressBar.setMessage("Fetching data ...");
    progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
    progressBar.show();

    try
    {
        Log.v("thread", "Starting thread");
        new Thread(new Runnable()
        {
            public void run()
            {
                while(!task_complete)
                {
                    fetch_data();
                    try
                    {
                        Thread.sleep(1000);
                    }
                    catch(InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                }
                progressBar.dismiss();
            }
        }).start();
        Log.v("thread", "Thread finished successfully");
    }
    catch(Exception e)
    {
        Log.v("thread", "fail "+e.toString());
    }
}

我遇到的问题是 onClick 调用了函数

load.setOnClickListener(new View.OnClickListener()
{
    public void onClick(View v)
    {
        load_data(v);
        show_data(v); // shows the data on a spinner
    }
});

当我第二次按下加载按钮时出现错误。我的日志确实显示了

Starting thread
Thread finished successfully

但不知何故,应用程序因错误提示而死掉了

03-27 02:48:39.282: E/AndroidRuntime(956): Uncaught handler: thread Thread-9 exiting due to uncaught exception
03-27 02:48:39.293: E/AndroidRuntime(956): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
03-27 02:48:39.293: E/AndroidRuntime(956):  at android.view.ViewRoot.checkThread(ViewRoot.java:2683)

如果有人能告诉我或向我解释导致错误的原因,我将不胜感激

【问题讨论】:

    标签: java android multithreading exception-handling android-progressbar


    【解决方案1】:

    问题是你的progressBar.dismiss();在另一个线程中执行,要使其在 UI 线程中运行,请执行以下操作:

        runOnUiThread(new Runnable() {
    
            @Override
            public void run() {
                progressBar.dismiss();
            }
        });
    

    【讨论】:

    • 非常感谢您的精彩回答,它有效,我所要做的就是更改一行 :)
    • 线程将开始在UI线程上运行,如果加载时间稍长,可能会提示ANR(Activity Not Responding)对话框。但是,在您的情况下,加载只需 7 秒,因此用户不会介意;)
    • 实际上只有progressBardismiss命令会在UI线程上执行,如果它需要超过0.1毫秒我会感到惊讶。
    【解决方案2】:

    ProgressDialog 是一个视图,您只能在 UI 线程(或主线程)中访问它。使用AsyncTask 而不是线程。

    编辑
    This official link 将帮助您掌握 AsyncTask 的窍门。要记住的是 doInBackground() 方法在单独的线程中运行,您应该在其中放置数据加载方法,即 fetch_data()。一旦方法完成执行,onPostExecute() 将被调用,它将在 UI 线程上运行,您可以在其中关闭对话框。您可以在 onPreExecute() 方法中启动对话框。
    尽管在这种情况下您不需要 onProgressUpdate() 方法,但仅供参考,它用于在加载仍在使用 publishProgress() 调用时更新 UI 线程中的视图(以防您将来使用 AsyncTask)。

    PS: 只有 doInBackground() 方法在单独的线程中运行,其他所有方法都在 UI 线程中运行。除了 UI 线程之外,关于不在任何其他线程中访问 View 的规则在这里仍然适用。

    【讨论】:

    猜你喜欢
    • 2016-08-25
    • 1970-01-01
    • 2017-11-05
    • 2012-01-26
    • 1970-01-01
    • 2022-08-15
    • 1970-01-01
    • 2013-12-17
    • 2020-10-02
    相关资源
    最近更新 更多