0

I am working on an application where i have to implement a button, and when the button is clicked, an image download starts and a progressDialog appears containing a horizontal bar that shows the image download progress. When the download is done, the progress dialog disappears and the image is shown. The problem is that when the download is going on (progressDialog is shown) , if i rotate my screen, the app crashes, how can i solve this problem please ?

This is my code :

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));
        }

    }
}

These are my logcat errors :

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)

Thanks.

user3783005
  • 542
  • 1
  • 9
  • 20
  • Did you add `android:configChanges="keyboardHidden|orientation|screenLayout|screenSize"` within your activity tag of AndroidManifest.xml – SathishKumar Jul 31 '14 at 06:54
  • using loaders instead of asyncTask will be more efficient for you – nobalG Jul 31 '14 at 06:55
  • i added the logcat .. and i need to do it without the android:configChanges="keyboardHidden|orientation|screenLayout|screenSize" ... – user3783005 Jul 31 '14 at 07:02
  • progressDialog = new ProgressDialog(this); in this change to the getApplicationContext or instead on this give your Activity name – Anuja Jul 31 '14 at 07:06
  • where do i put that ? and how ? sorry its been 1 week in android for me so i'm new ... – user3783005 Jul 31 '14 at 07:08

4 Answers4

4

That is because of dialog will became null. You can resolve these using two different ways.

  1. Stop recreating whole activity. i.e setting You can avoid activity recreation by adding following to your application's manifest file.

    android:configChanges="orientation|keyboardHidden|screenSize" As follows

    <activity
        android:name=".your activity"
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:label="@string/app_name" >
    </activity>
    
  2. Show/dismiss the dialog within AsyncTask during onPreExecute/onPostExecute as usual, though in case of orientation-change create/show a new instance of the dialog in the activity and pass its reference to the task. Refer below code and do necessary steps.

public class MainActivity extends 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;
        }
    }
}

Ok, So after editing your code it will look as below:

public class MainActivityProgress extends 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));
    }

}

}

user1621629
  • 765
  • 7
  • 19
0

When you are rotating your device system destroys all the UI that was in previous orientation and recreates it for new orientation. You can read more here.

So I think you should recreate your dialog on rotation. You can do it in onConfigurationChanged method.

Sergey Pekar
  • 8,555
  • 7
  • 47
  • 54
  • i'm sorry but i am new to this ... can you tell me how to do it ? i really have no idea – user3783005 Jul 31 '14 at 07:11
  • You need to hold instance of your task in the activity (here some technics http://stackoverflow.com/questions/3821423/background-task-progress-dialog-orientation-change-is-there-any-100-working). And then in onConfigurationChanged run this code : if (task.getStatus() == AsyncTask.Status.RUNNING) { showDialog(progress_bar_type);)} also you should check is dialog is not null in prugressUpdate method – Sergey Pekar Jul 31 '14 at 07:33
0
    <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" do in your manifest your problem solved

0

Check out this blog for complete solution on how to handle progress dialogs on orientation changes. Hope it helps.

CodeFury
  • 1,520
  • 16
  • 29