Android 使用setContentView加载布局时显示ProgressDialog
这是我的场景:我有一个登录屏幕,可以打开另一个活动。在活动中,我只需要:Android 使用setContentView加载布局时显示ProgressDialog,android,multithreading,android-activity,android-asynctask,progressdialog,Android,Multithreading,Android Activity,Android Asynctask,Progressdialog,这是我的场景:我有一个登录屏幕,可以打开另一个活动。在活动中,我只需要: public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_details); } 布局有点重,因为它是由一些碎片组成的,加载大约需要1.5秒。 现在,当setContentView完成对布局的充气时,如何显示ProgressDi
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
}
布局有点重,因为它是由一些碎片组成的,加载大约需要1.5秒。
现在,当setContentView
完成对布局的充气时,如何显示ProgressDialog
?我尝试了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();
}
}
}
给我一个错误:
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.
我在创建重视图时也遇到了同样的问题,我所做的是仅在xml文件中放置一个linearlayout,并在该文件上调用setContentView,然后我在asynctask中创建了真实视图,并动态地将视图添加到linearlayout中
这个方法似乎很有效,在这个过程中我可以打开一个进度对话框。我决定在这里为未来的读者提供一个完整的答案 在这个问题上花了几个小时后,我意识到问题在于我正在尝试做两件事:
谢谢大家 这不是一个完美的解决方案,但到目前为止,这是最接近我需要的解决方案:在设置可见的进度对话框(或消息视图或其他)和调用setContentView()之间需要一段时间,以便实际显示对话框/消息 为了实现这一点,我启动了一个执行短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),这是一个近似值,在所有机器上可能都不够。这对我来说是可行的,但是如果你没有看到进度对话框,你可能必须增加睡眠时间。那么在doInBackground方法中手动增加睡眠时间怎么样?如果你想查看布局文件,那就最好尝试并优化它。这是模拟器上的1.5秒还是手机/平板电脑上的1.5秒?嗨,在eeePad Transformer上实际上大约是1.5秒。如何手动充气?在这里发布的布局相当长,但是它有大约10-12个线性布局和一个真实片段(目前)。在活动\u空\u布局上有一个布局(相对、线性等),对吗?如何膨胀活动\ u详细信息并将null传递给root用户,这样,之后,您就可以从父布局中使用addView.trusted with:View inflated=inflater.inflate(R.layout.activity\ u details,null);rootView.addView(充气);我仍然会犯同样的错误。是的,这似乎是一个完美的选择!您可以查看线程部分的AsyncTask,将显示在onPreExecute中的进度对话框放入onPostExecute中。有一个例子是,在《我已经有了展示》和《我已经有了发布前和发布后》中的驳回。现在我在doInBackground中添加了膨胀,这就是我得到的(明显的)错误:06-27 16:12:35.630:error/AndroidRuntime(8077):由以下原因引起:android.view.ViewRoot$calledFromErrorThreadException:只有创建视图层次结构的原始线程才能接触其视图。我在第一篇文章中添加了一些细节,完整的代码和上面的错误。看来我做了一些与你建议的不同的事情(如果使用HandlerThread,可以在单独的线程上手动膨胀视图。基本上,膨胀视图的线程需要一个活套。
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
...
}