I am making a two player game where I am able to have a rematch. I am also keeping track of the scores of each player. This is what my code for a rematch looks like:
public void rematch(View view) {
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
finish();
startActivity(i);
}
The above code is called when the user clicks a rematch button. I basically just restart the application because it's easier than resetting all the variables I have. Anyways, to keep track of the scores, I am overriding the onStop() method like this:
#Override
protected void onStop() {
super.onStop();
// We need an Editor object to make preference changes.
// All objects are from android.context.Context
SharedPreferences settings = getSharedPreferences(SCORES_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("scoreOne", p1Score);
editor.putInt("scoreTwo", p2Score);
editor.commit();
}
I am using shared preferences. Then, in my onCreate method, I get these shared preferences like this:
// Remember scores from previous games
SharedPreferences settings = getSharedPreferences(SCORES_NAME, 0);
p1Score = settings.getInt("scoreOne", 0);
p2Score = settings.getInt("scoreTwo", 0);
updateScores();
SCORES_NAME is
public static final String SCORES_NAME = "MyScores";
This all isn't working. My scores after the game restarts are always back to 0. I was thinking of putting extras onto the intent in rematch() but I'm not sure how to access this intent in my onCreate() method. Any help is greatly appreciated!
You need to override onSaveInstanceState(Bundle savedInstanceState) and write the application state values you want to change to the Bundle parameter like this:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putInt("scoreOne", p1Score);
savedInstanceState.putInt("scoreTwo", p2Score);
// etc.
}
The Bundle is essentially a way of storing a NVP ("Name-Value Pair") map, and it will get passed in to onCreate() and also onRestoreInstanceState() where you'd extract the values like this:
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
int p1Score = settings.getInt("scoreOne", 0);
int p2Score = settings.getInt("scoreTwo", 0);
}
You would usually use this technique to store instance values for your application (selections, unsaved text, etc.).
Problem here is that you made the assumption that the new activity's onCreate() will be called after your first activity's onStop() has completed execution.
That's probably not an assumption you want to make, because they are two not completely related things.
Send the values you need to the newly created activity in the intent
public void rematch(View view) {
Intent i = getBaseContext().getPackageManager()
.getLaunchIntentForPackage( getBaseContext().getPackageName() );
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Those next values will be there for sure in the new activity.
i.putExtra("scoreOne", p1Score);
i.putExtra("scoreTwo", p2Score);
finish();
startActivity(i);
}
And in the onCreate of your Activity can extract those values as follows
public void onCreate(Bundle savedInstance) {
super.onCreate();
..
int p1Score = getIntent().getIntExtra("scoreOne", 0);
int p2Score = getIntent().getIntExtra("scoreTwo", 0);
}
You need to take the code from onStop and execute it before your call to finish() from the rematch method. Like this:
private void saveScores() {
SharedPreferences settings = getSharedPreferences(SCORES_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("scoreOne", p1Score);
editor.putInt("scoreTwo", p2Score);
editor.commit();
}
And then call this function from rematch:
(...)
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
saveScores();
finish();
startActivity(i);
However, #elmorabea's solution is better is you are now only using SharedPreferences to pass values between activities.
Related
I'm new to Android, and a bit to Java (Don't ask)
I want to use the Shared Preferences, and till to this day everything worked fine, but in my new project the shared preferences won't save the data.
In my onCreate Method I have following code:
preferences = this.getSharedPreferences(KEY, MODE_PRIVATE);
editor = preferences.edit();
preferences.getFloat(TESTEPFLOAT, 0);
preferences.getFloat(TESTCURRENTEPFLOAT, 0);
preferences.getInt(TESTLEVEL, 1);
in my onDestroy Method:
#Override
public void onDestroy(){
super.onDestroy();
editor.putInt(TESTLEVEL, level);
editor.putFloat(TESTEPFLOAT, ep);
editor.putFloat(TESTCURRENTEPFLOAT, currentEP);
editor.apply();
}
I don't know where the problem is, and I hope someone can help me
Don't use onDestroy(). There's no guarantee it will get called. If you put a break point in that method, my guess is it's not getting called when you think it is.
change to this:
preferences = this.getSharedPreferences(KEY, MODE_PRIVATE);
preferences.getFloat(TESTEPFLOAT, 0);
preferences.getFloat(TESTCURRENTEPFLOAT, 0);
preferences.getInt(TESTLEVEL, 1);
to save your data:
#Override
protected void onPause() {
super.onPause();
preferences = this.getSharedPreferences(KEY, MODE_PRIVATE);
editor = preferences.edit();
editor.putInt(TESTLEVEL, level);
editor.putFloat(TESTEPFLOAT, ep);
editor.putFloat(TESTCURRENTEPFLOAT, currentEP);
editor.apply();
}
or use editor.commit(); to save data immediately
Just as #Gavin Wright said, onDestroy don't get called everytime. Move the code to onPause(). onPause() is guaranteed to get called everytime you navigate away from your activity.
#Override
public void onPause(){
super.onPause();
editor.putInt(TESTLEVEL, level);
editor.putFloat(TESTEPFLOAT, ep);
editor.putFloat(TESTCURRENTEPFLOAT, currentEP);
editor.apply();
}
Is there a way to access to variables on onCreate(), to reuse them in another class?
String testSubCa="";
String prixe="";
String testWiifi="";
Double testPrice=0.0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_srdata);
testSubCa = getIntent().getStringExtra(SearchRestau.txxtSub);
prixe = getIntent().getStringExtra(SearchRestau.txtprix);
testWiifi = getIntent().getStringExtra(SearchRestau.txxtWifi);
testPrice=Double.parseDouble(prixe);
refresh = (ImageButton) findViewById(R.id.imgRefresh);
refresh.setOnClickListener(this);
}
I need to use these data :/
Since you didn't really specify what exactly your plan is, it's a bit of a challenge getting a proper solution.
I'm just going to assume what you want to do is to start an activity, let the user do something inside this activity and then go back to where it was started from with the ability to use the values created inside the activity.
The easiest way to that is by not starting the activity via startActivity(Intent) but rather by using startActivityForResult(Intent, RequestCode);
In the same activity you then need to handle the event of actually getting a result. To do this you need to implement the method
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
//Your code to retrieve the data here!
}
}
The variables should be stored inside the Intent data and can be grabbed by using
data.getStringExtra();
To place the values inside the result you need to place this code in the activity you actually create them:
Intent intent = new Intent();
intent.putExtra("value_id", value);
setResult(RESULT_OK, intent);
finish();
I hope that helps with your problem!
GL
I have simple counter application where, whenever you click the button, a textview shows the number increasing. If you click the button 10 times, the textview shows 10. Then, when I exit from the app and launch the app again, the application restarts all the activities I have done previously.
How can I continue to count where I left off previously? For example, I want to open my app and count up to 8 with the counter. When I exit, and after re-launching the activity, I want to continue counting where I left off from 8.
Please take a look at the source code:
TextView tv4;
ImageButton button5;
int counter=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_ikinci);
tv4=(TextView)findViewById(R.id.textView4);
button5.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
counter++;
tv4.setText("" + counter);
}
});
On your activity's onStop() method try to save your data in SharedPreferences
SharedPreferences.Editor editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
editor.putInt("key", count);
editor.commit();
And when you launch it, on your main Activity onCreate() method retrieve your SharedPreferences value by key and continue where you left off
SharedPreferences prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);
int count = prefs.getInt("key",0); //0 is the default value.
If you need to store little pieces of data throughout your activity's lifecycle it should be enough to store your counter variable in a Bundle inside onSaveInstanceState (Bundle outState) method. Note - don't forget to call super of that method after putting your variable into the Bundle.
This particular Bundle is passed to two methods on recreating Activity: onRestoreInstanceState() and onCreate() methods. So you can reset you instance variable from there.
For more info look here: http://developer.android.com/training/basics/activity-lifecycle/recreating.html
In settings activity, I have multiple fields, once the user press save all these fields will be stored separately as key-value in sharedPreference.
The problem is every editor change e.g.
editor.putString(SERVER, server.toString());
will fire onSharedPreferenceChangeListener
While I only need to fire it after update all values..
Is there any way to achieve this requirement?
Many thanks
There's only a way to do that. You can put editor.putString(SERVER, server.toString()); in runtime code, such as you pressing a button. Once the activity gets destroyed call editor.commit(); within onDestroy() method, it will saves the value and fires onSharedPreferenceChangeListener. Simply, waiting for the user to close the activity first which means that users already changed all of their settings.
Note: please make sure that editor is an instance variable or make a field for it.
EDIT
Here's an example for you:
public class SettingsActivity extends Activity {
// a field for preference
private SharedPreferences.Editor editor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedpreferences = getSharedPreferences("MyPreference", Context.MODE_PRIVATE);
editor = sharedpreferences.edit();
// for example, edit the value using a button at runtime
Button button = (Button)findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
editor.putString(SERVER, server.toString());
}
});
...
}
#Override
protected void onDestroy(){
// call commit to save all changes
editor.commit();
super.onDestroy();
}
}
I am working on a To Do List Android application (it happens to be for a class assignment, but that's not what I'm asking about--I've tried to leave out as much code as I could). The main screen displays a list of ToDo items with a button at the bottom to open the Add New ToDo Item screen.
On the Add New ToDo Item screen, there is a Cancel button.
Relevant ToDoManagerActivity.java snippet:
public void onCreate(Bundle savedInstanceState) {
// Init and setup adapter, etc.
footerView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(ToDoManagerActivity.this, AddToDoActivity.class);
startActivityForResult(intent, ADD_TODO_ITEM_REQUEST);
}
});
// Attach the adapter to this ListActivity's ListView
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
log("Entered onActivityResult()");
// Check result code and request code.
// If user submitted a new ToDoItem
// Create a new ToDoItem from the data Intent
// and then add it to the adapter
}
Relevant AddToDoActivity.java snippet:
protected void onCreate(Bundle savedInstanceState) {
// Initialize default view, handle other events, etc.
final Button cancelButton = (Button) findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
setResult(RESULT_CANCELED, new Intent());
finish();
}
});
}
The above code works. Previously, I was trying this in the onClick handler for cancelButton:
public void onClick(View v) {
finishActivity(RESULT_CANCELED);
}
When I clicked the Cancel button, I could see that the onActivityResult was being reached in the logs, but the screen was not reverting back to the main ToDo list screen.
Why does the above code not return me to the previous screen, but the following code does return me to the previous screen? What am I misunderstanding about the task backstack/activities?
public void onClick(View v) {
setResult(RESULT_CANCELED, new Intent());
finish();
}
According to the documentation:
public void finish ()
Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via
onActivityResult().
and
public void finishActivity (int requestCode)
Force finish another activity that you had previously started with startActivityForResult(Intent, int).
You should call finish() to close the current activity and finishActivity() to close another activity you started using startActivityForResult(Intent intent, int requestCode). Calling finishActivity() on the current activity will not close it.
Also, there's no point in creating a new Intent for setResult() as you are not passing back any data. Doing this would be sufficient:
setResult(RESULT_CANCELED);
finish();
From Android Docs:
public void finishActivity (int requestCode)
Force finish another activity that you had previously started with startActivityForResult(Intent, int).
finishActivity does not finish the current activity but calls finish for an activity called with requestCode
If you look at the documentation for finishActivity() it says that it will force finish an activity started with startActivityForResult(), but you have to pass in the request code that you used to start the other activity. In your case it would be ADD_TODO_ITEM_REQUEST.
This is probably not the API you want to use. Your 2nd method is cleaner in that you don't need to force close the child activity, but let it finish in the normal way.