Chrometobia Chrometobia - 5 months ago 22
Java Question

How to handle service when Orientation is changed

I am making a music player app for learning purposes but I am stuck at the point where the user decides to change the orientation of the device, my app always recreates which is bad, I have managed to have all other data saved and restored using

onRestoreInstanceState
but I cannot think of a good approach with the
musicplayer service
, below is part of my code, it is a lot of code so i will focus on the problem

public class ManagerActivty extends AppCompatActivity{

//music player service object
private MusicService musicService;

//boolean to keep track of musicservice state
private boolean musicBound = Boolean.FALSE;

//Music service connection object
private ServiceConnection musicServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
if(!instanceSaved) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) iBinder;
musicService = binder.getService();
musicService.setOnSongChangeListener(ManagerActivty.this);
musicService.setOnPlayerStateChangedListener(ManagerActivty.this);
new loadSongAsync().execute();
musicBound = Boolean.TRUE;
System.out.println("Music Service Connected");

}

}

@Override
public void onServiceDisconnected(ComponentName componentName) {
musicBound = Boolean.FALSE;
}
};



@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manager_activty);
}

//method to bind music service with my activity
private void bindMusicService()
{
playMusicIntent = new Intent(this, MusicService.class);
bindService(playMusicIntent, musicServiceConnection, Context.BIND_AUTO_CREATE);
startService(playMusicIntent);
System.out.println("Binder Called");

}



@Override
protected void onStart() {
super.onStart();

//launch binder
bindMusicService();
}


@Override
protected void onDestroy() {
//stop service connection
if (playMusicIntent != null) {
stopGuiUpdates();
unbindService(musicServiceConnection);
stopService(playMusicIntent);
musicService = null;
}
super.onDestroy();
}

}




@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
System.out.println("Saved Instances");
outState.putBoolean(Constant.IS_MEDIA_PLAYING_PLAYING, musicService.isPlaying());
outState.putInt(Constant.MEDIA_PLAYER_POSITION, musicService.getMediaPlayer().getCurrentPosition());
outState.putBoolean(Constant.IS_MUSIC_REPLAY, musicService.isReplay());

}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
System.out.println("Retrieving Instances");

//if null try to re-bind service
if(musicService == null) {
bindMusicService();

}


}


this code gives me a nullpointerexception when I try to access the
musicservice
object after orientation changed, anyone who has dealt with this before please help.

Answer

You can declare the config changes to the <activity> tag in the App Manifest.xml file

android:configChanges="orientation|keyboardHidden"

This is the complete list of the attributes that you can set in <activity> tag in Manifest.xml

<activity android:allowEmbedded=["true" | "false"]
          android:allowTaskReparenting=["true" | "false"]
          android:alwaysRetainTaskState=["true" | "false"]
          android:autoRemoveFromRecents=["true" | "false"]
          android:banner="drawable resource"
          android:clearTaskOnLaunch=["true" | "false"]
          android:configChanges=["mcc", "mnc", "locale",
                                 "touchscreen", "keyboard", "keyboardHidden",
                                 "navigation", "screenLayout", "fontScale",
                                 "uiMode", "orientation", "screenSize",
                                 "smallestScreenSize"]
          android:documentLaunchMode=["intoExisting" | "always" |
                                  "none" | "never"]
          android:enabled=["true" | "false"]
          android:excludeFromRecents=["true" | "false"]
          android:exported=["true" | "false"]
          android:finishOnTaskLaunch=["true" | "false"]
          android:hardwareAccelerated=["true" | "false"]
          android:icon="drawable resource"
          android:label="string resource"
          android:launchMode=["multiple" | "singleTop" |
                              "singleTask" | "singleInstance"]
          android:maxRecents="integer"
          android:multiprocess=["true" | "false"]
          android:name="string"
          android:noHistory=["true" | "false"]  
          android:parentActivityName="string" 
          android:permission="string"
          android:process="string"
          android:relinquishTaskIdentity=["true" | "false"]
          android:screenOrientation=["unspecified" | "behind" |
                                     "landscape" | "portrait" |
                                     "reverseLandscape" | "reversePortrait" |
                                     "sensorLandscape" | "sensorPortrait" |
                                     "userLandscape" | "userPortrait" |
                                     "sensor" | "fullSensor" | "nosensor" |
                                     "user" | "fullUser" | "locked"]
          android:stateNotNeeded=["true" | "false"]
          android:taskAffinity="string"
          android:theme="resource or theme"
          android:uiOptions=["none" | "splitActionBarWhenNarrow"]
          android:windowSoftInputMode=["stateUnspecified",
                                       "stateUnchanged", "stateHidden",
                                       "stateAlwaysHidden", "stateVisible",
                                       "stateAlwaysVisible", "adjustUnspecified",
                                       "adjustResize", "adjustPan"] >   
    . . .
</activity>