When Orientation change,onSaveInstanceState call caused values Swap - android

I have two variables to save on device orientation. One is current question number as an integer, another is a boolean value if the user cheated. It working fine when I'm storing and retrieving sinle value while storing both value it swaps.
public class QuizActivity extends ActionBarActivity {
// Logging members
private static final String LOG_TAG = QuizActivity.class.getSimpleName();
// The member of Saving the state for rotation of the device
private static final String KEY_BOOLEAN = "index";
private static final String KEY_INT = "index";
// Adding members
private Button mTrueButton;
private Button mFalseButton;
private Button mNextButton;
private Button mBackButton;
private TextView mQuestionTextView;
private ImageButton mImgRightButton;
private ImageButton mImgLeftButton;
private Button mCheatButton;
private TrueFalse[] mQuestionBank = new TrueFalse[] {
new TrueFalse(R.string.question_oceans, true),
new TrueFalse(R.string.question_mideast, false),
new TrueFalse(R.string.question_africa, false),
new TrueFalse(R.string.question_americas, true),
new TrueFalse(R.string.question_asia, true)
};
private int mCurrentIndex = 0;
// To save the CheatActivity returning result
private boolean mIsCheater;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(LOG_TAG, "QuizActivity onCreate(Bundle) called");
setContentView(R.layout.activity_quiz);
if(savedInstanceState != null) {
mCurrentIndex = savedInstanceState.getInt(KEY_INT);
mIsCheater = savedInstanceState.getBoolean(KEY_BOOLEAN);
}
}
// Not to loose activity state when rotating the device
#Override
public void onSaveInstanceState(Bundle saveInstanceState) {
Log.i(LOG_TAG, "onSaveIntanceState");
saveInstanceState.putInt(KEY_INT, mCurrentIndex);
saveInstanceState.putBoolean(KEY_BOOLEAN, mIsCheater);
super.onSaveInstanceState(saveInstanceState);
};
// to get the result from child activity(Cheat activity)
#Override
protected void onActivityResult(int arg0, int arg1, Intent data) {
if(data == null){
return;
}
mIsCheater = data.getBooleanExtra(CheatActivity.EXTRA_ANSWER_SHOWN, false);
};
}

You have the same keys!! Change code like this:
private static final String KEY_BOOLEAN = "index_BOOLEAN";
private static final String KEY_INT = "index_INT";

KEY_INT and KEY_BOOLEAN have the same name, the same value. So when setting those in the bundle one might overwrite the other. Use different names:
private static final String KEY_INT="intindex";
private static final String KEY_BOOLEAN="boolindex";

Related

How do update decoview chart with live data?

I have looked at the github resource and also here but I'm unable to get my graph to display live data. Here's my code.
public class Blink_HR extends Fragment {
TextView textView;
LinearLayout linearLayout;
DecoView mDecoView;
private int mBackIndex;
private int mSeries1Index;
private int mSeries2Index;
private int mSeries3Index;
private final float
mSeriesMax = 50f;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.blink_hr, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
textView = (TextView) getActivity().findViewById(R.id.meditation);
linearLayout = (LinearLayout) getView().findViewById(R.id.blinkHR);
mDecoView = (DecoView)getActivity().findViewById(R.id.dynamicArcView);
mDecoView.addEvent(new DecoEvent.Builder(mSeriesMax)
.setIndex(mBackIndex)
.setDuration(10)
.build());
SeriesItem seriesItem = new SeriesItem.Builder(Color.parseColor("#FFE2E2E2"))
.setRange(0, mSeriesMax, 0)
.setInitialVisibility(true)
.build();
mBackIndex = mDecoView.addSeries(seriesItem);
}
void update(int id, int value) {
String heart = String.valueOf(value);
Log.d("Blink Hai", heart);
if (value > 0 && mDecoView!=null && mSeries1Index!=0) {
SeriesItem seriesItem = new SeriesItem.Builder(Color.parseColor("#FFFF8800"))
.setRange(0, (float)value, 0)
.setInitialVisibility(false)
.build();
mSeries1Index = mDecoView.addSeries(seriesItem);
}
if (mDecoView != null) {
mDecoView.addEvent(new DecoEvent.Builder(42.4f)
.setIndex(mSeries1Index)
.setDelay(3250)
.build());
mDecoView.executeReset();
}
}
}
My update function is called every 1 second and I would expect the graph to update this data in real-time. However all I get is a blimp on the screen.
There is a couple of issues with the code
An event is added to the series mBackIndex before mBackIndex has been initialized
Update is triggered every 1 second but a 3.25 second delay is added to the event before it will be processed
The event on update always sets the DecoView position to 42.4
executeReset() is called every time the update is triggered, this
resets all series in the charts and cancels all pending animations
Here is some sample code that will update a DecoView every 1 second to a random position with animation
public class FauxFitActivity extends AppCompatActivity {
private DecoView mDecoView;
private int mSeries1Index;
private final float mSeriesMax = 50f;
private Handler mHandler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
update();
mHandler.postDelayed(this, 1000);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_faux_fit);
mDecoView = (DecoView) findViewById(R.id.dynamicArcView);
createDataSeries1();
// Start the timer
mHandler.post(runnable);
}
private void createDataSeries1() {
final SeriesItem seriesItem = new SeriesItem.Builder(Color.parseColor("#FFFF8800"))
.setRange(0, mSeriesMax, 0)
.setInitialVisibility(false)
.build();
mSeries1Index = mDecoView.addSeries(seriesItem);
}
private void update() {
final Random rand = new Random();
int newPosition = rand.nextInt((int)mSeriesMax);
mDecoView.addEvent(new DecoEvent.Builder(newPosition).setIndex(mSeries1Index).setDuration(1000).build());
}
}

