8

im going to re-ask this question because there is SO much bad information out there its really depressing. the short story is that i dont want anything to change or happen when the device orientation changes. 2 of the most popular "solutuions" given to this problem are:

1.You could lock the activity in one orientation by addingandroid:screenOrientation="portrait" (or "landscape") to in your manifest.

2.You could tell the system that you meant to handle screen changes for yourself by specifying android:configChanges="screenOrientation" in the tag. This way the activity will not be recreated, but will receive a callback instead (which you can ignore as it's not useful for you).

NEITHER of those work. so let me explain my particular problem in more detail...

i am experimenting with a VERY simple app as a learning exercise. i have a text file on a server. the text file has 1 thing in it: a single integer on a single line. this number is the number of image files also stored on this server, and the images are all named 0.jpg, 1.jpg, 2.jpg etc.

ALL of my code is in the onCreate method of my activity (like i said its a simple app).

the app does the following when it runs:

reads the number from the text file. generate a random number from zero to the number in the file. loads a random image into an imageview by using the random number in the URL.

when the screen rotates i do not want all of that to happen again. i simply want NOTHING to happen... except that the screen should obviosuly rotate and the image should scale to fit, which it does. but every time the screen rotates all of that code runs and a new random image is selcted. can someone please give me a simple solution with the working code to fix this? i learn by seeing so if you cant provide a code example it wont help.

thanks in advance.

ps... im not looking for a different way of doing what im doing, thats not the point. im looking to FIX the way im currently doing it.

Jimmy D
  • 5,282
  • 16
  • 54
  • 70
  • Ah, you must be doing something wrong in your code: `android:configChanges="screenOrientation"` IS the way to handle what you want to do. If you've configured it right your `onCreate` will NOT be re-run. If its re-run then you've configured it wrong. Put your code in the body of the question and I'm guessing the answer should be pretty straightforward. – Femi May 06 '11 at 16:46
  • 1
    hhmmm... what are you saying im configuring wrong? if the ONLY thing youre saying i have to do is to add that single line to my manifest, how could i be doing that wrong? – Jimmy D May 06 '11 at 16:57
  • That's what I'm unsure about, and why I asked to see your code. I have working code that does not fire `onCreate()` everytime you change orientation. – Femi May 06 '11 at 16:59
  • what parameter is it? `android:configChanges="orientation"` or `android:configChanges="screenOrientation"`? – auraham Mar 11 '13 at 14:36

5 Answers5

11

The solution using android:configChanges="orientation" won't work unless the application has an API level of 12 or lower.

In API level 13 or above, the screen size changes when the orientation changes, so this still causes the activity to be destroyed and started when orientation changes.

Simply add the "screenSize" attribute like I did below:

<activity>
    android:name=".YourActivityName"
    android:configChanges="orientation|screenSize">
</activity>

Now, when your change orientation (and screen size changes), the activity keeps its state and onConfigurationChanged() is called. This will keep whatever is on the screen (ie: webpage in a Webview) when the orientation chagnes.

Learned this from this site: http://developer.android.com/guide/topics/manifest/activity-element.html

Also, this is apparently a bad practice so read the link below about Handling Runtime Changes:

http://developer.android.com/guide/topics/resources/runtime-changes.html

corbin
  • 2,797
  • 3
  • 18
  • 17
  • Hi! I am using different layouts for portrait and landscape mode so i can't use `android:configChanges`, is there any other solution? – Shajeel Afzal Jun 11 '15 at 19:30
3

A very similar question is here: Don't reload application when orientation changes

Anyway, first of all you should change the code from onCreate to another method and divide it by "create random number and load image from the net" and "set image to view".

You have a Bitmap on the activity, that you verify if it's null everytime the activity starts.

If it is, do all. If it's not, just set the ImageView or whatever with the Bitmap you have.

To avoid destroying the Bitmap when it rotates use:

    Bitmap image = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);

 image = (Bitmap) getLastNonConfigurationInstance();

     if(bitmap == null){
         image = downloadImage();
      }
     setImage(bitmap);
}


@Override
public Object onRetainNonConfigurationInstance() {
    return bitmap;
}

This works, i'm 100% sure.

Community
  • 1
  • 1
