如何在启动新Activity时显示ProgressDialog?

9
目标:拥有一个ProgressDialog,直到下一个Activity完全加载并显示在屏幕上都显示“Loading...”。
尝试使用设置为源Activity的ProgressDialog上下文和活动。也尝试过使用getApplicationContext()和getParentContext()。最后两种方法会出现异常。需要这样做是因为目标Activity由于非简单布局文件而渲染缓慢。(由于组织问题,现在无法修复。)结果发现目标Activity需要1-2秒才能OnCreate,然后屏幕变黑,需要5秒以上才能绘制。渲染速度很慢。使用Hierarchy Viewer进行了审核,看到很多红球,但现在无法修复。
阅读了一些相关信息,但没有找到解决方法。例如获取Context的各种方法之间有什么区别? 例如,这两个都会崩溃。使用源Activity的“this”也不起作用。
// Context parentContext = this.getParent().getBaseContext();    
Context parentContext = this.getApplicationContext();
ProgressDialogMenuable theProgressDialog = new ProgressDialogMenuable(parentContext,this);
theProgressDialog.setTitle("yeeha");
theProgressDialog.setMessage("weewah");
theProgressDialog.setIndeterminate(true);
theProgressDialog.setCancelable(true);
theProgressDialog.show();

此外,奇怪的是,当我执行以下操作时什么都不会发生: theProgressDialog.show(); ActivityHelper.changeActivity(this, v, InsMyHoldingsActivity.class, extraMap, -1, -1); 用户单击按钮以显示下一个活动,但ProgressDialog与Activity启动冲突,除了按钮在ontouch时变成黄色之外,实际上什么也没有发生。下面的按钮可以正常工作。删除ProgressDialog创建后,它可以正常工作。没有记录任何控制台消息。对开发人员来说有点令人不安。