Data saving when orientation changes

I have put a condition in onCreate() method to check if there exist some previous data or not. But it is not working.
please guide me.
And I don't want to use onRestoreSavedState() method for this.d
public class ActivityOne extends Activity {
Use these as keys when you're saving state between reconfigurations
private static final String RESTART_KEY = "restart";
private static final String RESUME_KEY = "resume";
private static final String START_KEY = "start";
private static final String CREATE_KEY = "create";
String for LogCat documentation
private final static String TAG = "Lab-ActivityOne";
private int mCreate=0, mRestart=0, mStart=0, mResume=0;
You will need to increment these variables' values when their
corresponding lifecycle methods get called.
TODO: Create variables for each of the TextViews
private TextView mTvCreate, mTvRestart, mTvStart, mTvResume;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
TODO: Assign the appropriate TextViews to the TextView variables
mTvCreate=(TextView)findViewById(R.id.create);
mTvRestart=(TextView)findViewById(R.id.restart);
mTvResume=(TextView)findViewById(R.id.resume);
mTvStart=(TextView)findViewById(R.id.start);
Button launchActivityTwoButton = (Button) findViewById(R.id.bLaunchActivityTwo);
launchActivityTwoButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=null;
intent = new Intent(v.getContext(),ActivityTwo.class);
startActivity(intent);
}
});
if(savedInstanceState!=null){
mCreate=savedInstanceState.getInt(String.valueOf(mCreate));
mRestart=savedInstanceState.getInt(String.valueOf(mRestart));
mResume=savedInstanceState.getInt(String.valueOf(mResume));
mStart=savedInstanceState.getInt(String.valueOf(mStart));
}
// Emit LogCat message
Log.i(TAG, "Entered the onCreate() method");
mCreate++;
displayCounts();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
Save state information with a collection of key-value pairs
4 lines of code, one for every count variable
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt(String.valueOf(mCreate),mCreate);
savedInstanceState.putInt(String.valueOf(mRestart),mRestart);
savedInstanceState.putInt(String.valueOf(mResume),mResume);
savedInstanceState.putInt(String.valueOf(mStart),mStart);
}
Updates the displayed counters
This method expects that the counters and TextView variables use the names specified above
public void displayCounts() {
mTvCreate.setText("onCreate() calls: " + mCreate);
mTvStart.setText("onStart() calls: " + mStart);
mTvResume.setText("onResume() calls: " + mResume);
mTvRestart.setText("onRestart() calls: " + mRestart);
}
}
It looks like the problem is that you attempting to use values that have not been set yet when you try to capture the saved value.
All you need to do to fix it is to use the String constants that you have defined.
So, in onCreate(), you would have:
if(savedInstanceState!=null){
mCreate=savedInstanceState.getInt(CREATE_KEY);
mRestart=savedInstanceState.getInt(RESTART_KEY);
mResume=savedInstanceState.getInt(RESUME_KEY);
mStart=savedInstanceState.getInt(START_KEY);
}
Then, in onSaveInstanceState(), you would have:
savedInstanceState.putInt(CREATE_KEY,mCreate);
savedInstanceState.putInt(RESTART_KEY,mRestart);
savedInstanceState.putInt(RESUME_KEY,mResume);
savedInstanceState.putInt(START_KEY,mStart);

Robolectric view doesn't update after restore state

