Text Of EditTextPreference Turns White On Orientation Change - android

I'm using SettingsActivity as preference activity for my application like so:
public class SettingsActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(getString(R.string.dark_theme_key), false)) {
setTheme(R.style.AppThemeDark);
} else {
setTheme(R.style.AppThemeLight);
}
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
}
}
public static class SettingsFragment extends PreferenceFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.app_preferences);
...
}
}
}
If I use getActivity().recreate(); (I have a SwitchPreference for dark and light theme. Dark theme is Theme.AppCompat and light is same but with .Light. If I change the theme I use recreate.) or change orientation of the screen (Resulting in onCreate of course), I get a weird problem when I'm on my light theme.
The problem is as follows -after a recreate, the text content of the EditTextPreference's turn white instead of black.
If I simply ignore savedInstanceState == null and just create a new fragment every time on SettingsActivity.onCreate, I lose the "screen state" (for example if I was scrolled all the way down before, after recreate Im scrolled back to the top. If I had a EditTextPreference open before, after recreate its closed).
I'm not sure how to restore a fragment screen state in case of recreation, or why my problem even occurs. Would appreciate help.

Related

Save App Preferences from PreferenceScreen when pressing back button

I'm trying to learn how to develop Android apps. I followed a video tutorial on YouTube, and it ended by adding a simple App Settings screen to the application.
However, there's one point that bothers me: when I press the back button on my phone's navigation bar, the changed settings aren't applied.
I have tried searching on Google, but none of the solutions I found have worked. The fact that I don't yet understand 100% of what's happening on the proposed solutions may also contribute to my difficulty on solving this one problem.
The behavior I expect from the app is that when I press the back button on the navigation bar, the changed settings should be applied.
For instance, I have a setting for dark background, which is controlled by a checkbox. The current behavior is: I check the setting for dark background. When I press the back button on the navigation bar, the setting isn't applied (I do have a method that loads the preferences on my MainActivity). What I want to happen is when I press the back button, the dark background is applied in this case.
From what I understand, I believe that overriding onBackPressed should do the trick, but I don't know what should be executed in order to properly apply the settings.
Here are the class and layout of my PreferenceScreen. Regarding the strings on the XML, they aren't actually hard-coded. I just copied the English values here to show the text that should appear on the interface.
public class AppPreferences extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note_detail);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
SettingsFragment settingsFragment = new SettingsFragment();
fragmentTransaction.add(android.R.id.content, settingsFragment, "SETTINGS_FRAGMENT");
fragmentTransaction.commit();
}
public static class SettingsFragment extends PreferenceFragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.app_preferences);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="General">
<EditTextPreference
android:title="Notebook"
android:summary="The title that will be used on the main action bar."
android:key="title"
android:defaultValue="Notebook" />
</PreferenceCategory>
<PreferenceCategory
android:title="Color">
<CheckBoxPreference
android:title="Dark Background"
android:summary="Is the main background color dark?"
android:key="background_color"
android:defaultValue="false" />
</PreferenceCategory>
</PreferenceScreen>
You will need to use
public class AppPreferences extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_note_detail);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
SettingsFragment settingsFragment = new SettingsFragment();
fragmentTransaction.add(android.R.id.content, settingsFragment, "SETTINGS_FRAGMENT");
fragmentTransaction.commit();
}
public static class SettingsFragment extends PreferenceFragment
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.app_preferences);
Preference preference = findPreference("background_color");
preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//do your action here
return false;
}
});
}
}
}
Or from other activity:
PreferenceManager.setDefaultValues(this, R.xml.your_setting_xml, false);
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
if (settings.getBoolean("background_color", true)) {
//do your action here
.........
Refer to this question also, (it has similar use case):
Checkbox Preference and Checking if its enabled or disable
Like #Chisko said, there isn't enough code in your question for us to be able to figure out your end goal - although I'm guessing you are wanting some form of persistent storage for your app to be able to save your app preferences. For this, you will want to use something in Android called SharedPreferences. This allows you to save simple data types to be accessed later.
Give that link a read, and then try saving/loading one simple piece of data. You'll want to load it from SharedPreferences on starting the activity (you can specify a default value if it hasn't been saved yet) and then you'll want to save the data in onBackPressed() as you said.
Best of luck and if you run into any issues, just comment here.
#Abdulhamid Dhaiban correctly points it out.
I'll add to your suggestion about overriding the onBackPressed() method.
If your "Up" button (top left <-) provides the correct result, then you can set the Back button to behave like the Up button by just adding the following code:
#Override
public void onBackPressed() {
super.onBackPressed();
NavUtils.navigateUpFromSameTask(this);
}
Hope it helps!

Saving state in Android not working

I have an activity that contains a fragment in it. The fragment has a progress bar and a text view, along with some other stuff. The progress bar and the text view both are visible sometimes, invisible at other times depending on some application logic.
What I'm trying to do is save the current state of both these views when the screen is rotated. Here is the relevant code in my fragment -
#Override
public void onSaveInstanceState(Bundle outState) {
// pbTranscribe is my progress bar
if (pbTranscribe != null) {
Log.d(TAG, "saving pb visibility");
boolean visibility = (pbTranscribe.getVisibility() == ProgressBar.VISIBLE);
outState.putBoolean("pbVisible", visibility);
}
}
#Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
Log.d(TAG, "bundle available !!");
boolean pbVisible = savedInstanceState.getBoolean("pbVisible", false);
Log.d(TAG, "is visible? " + pbVisible);
if (pbVisible) {
pbTranscribe.setVisibility(ProgressBar.VISIBLE);
}
}
}
The above code doesn't seem to be working for some reason. If I rotate my screen when the progress bar is visible, logcat prints all the above messages ("saving pb visibility", "bundle available !!", "is visible? true"). I know for a fact that my application logic doesn't set the visibility to invisible during this time.
Even though the value obtained from the bundle is true, the progress bar doesnt become visible, i.e. pbTranscribe.setVisibility(ProgressBar.VISIBLE); is apparently not doing its job.
Where am I going wrong ? How do I successfully maintain the progress bar state ?
I have also tried to restore the state in onCreateView() and onActivityCreated(), same results. Also, I have tried saving the text view state in a similar fashion, but that also gives the same results. Saving the text view state with android:freezesText="true" also did not do the trick.
EDIT: This is how I add the fragment to the activity, in the activity's onCreate() method -
#Override
protected void onCreate(Bundle savedInstanceState) {
...
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragments_frame, new WatsonFragment())
.commit();
...
}
When screen rotated, Activity will call onCreate and create another WatsonFragment, modify you code to this
if(savedInstanceState==null){
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragments_frame, new WatsonFragment())
.commit();
}