4
在您的新活动中创建一个异步任务,在其中进行所有处理,然后在 "post execute" 中设置布局元素。在 "on create" 中显示进度条,在 "post execute" 中关闭它。 - Vrashabh Irde
让我试试。情况是我只能子类化(而不能更改)目标Activity。所以,这可能有效。 - maxweber
如果您发布解决方案,那么我会接受。我认为ProgressDialog不能跨越活动的生命周期(超过一个活动); 但是可以使用此方法向用户传达它,即在Activity A中使用一个PDlg,然后在ActivityB中使用另一个,就像您所说的那样。实际上,我使用了与AsynTask不同的语法,但从语义上讲,我认为它是相同的。最终的Runnable r = new Runnable() { public void run() { setupActivityDisplay(); // 需要一段时间的事情 theProgressDialog.dismiss(); } }; (new Handler()).postDelayed(r, 1000); - maxweber
更多的研究表明,在 Activity 布局完成之前无法显示 ProgressDialog。简单来说,当出现复杂的布局时,用户会看到黑屏(空白屏幕)一段时间。仍在进行研究。 - maxweber
有一种方法可以显示ProgressDialog。在onCreate之后。只需从onCreate中删除布局setContentView(调用即可。稍后再执行它。 - maxweber
将 setContentView( 调用移动到 onStart 并没有帮助。实际上,似乎必须完成 onResume 才能应用布局。ProgressDialog 也不会出现;因此,AsyncTask 是使其最好工作的方法。 - maxweber
3个回答

12
您可以像这样显示进度对话框 -
定义此处。
private ProgressDialog pd = null;

在你的活动类中

将这个放在你的onCreate方法中(别在这里直接设置setContentView)

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.pd = ProgressDialog.show(this, "Fancy App",
                    "Loading...Please wait...", true, false);
        // Start a new thread that will download all the data
        new IAmABackgroundTask().execute();

    }

// 后台重量级处理

class IAmABackgroundTask extends
        AsyncTask<String, Integer, Boolean> {
    @Override
    protected void onPreExecute() {
        // showDialog(AUTHORIZING_DIALOG);
    }

    @Override
    protected void onPostExecute(Boolean result) {

        // Pass the result data back to the main activity
        ActivityName.this.data = result;

        if (ActivityName.this.pd != null) {
            ActivityName.this.pd.dismiss();
        }

        setContentView(R.layout.main);


    }

    @Override
    protected Boolean doInBackground(String... params) {

        //Do all your slow tasks here but dont set anything on UI
                    //ALL ui activities on the main thread 

        return true;

    }

}

另外,请查看以下内容:http://developer.android.com/training/improving-layouts/index.html 以优化布局性能。 同时,使用Traceview查找瓶颈。


这是正确的方法。将缓慢的渲染延迟到稍后。由于使用Handler的AsyncTask作为“post”无法正常工作(怀疑如果没有其他内容,AsyncTask只能从MessageQueue中运行?还没有找到答案),所以必须进行调整。实际上我需要两个AsycTasks。一个用于设置布局,然后第二个填充数据。感谢Slartibartfast的帖子。 - maxweber
没问题。如果解决了您的问题,请接受它作为答案,并欢迎来到 SO :) - Vrashabh Irde

3

有两种方法:

第一种方法是使用Async Task

如果你正在进行重型任务,例如从服务器加载数据或解析XML,则使用AsynTask<>。如果你想从ActivityA调用ActivityB,那么

*步骤1*创建一个AsyncTask类。将所有后台任务写在doBackground()方法中,在任务完成后,你想要调用的Activity的代码写在onPostExecute()后执行方法中。

import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.view.View;



public class LoadingDataFromServer extends AsyncTask {
    Context currentContext = null;

    boolean isCancelled = false;


    public LoadingDataFromServer(Context context) {
        currentContext = context;

    }

    @Override
    protected void onPreExecute() {
        if (DashboardActivity.progressBarLayout != null) {
            DashboardActivity.progressBarLayout.setVisibility(View.VISIBLE);
            // Log.i(TAG,".....Now make progress bar visible.....");
        }

        super.onPreExecute();
    }

    @Override
    protected Object doInBackground(Object... params) {
        // do background processing

        try {
// do background tasks eg sever communication
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Object result) {
        // TODO Auto-generated method stub
        // progressDialog.dismiss();

        // call second Activity
        Intent i = new Intent(currentContext, com.ActvityB.class);
        super.onPostExecute(result);
    }

    @Override
    protected void onCancelled() {
        // TODO Auto-generated method stub
        isCancelled = true;
        super.onCancelled();
    }

}

第二步,在你想要跳转到新活动的活动中(例如在ActivityA中),调用AsynTask的execute()。

new LoadingDataFromServer(context).execute(null);

第二种方法

首先展示进度对话框。 创建一个线程来执行所有后台任务。当线程完成任务时,取消进度对话框并调用下一个活动。

或者

当线程完成任务时,调用下一个活动并传递此对象(进度对话框),在新活动中关闭此对话框。


接受此答案作为最佳方法。实际上,布局渲染步骤对于开发人员来说是一个黑洞(和黑屏)。根据我所做的研究,无法在两个活动之间显示ProgressDialog。类似的问题也没有人找到解决办法。http://stackoverflow.com/questions/6563531/how-to-display-progressdialog-when-preparing-to-show-another-activity?rq=1 和 https://dev59.com/aFHTa4cB1Zd3GeqPUca1?rq=1。流程:1-用户触摸,新的Activity对象2秒。2-渲染布局5秒。3-数据检索0秒。4-UI填充2秒。在模拟器中。 - maxweber
看起来可能可以使用ActivityGroup,但现在已经被弃用了。http://developer.android.com/reference/android/app/ActivityGroup.html - maxweber
我按照第一位发帖者告诉我的方式,在AsyncTask中进行了布局渲染。它有效了。 - maxweber

0

这是我的代码,可以帮助你。

在这里,我只发布了AsyncTask的第一个方法,即onPreExecute

User_AsyncTask扩展了AsyncTask:

public class User_AsyncTask extends AsyncTask<String, String, String>
    {
        String response = "";

        @Override
        protected void onPreExecute()
        {
            try
            {
                if (progressDialog != null)
                    progressDialog.cancel();
            }
            catch (Exception e)
            {

            }
            progressDialog = ProgressDialog.show(DisplayDetails.this, "", "Please wait...", true, true);
            progressDialog.setCancelable(false);
            progressDialog.show();
        }

如果这个回答有帮助,请给它评分。 - Vaibhav Joshi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接