I have an activity which contains a fragment.
This is a part of the fragment:
public class NotificationFragment extends DialogFragment {
private static final String EDIT_TEXT_KEY = "EDIT_TEXT_KEY";
private static final String SPINNER_KEY = "SPINNER_KEY";
private static final String IMAGE_VIEW_KEY = "IMAGE_VIEW_KEY";
private static final List<String> arraySpinner = Arrays.asList("item 1", "item 2", "item 3", "item 4", "item 5");
// private String text;
private String spinnerValue;
private Bitmap bitmap;
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
System.out.println("NotificationFragment#onActivityCreated");
if (savedInstanceState != null) {
final EditText editText = (EditText) getView().findViewById(R.id.edit_text);
editText.setText(savedInstanceState.getString(EDIT_TEXT_KEY));
editText.setText("gebroken");
final Spinner spinner = (Spinner) getView().findViewById(R.id.spinner);
spinner.setSelection(savedInstanceState.getInt(SPINNER_KEY));
final ImageView imageView = (ImageView) getView().findViewById(R.id.image_view);
imageView.setImageBitmap((Bitmap) savedInstanceState.getParcelable(IMAGE_VIEW_KEY));
System.out.println("1: " + ((EditText) getView().findViewById(R.id.edit_text)).getText().toString());
System.out.println(getView().hashCode());
}
}
In my test I want to check if the view gets restored after restoring the activity/fragment.
My test (debug state) looks like this:
#Config(manifest = IConfig.MANIFEST_PATH, emulateSdk = IConfig.SDK_VERSION, reportSdk = IConfig.SDK_VERSION)
#RunWith(RobolectricTestRunner.class)
public class AbstractFragmentTest {
#Test
public void test() {
final ActivityController<NotificationActivity> controller = Robolectric.buildActivity(NotificationActivity.class).setup().visible()
.start().resume();
final NotificationActivity activity = controller.get();
final ShadowActivity shadowActivity = Shadows.shadowOf(activity);
shadowActivity.recreate();
assertEquals("gebroken", ((EditText) shadowActivity.findViewById(R.id.edit_text)).getText().toString());
}
I would expect to have "gebroken" as a result, as this is the output from the test:
NotificationActivity#onCreate
NotificationFragment#onCreateView
NotificationFragment#onViewCreated
2:
NotificationFragment#onActivityCreated
NotificationFragment#onSaveInstanceState
NotificationActivity#onSaveInstanceState
NotificationActivity#onCreate
NotificationFragment#onCreateView
NotificationFragment#onViewCreated
2:
NotificationFragment#onActivityCreated
1: gebroken
NotificationActivity#onRestoreInstanceState
But instead of being "gebroken", the result is "".
Am I missing a refresh over here?
Change the test to this:
#Config(manifest = IConfig.MANIFEST_PATH, emulateSdk = IConfig.SDK_VERSION, reportSdk = IConfig.SDK_VERSION)
#RunWith(RobolectricTestRunner.class)
public class AbstractFragmentTest {
private static final int EDIT_TEXT_ID = R.id.edit_text;
private static final String EDIT_TEXT_VALUE = "this text value should be restored";
private ActivityController<NotificationActivity> controller;
#Before
public void setupFreshFixture() {
controller = Robolectric.buildActivity(NotificationActivity.class).setup();
}
#Test
public void test() {
setEditText(controller.get(), EDIT_TEXT_ID, EDIT_TEXT_VALUE);
final Bundle state = restartActivity();
assertEquals(EDIT_TEXT_VALUE, state.getString(NotificationFragment.EDIT_TEXT_KEY));
assertEquals(EDIT_TEXT_VALUE, getEditText(controller.get(), EDIT_TEXT_ID));
}
private Bundle restartActivity() {
final Bundle state = new Bundle();
controller.saveInstanceState(state).stop().destroy();
controller = Robolectric.buildActivity(NotificationActivity.class).setup(state);
return state;
}
//TODO move to utilities
public static String getEditText(final Activity activity, final int id) {
return ((EditText) activity.findViewById(id)).getText().toString();
}
public static void setEditText(final Activity activity, final int id, final String value) {
((EditText) activity.findViewById(id)).setText(value);
}
}
And I had to modify my activity too:
public class NotificationActivity extends FragmentActivity {
private NotificationFragment fragment;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println("NotificationActivity#onCreate");
setContentView(R.layout.activity_notification);
if (savedInstanceState == null) {
fragment = new NotificationFragment();
getSupportFragmentManager().beginTransaction().add(R.id.notification_container, fragment).commit();
}
}
#Override
protected void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
System.out.println("NotificationActivity#onSaveInstanceState");
fragment.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
System.out.println("NotificationActivity#onRestoreInstanceState");
getSupportFragmentManager().findFragmentById(R.id.notification_container).onActivityCreated(savedInstanceState);
}
}
All this together makes sure that you can test the saving and restoring of the state within a fragment with robolectric

onsaveinstancestate only works once?

