Android activity-reset after picture taken (orientation?) - android

Well basically, I press a button, this opens up your default camera app by using the camera intent. After a picture is taken, it will save the things needed and redirect to another activity.
In this activity, I have an AsyncTask that can succesfully upload pictures. So what is my problem you may ask. My problem is that it re-creates my activity and therefore reset my ProgressDialog together with it. ( It runs the activity, does the aSyncTask, dies before it can finish it and re-creates my Activity to do the asynctask once again. )
It does not always do this. I think it does this because it changes the Orientation from the phone from Landscape to Portrait. ( I have a Samsung. When I go to the Camera it changes to landscape and when I finish it, it goes back to portrait. )
I've already done my homework and added these things to my manifest:
android:configChanges="orientation|keyboardHidden"
android:screenOrientation="portrait" >
I've made sure to "lock" my app in the portrait orientation but I still see my app change orientation and I believe this is why my activity gets re-created.
I was planning to add all kinds of checks but I believe this is not the right way to handle this situation, since it sometimes does not re-create the activity.
The check I am talking about is to use:
protected void onSaveInstanceState(Bundle outState) {
outState.putString("started", "1");
}
Anyway, can somebody help me out? I just want it to load the activity without it self-destructing on me.
PS: The VM doesn't have any problems. The VM loads the activity and finishes it without re-creating it.
PPS: Did extra testing, on my Samsung if I keep it on landscape-mode it will work. So it is definately the camera that is destroying my activity with it's orientation change.

I had the same issue, turns out you also need to listen for screen size changes in API level 13 or higher as explained here; https://stackoverflow.com/a/11483806
android:configChanges="orientation|screenSize"

For this to fix, I had to use following in my manifest file:
android:screenOrientation="portrait"
android:launchMode="singleTop"
android:configChanges="keyboardHidden|orientation|screenSize"

Try creating a fragment activity to handle displaying and updating the progress dialog
In the fragment activity make sure and set "setRetainInstance(true);" This will make sure it isn't destroyed when the main activity gets created/destroyed.
It's probably a good idea to put the entire image capture process inside this fragment, including the asynctask. Make sure you don't reference the parent activity's context from within the doInBackground() in the AsyncTask. If you do this and the orientation changes (i.e. the activity is destroyed) it will throw an error.
here's a rough example:
public class MyFragment extends FragmentActivity {
private ProgressBar mProgressBar;
private boolean mAsyncTaskActive = false;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
// grab reference to progress bar
mProgressBar = (ProgressBar) getActivity().findViewById(R.id.my_progress_bar);
// check to see if the async task is active and set the progress bar visibility accordingly
if (mAsyncTaskActive) {
mProgressBar.setVisibility(View.VISIBLE);
mProgressBarText.setVisibility(View.VISIBLE);
}
}
// this method is called from your main activity when the user does something (i.e. clicks a button)
// make sure you have already instantiated the fragment
public void startSomething() {
if (mAsyncTaskActive == false) {
mProgressBar.setVisibility(View.VISIBLE);
new MyAsyncTask().execute();
mAsyncTaskActive = true;
}
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
Context applicationContext;
#Override
protected Void doInBackground(String... params) {
// do stuff
publishProgress(//some number);
return null;
}
#Override
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
}
You should also take a look at how to implement fragments if you're not already familiar. The Android dev blog has a good post on DialogFragments, same priniciples. http://android-developers.blogspot.com/2012/05/using-dialogfragments.html

Related

Progress dialog in async task is not shown anymore after screen rotation

I am using an async task for uploading pictures to a remote server. To show the progress to the user I am using a progress dialog. This progress dialog is created at the preExecute method of the async task class.
When the user rotates the screen, the progress dialog disappears but the async task is still running. The activity holds a static reference to the async task so I do know that the task is still running. How can I now show up the progress dialog again? I tried the following:
The create method of the activity:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
if(task != null) {
Status status = task.getStatus();
if(status == Status.RUNNING) {
task.updateViewContext(this);
}
}
the constructor of my async task class:
public UploadTask(UploadPicturesActivity activity) {
this.context = activity;
dialog = new ProgressDialog(activity);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
}
the preexcetue method of my asnyc task class:
protected void onPreExecute() {
this.dialog.show();
}
and trying to show the dialog again (does not work):
public void updateViewContext(UploadPicturesActivity activity) {
this.context = activity;
dialog.show();
}
Regards
Michael
Why don't you add attribute android:configChanges="orientation" to the activity declaration in the AndroidManifest.xml file.
The purpose of the android:configChanges attribute is to prevent an activity from being recreated when it's really required.
It won't dismiss dialog when screen orientation changes.
Beginning with Android 3.2 (API level 13), the "screen size" also changes when the device
switches between portrait and landscape orientation. Thus, if you want to prevent runtime
restarts due to orientation change when developing for API level 13 or higher (as declared by the
minSdkVersion and targetSdkVersion attributes), you must include the "screenSize" value in
addition to the "orientation" value.That is, you must declare android:configChanges="orientation|screenSize"
This is because Android destroys your activity and restarts it on rotation. This means all views, dialogs, etc are destroyed. But a running thread can't be. The best solution for this is to add android:configChanges="orientation|screenSize" to your activity in the manifest, this will turn off this behavior for your activity. It will still redraw your activity correctly though, so long as you don't have different layouts for landscape and portrait.

how to retain the state of activity in android

How do I retain the state of an activity in android? I have two layouts for portrait and landscape in layout and layout-land. I am loading the value from service at the time I am showing progress dialog. If loaded user rotates the device to landscape at the time also loading. How do I avoid that? user typed content in webview that also refreshed. How do I avoid that, can anybody provide an example?
Thanks
When orientation changes, the Activity is reloaded by default. If you do not want this behavior then add this to the Activity definition in your manifest:
android:configChanges="orientation|keyboardHidden"
For more detail, see Handling Runtime Changes
You can use the onRetainNonConfigurationChange() callback to store arbitrary data. It is called just before your application is about to be recreated.
Then, in onCreate() just check if some data were put aside by calling getLastNonConfigurationInstance() that returns the Object you put aside or null.
See this article on android developers.
Here's a sample borrowed from the link above:
#Override
public Object onRetainNonConfigurationInstance() {
//this is called by the framework when needed
//Just return what you want to save here.
return MyBigObjectThatContainsEverythingIWantToSave;
}
Automagic restore of previously saved state:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final MyDataObject MyBigObjectThatContainsEverythingIWantToSave = (MyDataObject) getLastNonConfigurationInstance();
if (MyBigObjectThatContainsEverythingIWantToSave == null) {
//No saved state
MyBigObjectThatContainsEverythingIWantToSave = loadMyData();
} else {
//State was restored, no need to download again.
}
...
}
When orientation changes, the Activity is reloaded by default. If you do not want this behavior then add this to the Activity definition in your android manifest file :
android:configChanges="orientation|screenSize|keyboardHidden"

