【问题标题】:progressDialog app crashes on screen rotationprogressDialog 应用程序在屏幕旋转时崩溃
【发布时间】:2014-07-31 17:28:25
【问题描述】:

我正在开发一个应用程序,我必须在其中实现一个按钮,当单击该按钮时,将开始下载图像并出现一个progressDialog,其中包含一个显示图像下载进度的水平条。下载完成后,进度对话框消失并显示图像。 问题是,当下载进行时(显示progressDialog),如果我旋转屏幕,应用程序崩溃,请问我该如何解决这个问题?

这是我的代码:

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivityProgress extends Activity {

    Button button;

    private ProgressDialog progressDialog;
    ImageView imageView;
    public static final int progress_bar_type = 0;

    private static String file_url = "http://farm1.static.flickr.com/114/298125983_0e4bf66782_b.jpg";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_activity_progress);

        button = (Button) findViewById(R.id.btnProgressBar);

        imageView = (ImageView) findViewById(R.id.my_image);

        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                new DownloadFileFromURL().execute(file_url);
            }
        });
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case progress_bar_type:
            progressDialog = new ProgressDialog(this);
            progressDialog.setMessage("Downloading file. Please wait...");
            progressDialog.setIndeterminate(false);
            progressDialog.setMax(100);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setCancelable(false);
            progressDialog.show();
            return progressDialog;
        default:
            return null;
        }
    }

   @Override
    public void onConfigurationChanged(Configuration newConfig){ 
            super.onConfigurationChanged(newConfig);
            setContentView(R.layout.activity_main_activity_progress);        
    }

    class DownloadFileFromURL extends AsyncTask<String, String, String> {
        @SuppressWarnings("deprecation")
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            showDialog(progress_bar_type);
        }

        @SuppressLint("SdCardPath")
        @Override
        protected String doInBackground(String... f_url) {
            int count;
            try {
                URL url = new URL(f_url[0]);
                URLConnection conection = url.openConnection();
                conection.connect();

                int lenghtOfFile = conection.getContentLength();

                InputStream input = new BufferedInputStream(url.openStream(), 8192);

                OutputStream output = new FileOutputStream("/sdcard/downloadedfile.jpg");

                byte data[] = new byte[1024];

                long total = 0;

                while ((count = input.read(data)) != -1) {
                    total += count;
                    publishProgress(""+(total*100)/lenghtOfFile);

                    output.write(data, 0, count);
                }

                output.flush();

                output.close();
                input.close();

            } catch (Exception e) {
                Log.e("Error: ", e.getMessage());
            }

            return null;
        }

        protected void onProgressUpdate(String... progress) {
            progressDialog.setProgress(Integer.parseInt(progress[0]));
       }

        @SuppressWarnings("deprecation")
        @Override
        protected void onPostExecute(String file_url) {
            dismissDialog(progress_bar_type);

            String imagePath = Environment.getExternalStorageDirectory().toString() + "/downloadedfile.jpg";
            imageView.setImageDrawable(Drawable.createFromPath(imagePath));
        }

    }
}

这些是我的 logcat 错误:

07-31 10:00:48.023: E/MoreInfoHPW_ViewGroup(20485): Parent view is not a TextView
07-31 10:00:49.658: E/MoreInfoHPW_ViewGroup(20485): Parent view is not a TextView
07-31 10:00:49.728: E/ViewRootImpl(20485): sendUserActionEvent() mView == null
07-31 10:00:50.753: E/MoreInfoHPW_ViewGroup(20485): Parent view is not a TextView
07-31 10:00:50.803: E/ViewRootImpl(20485): sendUserActionEvent() mView == null
07-31 10:00:52.688: E/MoreInfoHPW_ViewGroup(20485): Parent view is not a TextView
07-31 10:00:52.803: E/ViewRootImpl(20485): sendUserActionEvent() mView == null
07-31 10:00:52.803: E/ViewRootImpl(20485): sendUserActionEvent() mView == null
07-31 10:00:52.828: E/ViewRootImpl(20485): sendUserActionEvent() mView == null
07-31 10:01:01.018: E/AndroidRuntime(20485): FATAL EXCEPTION: main
07-31 10:01:01.018: E/AndroidRuntime(20485): Process: com.example.progressdownload, PID: 20485
07-31 10:01:01.018: E/AndroidRuntime(20485): java.lang.IllegalArgumentException: no dialog with id 0 was ever shown via Activity#showDialog
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.app.Activity.missingDialog(Activity.java:3214)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.app.Activity.dismissDialog(Activity.java:3199)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at com.example.progressdownload.MainActivityProgress$DownloadFileFromURL.onPostExecute(MainActivityProgress.java:121)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at com.example.progressdownload.MainActivityProgress$DownloadFileFromURL.onPostExecute(MainActivityProgress.java:1)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.os.AsyncTask.finish(AsyncTask.java:632)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.os.AsyncTask.access$600(AsyncTask.java:177)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.os.Handler.dispatchMessage(Handler.java:102)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.os.Looper.loop(Looper.java:157)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at android.app.ActivityThread.main(ActivityThread.java:5293)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at java.lang.reflect.Method.invokeNative(Native Method)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at java.lang.reflect.Method.invoke(Method.java:515)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
07-31 10:01:01.018: E/AndroidRuntime(20485):    at dalvik.system.NativeStart.main(Native Method)