I have an app with two layouts (portrait and landscape). There are 4 int values I want to save so they don't get erased on rotation. For that, I call on save instance and then I recover the state on the onCreate method like this:
private int operando1;
private int operando2;
private int operador;
private int contadorIntentos;
private String operadorTxt;
private static final String CONTADOR_INTENTOS = "contadorIntentos";
private static final String OPERANDO1 = "operando1";
private static final String OPERANDO2 = "operando2";
private static final String OPERADOR = "contadorIntentos";
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(CONTADOR_INTENTOS, contadorIntentos);
outState.putInt(OPERANDO1, operando1);
outState.putInt(OPERANDO2, operando2);
outState.putInt(OPERADOR, operador);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_actividad_principal);
//other random code
Random generador = new java.util.Random();
if (savedInstanceState != null){
contadorIntentos = savedInstanceState.getInt(CONTADOR_INTENTOS);
operando1 = savedInstanceState.getInt(OPERANDO1);
operando2 = savedInstanceState.getInt(OPERANDO2);
operador = savedInstanceState.getInt(OPERADOR);
}else {
contadorIntentos = 0;
operando1 = generador.nextInt(1000);
operando2 = generador.nextInt(1000);
operador = generador.nextInt(4);
}
Well, it turns out that it only saves the state once. after the first rotation (when it saves correctly) if I modify things and rotate again it recovers the state of the first rotation. It's like onsaveinstancestate only works once. Why?
Because savedInstanceState isn't null in all of the subsequent rotations, you are never generating new numbers (ex: never calling this again: operando1 = generador.nextInt(1000)...etc...)

Immediate App Crash, whenever single line of code is added

Here is a class that works perfectly until I wanted to add one more feature, The code compiles then crashes immediately upon execution. The problem lies with the componentAnalyzer class that I wish to implement in this class. I donĀ“t know why it won't work because I implemented this componentAnalyzer in another class in the exact same way and it works beautifully.
I think its a small mistake but unsure. I commented out the part that was creating problems because the rest works and should not be touched.
The method that will use the componentAnalyzer is at the end of the code. I cut out everything that was working in order to see it easier.
public class PowerMonitorActivity extends Activity implements SeekBar.OnSeekBarChangeListener {
private static boolean instantiated = false;
//private static ComponentAnalyzer componentAnalyzer;
//private Context context;
private Button changeGPSButton;
private Button changeAudioButton;
private Button locationUpdateButton;
private SeekBar brightnessSeekBar;
private int screenBrightness = 123;
private Handler cpuHandler = new Handler();
private CPUMonitor cpuMonitor = new CPUMonitor();
private int updateTime = 1000;
private Handler totalPowerHandler = new Handler ();
private MediaManager mediaManager = new MediaManager();
private boolean requestingLocation = false;
private boolean wifiIsTransmitting = false;
private boolean wifiIsConnected = false;
private boolean cellIsTransmitting = false;
private boolean cellIsConnected = false;
private boolean isLogging = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Bundle extras = getIntent().getExtras();
if (!instantiated) {
instantiated = true;
//componentAnalyzer = new ComponentAnalyzer(context, extras);
}
// Create GPS button - note that location settings cannot be changed directly
// in a program. Rather, a settings screen is shown when this button is pressed.
changeGPSButton = (Button)findViewById(R.id.changeGPS);
changeGPSButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showGPSOptions();
}
});
totalPowerHandler.removeCallbacks(updatePower);
totalPowerHandler.postDelayed(updatePower, 1000);
}
private Runnable updateCpu = new Runnable() {
public void run() {
float util = cpuMonitor.getUtil();
int rutil = Math.round(100*util);
TextView cpuTextView = (TextView)findViewById(R.id.cpuTextView);
cpuTextView.setText(rutil+"%");
cpuHandler.postDelayed(this, updateTime);
}
};
private Runnable updatePower = new Runnable()
{
public void run()
{
//float testPower = componentAnalyzer.getWifiPower();;
TextView totalPowerView = (TextView)findViewById(R.id.totalPowerTextView);
//totalPowerView.setText(testPower+"mW");
totalPowerHandler.postDelayed(this, 1000);
}
};
Did you initialize context? In the current code example context is null when the ComponentAnalyzer is instantiated.
For my point of view, your application context is null (you forgot to assign reference to context for current activity or application)
Remove comments for problematic lines,
Now look at these lines,
Bundle extras = getIntent().getExtras();
if (!instantiated) {
instantiated = true;
componentAnalyzer = new ComponentAnalyzer(context, extras); // Here context is null
}
change this according to given below,
Bundle extras = getIntent().getExtras();
if (!instantiated) {
instantiated = true;
if(extras != null)
componentAnalyzer = new ComponentAnalyzer(PowerMonitorActivity.this, extras);
else Log.e("PowerMonitorActivity","Bundle extras is null");
}

Categories

Resources