使用setContentView加载布局时显示ProgressDialog

时间:2011-06-27 13:24:47

标签: android multithreading android-activity android-asynctask progressdialog

这是我的方案:我有一个登录屏幕,可以打开另一个活动。在活动中,我只需:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_details);
}

布局有点沉重,因为它是由一些碎片组成的,并且需要大约1.5秒才能加载。 现在,如何在ProgressDialog完成布局时显示setContentView?我通过将AsyncTask放在setContentView中尝试doInBackground,但当然无法完成,因为UI只能从UI线程更新。 所以我需要在UI线程中调用setContentView,但是我必须在哪里显示/关闭ProgressDialog

感谢您的帮助。

弗拉。

编辑:我跟着@ JohnBoker先前的建议,这是我现在的代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_empty_layout);
    new ContentSetterTask().execute("");
}

private class ContentSetterTask extends AsyncTask<String, Void, Void> {

    public ProgressDialog prgDlg;

    @Override
    protected void onPreExecute() {
        android.os.Debug.waitForDebugger();
        prgDlg = ProgressDialog.show(MultiPaneActivity.this, "", "Loading...", true);

    }

@Override
protected Void doInBackground(String... args) {
    android.os.Debug.waitForDebugger();
    ViewGroup rootView = (ViewGroup)findViewById(R.id.emptyLayout);
    LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View inflated = inflater.inflate(R.layout.activity_details, rootView);
    return null;
}

@Override
protected void onPostExecute(Void arg) {
    android.os.Debug.waitForDebugger();
    if (prgDlg.isShowing())
        prgDlg.dismiss();
    }
  }
}

View inflated = inflater.inflate(R.layout.activity_details, rootView);

给我错误:

06-27 16:47:24.010:   
ERROR/AndroidRuntime(8830): Caused by:android.view.ViewRoot$CalledFromWrongThreadException: 
Only the original thread that created a view hierarchy can touch its views.

3 个答案:

答案 0 :(得分:8)

我在创建一个沉重的视图时遇到了同样的问题,我所做的只是在xml文件中放置了一个linearlayout并在其上调用了setContentView,然后我在asynctask中创建了真实视图,并将视图dymanically添加到linearlayout

此方法似乎有效,我可以在此过程中设置进度对话框。

答案 1 :(得分:8)

我决定在这里为未来的读者做一个完整的答案。

在这个问题上花了几个小时之后,我意识到问题是我正在尝试做两件事:

  1. 给布局充气,这是一个 需要进行的操作 UI线程的设计。
  2. 显示对话框(ProgressDialog, 实际上,但这并没有改变 结果),可以从中完成 仅限UI线程,因为服务 无法显示任何对话框。
  3. 因此,由于两个调用都来自UI线程(onCreate或AsyncTask没有区别,它仍然是UI线程),第一个阻止第二个调用正确显示。 底线是:此问题无法在Android中解决。让我们希望我们可以获得一些更好的API来与UI进行交互,因为我们有点吮吸。

    我将通过更改布局并使其更轻(如果可能!)来解决此问题。 谢谢大家!

答案 2 :(得分:0)

这不是一个完美的解决方案,但到目前为止最接近我需要的东西:我们需要一些时间设置进度对话框(或消息视图或其他)可见和调用setContentView(),以便对话/消息实际上是显示的。

为了实现这一点,我启动一个Thread执行一个short sleep(),然后在UI线程中调用setContentView()。

以下是进度对话框的示例:

private ProgressDialog  m_Hourglass = null ;
private Thread          m_LoadingThread = null ;

...

public void onCreate( Bundle savedInstanceState )
{
    super.onCreate( savedInstanceState );

    ...

    m_Hourglass = new ProgressDialog( this );
    m_Hourglass.setMessage( "Loading" );
    m_Hourglass.setIndeterminate( true );
    m_Hourglass.setCancelable( false );
}

public void SetMyView( View vvv )                   // Can be called from buttons.
{
    if( m_LoadingThread != null ) return;           // Avoid multiple press

    m_Hourglass.show();

    ////////////////////////////////////////////////////
    // Load in a thread, just to show the above message
    // before changing layout (because setContentView()
    // freezes the GUI.)
    m_LoadingThread = new Thread()
    {
            @Override
            public void run()
            {
                super.run();
                try                 {   sleep( 20 ); }
                catch (Exception e) {   System.out.println( e ); }
                finally             {   runOnUiThread( new Runnable()
                                        {
                                            public void run() 
                                            {
                                                SetMyViewThreaded();
                                            }
                                        });
                                    }
                m_LoadingThread = null ; // Now we can load again
            }
    };
    m_LoadingThread.start();
}

public void SetMyViewThreaded()
{
    setContentView( R.layout.some_gorgeous_layout );

    /////////////////////////////////////////////////////
    // Catch when to finally hide the progress dialog:
    ImageView iv            = (ImageView) findViewById( R.id.some_view_in_the_layout );
    ViewTreeObserver obs    = iv.getViewTreeObserver();      
    obs.addOnGlobalLayoutListener( new OnGlobalLayoutListener()
    {          
         @Override          
         public void onGlobalLayout()    // The view is now loaded
         {
             m_Hourglass.hide();
         }      
    });

    //////////////////////////////////////////////////////
    // Here we can work on the layout
    ...
}

我的主要问题是睡眠(20),这是近似值,并且在所有机器上可能都不够。它适用于我,但如果你没有看到进度对话框,你可能需要增加睡眠持续时间。