我很清楚阻止UI通常不是一个好主意,但在某些情况下,我的应用程序在完成一些长时间运行的操作(例如从服务器加载数据)之前根本无法执行任何其他工作。
假设用户单击“加载数据”按钮。为了表明在加载数据之前不可能进行UI交互,我想在屏幕上显示灰色并显示某种活动指示符。这根本不是问题,我只是用一个新的片段覆盖屏幕。
问题是:如何呈现此叠加片段?
public void onLoadDataClick() {
// grey out the screen by simple showing a new Fragment
showActivityIndicatorOverlay();
// Start the long running opeartion
doVeryMuchWork();
dismissActivityIndicatorOverlay();
}
public void showActivityIndicatorOverlay() {
FragmentTransaction ft = context.getSupportFragmentManager().beginTransaction();
ActivityIndicatorOverlayFragment overlayFragment = ActivityIndicatorOverlayFragment.newInstance("Loading Data");
overlayFragment.show(ft, "activityIndicator");
}
这不起作用。叠加层不会显示。如果我删除dismissActivityIndicatorOverlay()
,则重叠显示后长时间运行操作完成。这并不太令人惊讶:我假设显示新片段是在当前运行循环结束时或下一循环开始时进行的。当然,长时间运行的操作必须在运行循环结束之前完成,因此叠加显示得太晚了......
显而易见的解决方案当然是使用AsyncTask
:
public void onLoadDataClick() {
LoadDataTask loadTask = new LoadDataTask();
loadTask.execute();
}
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
@Override
protected void onPreExecute() {
showActivityIndicatorOverlay();
}
@Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
@Override
protected void onPostExecute() {
dismissActivityIndicatorOverlay();
}
}
我很惊讶,此解决方案也不起作用。它的行为与第一种方法完全相同:叠加层不会出现。删除onPostExecute()
后,操作完成后会显示叠加层。那是为什么?
提供此类活动指标的正确解决方案是什么?
答案 0 :(得分:1)
我建议使用ProgessDialog
。
将ProgressDialog声明为实例变量。类似于:ProgressDialog pDialog;
然后在onCreate()中:
pDialog = new ProgressDialog(this);
//The next two methods will ensure that the user is unable to
//cancel the Progress Dialog unless you explicitly
//do so by calling `pDialog.dismiss();`
pDialog.setCancelable(false);
pDialog.setCanceledOnTouchOutside(false);
像这样修改AsyncTask:
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
@Override
protected void onPreExecute() {
pDialog.setMessage("Loading Data.. Please Wait.");
pDialog.show();
}
@Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
@Override
protected void onPostExecute() {
pDialog.dismiss();
}
}
答案 1 :(得分:1)
ProgressDialog
是这些案件的规范解决方案......
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog mProgress;
@Override
protected void onPreExecute() {
mProgress = new ProgressDialog(context);
mProgress.setTitle("So much to do");
mProgress.setMessage("Doing very much work");
mProgress.setIndeterminate(true);
mProgress.setCancelable(false);
mProgress.show();
}
@Override
protected Void doInBackground(Void... params) {
doVeryMuchWork();
}
@Override
protected void onPostExecute() {
mProgress.dismiss();
}
}
至于您尝试过的解决方案,第一个解决方案因您说明的原因而无效。但第二个应该。
答案 2 :(得分:0)
如果你没有在setContentView(R.layout.main)上精确地做重物,你可以做这样的事情
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
handler = new Handler();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
//Do some heavy stuff
return null;
}
@Override
public void onPostExecute(Void result){
handler.post(new Runnable(){
@Override
public void run(){
setContentView(R.layout.main);
}
});
}
}.execute();
}
或者您可以使用进度对话框
private class LongTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog pd;
Context context;
public LongTask(Context c)
{
this.context = c;
}
@Override
protected void onPreExecute() {
pd = new ProgressDialog(context);
pd.setTitle("Please wait...!");
pd.setMessage("Loding the information");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.show();
}
@Override
protected Void doInBackground(Void... params) {
// do your heavy tasks here
}
@Override
protected void onPostExecute() {
if (pd.isShowing())
pd.dismiss();
}
}
像这样调用AsyncTask
new LongTask(your_activity.this).execute();