Why is onCreate called twice when doing screen rotation from landscape to portrait? [duplicate]

I need to handle orientation changes in my Android application. For this purpose I decided to use OrientationEventListener convenience class. But his callback method is given somewhat strange behavior.
My application starts in the portrait mode and then eventually switches to the lanscape one. I have some custom code executing in the callback onOrientationChanged method that provides some additional UI handling logic - it has a few calls to findViewById.
What is strange is that when switching back from landscape to portrait mode onOrientationChanged callback is called twice, and what's even worse - the second call is dealing with bad Context - findViewById method starts returning null. These calls are made right from the MainThread
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listener = new OrientationListener();
}
#Override
protected void onResume() {
super.onResume();
// enabling listening
listener.enable();
}
#Override
protected void onPause() {
super.onPause();
// disabling listening
listener.disable();
}
I've replicated the same behavior with a dummy Activity without any logic except for one that deals with orientation hadling.
I initiate orientation switch from the Android 2.2 emulator by pressing Ctrl+F11
What could be wrong?
Upd:
Inner class that implements OrientationEventListener
private class OrientationListener extends OrientationEventListener {
public OrientationL() {
super(getBaseContext());
}
#Override
public void onOrientationChanged(int orientation) {
toString();
}
}
}
This is a documented bug in the emulator ONLY. A real device will not exhibit this double-lifecycle-events behavior. I had the same issue a while ago and it disappears on a real device.
I would suggest ignoring the problem if you can by only testing orientation changes in one direction until you get your hands on a physical phone. Otherwise you might be able to "skip" the second set of lifecycle calls by keeping a static boolean around indicating you've already gone through the first set.
See this issue report for more info.
Have you tried using onConfigurationChanged?
#Override
public void onConfigurationChanged(Configuration newConfig) {
if(newConfig.equals(Configuration.ORIENTATION_LANDSCAPE)…
Add android:configChanges="orientation" in manifest file in activity tag like
<activity android:label="#string/app_name"
android:configChanges="orientation"
android:name=".com.androidpeople">

Problems when handling orientation changes

I need to handle orientation changes in my Android application. For this purpose I decided to use OrientationEventListener convenience class. But his callback method is given somewhat strange behavior.
My application starts in the portrait mode and then eventually switches to the lanscape one. I have some custom code executing in the callback onOrientationChanged method that provides some additional UI handling logic - it has a few calls to findViewById.
What is strange is that when switching back from landscape to portrait mode onOrientationChanged callback is called twice, and what's even worse - the second call is dealing with bad Context - findViewById method starts returning null. These calls are made right from the MainThread
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
listener = new OrientationListener();
}
#Override
protected void onResume() {
super.onResume();
// enabling listening
listener.enable();
}
#Override
protected void onPause() {
super.onPause();
// disabling listening
listener.disable();
}
I've replicated the same behavior with a dummy Activity without any logic except for one that deals with orientation hadling.
I initiate orientation switch from the Android 2.2 emulator by pressing Ctrl+F11
What could be wrong?
Upd:
Inner class that implements OrientationEventListener
private class OrientationListener extends OrientationEventListener {
public OrientationL() {
super(getBaseContext());
}
#Override
public void onOrientationChanged(int orientation) {
toString();
}
}
}
This is a documented bug in the emulator ONLY. A real device will not exhibit this double-lifecycle-events behavior. I had the same issue a while ago and it disappears on a real device.
I would suggest ignoring the problem if you can by only testing orientation changes in one direction until you get your hands on a physical phone. Otherwise you might be able to "skip" the second set of lifecycle calls by keeping a static boolean around indicating you've already gone through the first set.
See this issue report for more info.
Have you tried using onConfigurationChanged?
#Override
public void onConfigurationChanged(Configuration newConfig) {
if(newConfig.equals(Configuration.ORIENTATION_LANDSCAPE)…
Add android:configChanges="orientation" in manifest file in activity tag like
<activity android:label="#string/app_name"
android:configChanges="orientation"
android:name=".com.androidpeople">

Dismiss dialog after screen orientation change

1) I launch a background task (via AsyncTask)
new FindJourneyTask().execute(); // FindJourneyTask extends AsyncTask
2) Still in the main thread (just before new thread is launched) I create a dialog with showDialog(dialogId)
// this method is in FindJourneyTask
protected void onPreExecute() {
showDialog(DIALOG_FINDING_JOURNEY);
}
3) Screen orientation changes and the Activity is recreated
4) How can I now dismiss the dialog from the FindJourneyTask? Calling dismissDialog(dialogId) does nothing.
// this method is in FindJourneyTask
protected void onPostExecute(FindJourneyResult result) {
dismissDialog(DIALOG_FINDING_JOURNEY); // does nothing
}
This is a common problem, and there are no real good solutions. The issue is that on screen orientation change, the entire Activity is destroyed and recreated. At the same time, the Dialog you previously had is re-created in the new Activity, but the old background task still refers to the old Activity when it tries to dismiss the dialog. The result is that it dismisses a dialog which was long ago destroyed, rather than dismissing the dialog the new orientation created.
There are three basic solutions:
Override the default orientation-handling code so that your Activity is not destroyed upon rotation. This is probably the least satisfactory answer, as it blocks a lot of code that is automatically run upon orientation changes.
Create a static member variable of your Activity that references the Activity itself, so you can call STATIC_ACTIVITY_VARIABLE.dismissDialog().
Code a solution in which the background task keeps track of the current Activity and updates itself as necessary.
These three solutions are discussed at length here: http://groups.google.com/group/android-developers/browse_thread/thread/bf046b95cf38832d/
There is a better solution to this problem now which involves using fragments.
If you create a dialog using DialogFragment, then this fragment will be responsible for maintaining your dialog's lifecycle. When you show a dialog, you supply a tag for your fragment (DialogFragment.show()). When you need to access your dialog, you just look for the necessary DialogFragment using FragmentManager.findFragmentByTag instead of having a reference to the dialog itself.
This way if device changes orientation, you will get a new fragment instead of the old one, and everything will work.
Here's some code based also in #peresisUser answer:
public void onSaveInstanceState(Bundle outState) {
AppCompatActivity activity = (AppCompatActivity) context;
FragmentManager fragmentManager = activity.getSupportFragmentManager();
DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag("your_dialog_tag");
if(dialogFragment!=null) {
Dialog dialog = dialogFragment.getDialog();
if(dialog!=null && dialog.isShowing()) {
dialogFragment.dismiss();
}
}
}
This is long after the question was asked and answered, but i stumbled upon this problem also and wanted to share my solution...
I check in onSavedInstance() which runs on orientation change, whether the dialog is showing or not with dialog.isShowing(), and pass it into outState variable. Then in your onCreate(), you check this var if it's true. If it is, you simply dismiss your dialog with dialog.dismiss()
Hope this helps others :()
I tried adding setRetainInstance(true); on OnCreate function of DialogFragment. This will cause dialog to dismiss on rotation.
Just add this line to specific activity in your Manifest to solve this problem android:configChanges="orientation|screenSize|smallestScreenSize"
like this,
<activity
android:name=".PDFTools"
android:exported="false"
android:configChanges="orientation|screenSize|smallestScreenSize"
android:theme="#style/Theme.DocScanner.NoActionBar" />

Categories

Resources