IllegalStateException fragment did not create a view after orientation change

I have an app that has a main activity that the user can select an item from. That selection brings up a fragment (TracksActivityFragment) that itself is another list. When an item of that list is selected, a fragment is added that is a DialogFragment. So far so good, but when I rotate the device, the AFragment's onCreate() gets called and then the DailogFragment's onCreate() gets called, then it dies with the IllegalStateException saying that it dies on AFragment's Activity line 20 (setContentView).
Here is a part of that Activity with the line in question:
public class TracksActivity extends AppCompatActivity
{
private String mArtistName;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tracks); //DIES HERE
Here is the onCreate of the fragment
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if(savedInstanceState != null)
{
//We've got data saved. Reconstitute it
mTrackRowItemList = savedInstanceState.getParcelableArrayList(KEY_ITEMS_LIST);
}
}
The DialogFragment gets created in the TracksFragment like this:
PlayerFragment fragment = PlayerFragment.newInstance(mTrackRowItemList, i, mArtistBitmapFilename);
// The device is smaller, so show the fragment fullscreen
FragmentTransaction transaction = fragMan.beginTransaction();
// For a little polish, specify a transition animation
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// To make it fullscreen, use the 'content' root view as the container
// for the fragment, which is always the root view for the activity
transaction.add(android.R.id.content, fragment).addToBackStack(null).commit();
Here is the DialogFragment's onCreate
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
{
//We've got data saved. Reconstitute it
if (mPlayer != null)
{
mPlayer.seekTo(savedInstanceState.getInt(KEY_SONG_POSITION));
}
}
}
Not sure why it goes back to the TracksFragment since it had the DialogFragment active on rotation, but since that is the case, it would seem like I would need to recreate the entireDialogPlayer object, But it seems to keep this around as the call to its onCreate happens.
Anyone know what it is that needs to be done here?
OK, this was asked before but I discounted the solution...I should not have.
For some reason, Android wants the Tracks layout XML to use a FrameLayout instead of a fragment.
So, just replace fragment with FrameLayout in the layout xml file and all is well.

Android ActivityOptions.makeSceneTransitionAnimation doesn't seem to exist

Android L introduced a new animations feature: animating between similar Views in different activities. It's documented here.
I've tried to use ActivityOptions.makeSceneTransitionAnimation, but it doesn't seem to be visible in the SDK (or in the jar at all), so I tried using reflection, and it returns a null value.
Has anyone else got it working?
Okay, I got it working.
It seems like setting the value in styles.xml is completely ignored for now.
You'll need to do this in each Activity's onCreate till that's fixed
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
Transition transition = // load transition here.
getWindow().setSharedElementEnterTransition(transition);
getWindow().setSharedElementExitTransition(transition);
As per the same bug ViewAnimationUtils has, you'll see errors in Android Studio, it'll compile and run fine though.
We can got it working with theme config for v21.
Put these items into res/values-v21/styles.xml
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
Here is something work with 5.0 sdk got after 10/17/14.
But not sure what is the expected behavior if enable window content transitions and called setEnterTransition/setExitTransition in both mainActivity and secondActivity. If they are different (e.g one choose Explode and other choose Slide), which one would be applied?
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
To enable window content transitions in your code instead, call the Window.requestFeature() method:
*/
getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);
Transition ts = new Explode(); //Slide(); //Explode();
ts.setStartDelay(2000);
ts.setDuration(5000);
/*
If you have set an enter transition for the second activity,
the transition is also activated when the activity starts.
*/
getWindow().setEnterTransition(ts);
getWindow().setExitTransition(ts);
setContentView(R.layout.activity_main_view);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, mainViewFragment.newInstance())
.commit();
}
}
public void launchSecondActivity() {
/*
If you enable transitions and set an exit transition for an activity,
the transition is activated when you launch another activity as follows:
*/
Intent listIntent = new Intent(this, secondActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
}
}
//===
public class secondActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
///
getWindow().requestFeature(android.view.Window.FEATURE_CONTENT_TRANSITIONS);
Transition ts = new Slide(); //Slide(); //Explode();
ts.setDuration(3000);
getWindow().setEnterTransition(ts);
getWindow().setExitTransition(ts);
///
setContentView(R.layout.activity_scene_transition);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
}

Screen orientation landscape change activity

I'm making an app that change the colors depending of the color you select this change the background, but when I make the screen orientation to landscape this automatically change the color to the predefined and if I'm not wrong this happen because it's being destroy after I change the orientation... so I would like to know where and how I can solve that problem.
Android gives you a chance to save state before changing the layout
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mColor = savedInstanceState.getString(COLOR_VALUE);
}
#Override //this method is called before android trashes and recreates your activity
protected void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(COLOR_VALUE, mColor);
}
If your UI is expensive to recreate then look into retained fragments instead

Categories

Resources