谢谢。

【问题讨论】:

  • 您是否在 AndroidManifest.xml 的活动标签中添加了android:configChanges="keyboardHidden|orientation|screenLayout|screenSize"
  • 使用 loader 代替 asyncTask 会更高效
  • 我添加了 logcat .. 我需要在没有 android:configChanges="keyboardHidden|orientation|screenLayout|screenSize" ...
  • progressDialog = new ProgressDialog(this);在对 getApplicationContext 的更改中,或者在此更改您的 Activity 名称
  • 我把那个放在哪里?如何 ?抱歉,我在 android 上呆了 1 周,所以我是新手……

标签: android


【解决方案1】:

那是因为对话框会变成空。 您可以使用两种不同的方式解决这些问题。

  1. 停止重新创建整个活动。即设置 您可以通过在应用程序的清单文件中添加以下内容来避免重新创建活动。

    android:configChanges="orientation|keyboardHidden|screenSize" 如下

    <activity
        android:name=".your activity"
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:label="@string/app_name" >
    </activity>
    
  2. 像往常一样在 onPreExecute/onPostExecute 期间显示/关闭 AsyncTask 中的对话框,但在方向更改的情况下,在活动中创建/显示对话框的新实例并将其引用传递给任务。请参考以下代码并执行必要的步骤。

公共类 MainActivity 扩展 Activity {

    private Button mButton;
    private MyTask mTask = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        MyTask task = (MyTask) getLastNonConfigurationInstance();
        if (task != null) {
            mTask = task;
            mTask.mContext = this;
            mTask.mDialog =  new ProgressDialog(MainActivityProgress.this);
            mTask.mDialog.setMessage("Please wait...");
            mTask.mDialog.setIndeterminate(false);
            mTask.mDialog.setMax(100);
            mTask.mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            mTask.mDialog.setCancelable(true);
            mTask.mDialog.show();
        }

        mButton = (Button) findViewById(R.id.button1);
        mButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                mTask = new MyTask(MainActivity.this);
                mTask.execute();
            }
        });
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        String str = "null";
        if (mTask != null) {
            str = mTask.toString();
            mTask.mDialog.dismiss();
        }
        Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
        return mTask;
    }

    private class MyTask extends AsyncTask<Void, Void, Void> {
        private ProgressDialog mDialog;
        private MainActivity mContext;

        public MyTask(MainActivity context) {
            super();
            mContext = context;
        }

        protected void onPreExecute() {
                mDialog = new ProgressDialog(MainActivityProgress.this);
        mDialog.setMessage("Please wait...");
        mDialog.setIndeterminate(false);
        mDialog.setMax(100);
        mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mDialog.setCancelable(true);
        mDialog.show();
        }

        protected void onPostExecute(Void result) {
            mContext.mTask = null;
            mDialog.dismiss();
        }

        @Override
        protected Void doInBackground(Void... params) {
            SystemClock.sleep(5000);
            return null;
        }
    }
}

好的,所以在编辑完你的代码后,它会如下所示:

公共类 MainActivityProgress 扩展 Activity {

Button button;

public static final int progress_bar_type = 0;

private static String file_url = "http://farm1.static.flickr.com/114/298125983_0e4bf66782_b.jpg";
private DownloadFileFromURL mTask = null;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main_activity_progress);
    button = (Button) findViewById(R.id.btn_download);
    DownloadFileFromURL task = (DownloadFileFromURL) getLastNonConfigurationInstance();
    if (task != null) {
        mTask = task;
        mTask.mContext = this;
        mTask.mDialog = ProgressDialog.show(MainActivityProgress.this,
                "Downloading file.", "Please wait...", true);
    }

    button.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            mTask = new DownloadFileFromURL(MainActivityProgress.this);
            mTask.execute(file_url);
        }
    });
}

@Override
public Object onRetainNonConfigurationInstance() {
    String str = "null";
    if (mTask != null) {
        str = mTask.toString();
        mTask.mDialog.dismiss();
    }
    return mTask;
}

class DownloadFileFromURL extends AsyncTask<String, String, String> {

    private ProgressDialog mDialog;
    private MainActivityProgress mContext;

    public DownloadFileFromURL(MainActivityProgress context) {
        mContext = context;
    }

    protected void onPreExecute() {
        mDialog = ProgressDialog.show(MainActivityProgress.this,
                "Downloading file.", "Please wait...", true);
    }

    @Override
    protected String doInBackground(String... f_url) {
        SystemClock.sleep(5000);
        int count;
        try {
            URL url = new URL(f_url[0]);
            URLConnection conection = url.openConnection();
            conection.connect();

            int lenghtOfFile = conection.getContentLength();

            InputStream input = new BufferedInputStream(url.openStream(),
                    8192);

            OutputStream output = new FileOutputStream(
                    "/sdcard/downloadedfile.jpg");

            byte data[] = new byte[1024];

            long total = 0;

            while ((count = input.read(data)) != -1) {
                total += count;
                publishProgress("" + (total * 100) / lenghtOfFile);

                output.write(data, 0, count);
            }

            output.flush();

            output.close();
            input.close();

        } catch (Exception e) {
            Log.e("Error: ", e.getMessage());
        }

        return null;
    }
     protected void onProgressUpdate(String... progress) {
         mDialog.setProgress(Integer.parseInt(progress[0]));
       }
    @Override
    protected void onPostExecute(String file_url) {
        mContext.mTask = null;
        if (mDialog.isShowing()) {
            mDialog.dismiss();
        }

        String imagePath = Environment.getExternalStorageDirectory()
                .toString() + "/downloadedfile.jpg";
        Log.e("imagePath: ", imagePath);
        // imageView.setImageDrawable(Drawable.createFromPath(imagePath));
    }

}

}

【讨论】:

  • 我尝试在我的应用程序上执行第二种方法..它没有成功..如果你知道如何实现它,你能告诉我吗?谢谢
  • 检查我的编辑。您可以删除此行 SystemClock.sleep(5000);
  • progressdialog 没有像我的代码那样显示......当我旋转加载的图像时消失
  • 看起来我也需要编写你的应用程序。顺便说一句,你可以通过下载我上传的这个应用程序来测试这段代码dropbox.com/s/tbiu0aqxwcjw0ah/Test.apk
  • 帮我解决它当然是完美的..我是新手,我现在真的很困惑!非常感谢,我很感激
【解决方案2】:

当您旋转设备时,系统会破坏之前方向的所有 UI,并为新方向重新创建它。你可以阅读更多here

所以我认为你应该重新创建你的旋转对话框。您可以在 onConfigurationChanged 方法中执行此操作。

【讨论】:

  • 对不起,我是新手……你能告诉我怎么做吗?我真的不知道
  • 你需要在活动中保存你的任务实例(这里是一些技术stackoverflow.com/questions/3821423/…)。然后在 onConfigurationChanged 中运行此代码: if (task.getStatus() == AsyncTask.Status.RUNNING) { showDialog(progress_bar_type);)} 您还应该检查对话框在 prugressUpdate 方法中是否为空
【解决方案3】:
    <activity
        android:name="com.example.one.MainActivityProgress"
        android:configChanges="orientation|screenSize"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

android:configChanges="orientation|screenSize" 在你的清单中做你的问题解决了

【讨论】:

  • 非常感谢,但我在 cmets 中说过我不应该那样做......还有其他解决方案吗?
【解决方案4】:

查看this 博客,了解如何处理有关方向更改的进度对话框的完整解决方案。希望对您有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2019-12-27
    相关资源
    最近更新 更多