neteinstein
  • 17,529
  • 11
  • 93
  • 123
  • 1
    yeah, thats MY question. none of the solutions work. people just keep posting this stuff without ever testing the code. kinda ridiculous. – Jimmy D May 06 '11 at 16:56
  • @NeTeInStEiN: that's JJD's same question. – techi.services May 06 '11 at 16:56
  • Note that the data you retrieve here should only be used as an optimization for handling configuration changes. You should always be able to handle getting a null pointer back, and an activity must still be able to restore itself to its previous state (through the normal onSaveInstanceState(Bundle) mechanism) even if this function returns null. – techi.services May 06 '11 at 17:18
  • this is unreal. i cant return a bitmap from my DownLoadImage function because i do the work in a try/catch block. if "return" is IN the try it isnt recognized and if its OUT of the try the return doesnt recognize the bitmap varialbe that was created IN the try – Jimmy D May 06 '11 at 18:18
  • You need to review Java. You have to define the variable before the try not to be only on the try context Bitmap name = null; try{ name = ... }catch(Exception e){ ... } return name; – neteinstein May 06 '11 at 18:43
  • whew. i think this might actually be working so thank you. what should i have as a return when i catch an exception? and in the finally? – Jimmy D May 06 '11 at 19:02
  • I can't tell you that... it depends on the logic that you have implemented. On catch probably you should do some logging to know something was wrong, and return null (on the other side you should check for null. On finally close whatever http connection you used.. or something like this. Glad i helped. But you should read some java stuff, or else you'll have a lot of problems. If the question is answered you should mark it as such. – neteinstein May 07 '11 at 15:13
0

what worked for me is declaring one of the class variables as static. it turns out that static class variables are initialized once when the application is being loaded, but when the application is being reloaded, these won't be initialized again.

these variables could hold a state or an object that you don't want to reinitialize. I can't say that this is not super elegant, but tested and worked for me.

mvalenci
  • 31
  • 5
0

Save the image details in your onPause() or onStop() and use it in the onCreate(Bundle savedInstanceState) to restore the image.

More info on the actual process is detailed here http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle as it is different in Honeycomb than previous Android versions.

techi.services
  • 8,473
  • 4
  • 39
  • 42
0

For example, add to the manifest:

<activity android:name=".Explorer" android:label="@string/app_name"
            android:configChanges="orientation" android:launchMode="standard">
        </activity>

and then just override the default function:

    @Override
        public void onConfigurationChanged(Configuration _newConfig){
            super.onConfigurationChanged(_newConfig);
int height = getWindowManager().getDefaultDisplay().getHeight();
        int width = getWindowManager().getDefaultDisplay().getWidth();
        if(width > height){
// layout for landscape
}else{
// layout for portrait
        }
            }

NOTE: if you override this function YOU must redo the layout yourself. That is the only way to do what you want. Android's approach to fixing your screen size is to blow the entire Activity away and bring it up again with the new dimensions. If you opt to not have it blow the Activity away then YOU have to handle the screen size change. There aren't any other options to that.

EDIT: In this particular app, I have a table that shows up in portrait, and a chart that shows up in landscape. So I do this:

void showDataView()
    {
        setContentView(mainView);
        currentView = mainView; 
    }

    void showGraphView()
    {
        if(currentView == mainView){
            if(graphView == null){
                setContentView(R.layout.graphview);
                graphView = (GraphView)findViewById(R.id.graphview);
            }
            setContentView(graphView);
            currentView = graphView;
            graphView.setDataToPlot(DATA_TO_PLOT);
            graphView.clear();
        }
    }

@Override
    public void onConfigurationChanged(Configuration _newConfig){
        super.onConfigurationChanged(_newConfig);
        int height = getWindowManager().getDefaultDisplay().getHeight();
        int width = getWindowManager().getDefaultDisplay().getWidth();
        if(width > height){
            showGraphView();
        }else{
            showDataView();
        }
        if(graphView != null) graphView.setGraphWidth(width);
    }

Everytime the orientation changes, I switch the content view from one to the other. In your case you might be able to just invalidate the current root View and see if it will redraw correctly.

This is why you want the platform to take care of it, so you don't deal with this crap. You'd be better off just using onSaveInstanceState to preserve the specific data you need and then check in onCreate for that data and then use it. See http://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges for info about that.

Femi
  • 64,273
  • 8
  • 118
  • 148
  • ok and where am i putting that code? in my activity before onCreate? – Jimmy D May 06 '11 at 17:09
  • @Femi This is the only true answer. I've found that it's best to just force a screen orientation and stay with that. Especially if it's any kind of art asset heavy application. That's why most games on the marketplace force an orientation and do not allow it to change. – SRM May 06 '11 at 17:10
  • and what am i putting in the "layout for landscape" and "layout for portrait" areas? – Jimmy D May 06 '11 at 17:11
  • In your Activity: its just another Android callback like `onCreate`: you have to implement `onConfigurationChanged` and then force the new layout to take place. All its saying is instead of `destroy`ing the activity when a screen orientation change occurs, call this function and you'll redo the layout yourself. You might get away with just getting the root View and `invalidate`ing it. – Femi May 06 '11 at 17:12
  • i still have no idea what i should be doing in the if/else sections. can i have an example? – Jimmy D May 06 '11 at 17:17
  • Configuration contains the orientation of the phone. – techi.services May 06 '11 at 17:23