How can I persist a variable across Activities? - java

I have a File object called currentFile. When currentFile has been changed and the user attempts to open a new file without saving first a Save dialog is presented and if Yes is clicked currentFile is saved. The problem I'm having is that when I start a new Activity and press the Android back button, currentFile is set to null so changing the file, attempting to open a new one results in a NullPointerException. How can I persist currentFile across Activities?

There's several ways to do this, depending on what you want to do you should put on a balance what's better for your needs, one way is using extras to pass the variable value to another activity
Bundle extras = new Bundle();
extras.putString(key, value);
Intent intent = new Intent("your.activity");
intent.putExtras(extras);
startActivity(intent);
Another approach is to set a variable in your application context, creating a class that extends from Application and which reference you will be able to get from any activity using
YorApplicationClass app = (YorApplicationClass)getApplication();
app.getYourVariable();
And the last i can think of is using SharedPreferences, storing variables as key/value pairs that can be used for any activity...
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
Editor edit = pref.edit();
edit.putString(key, value);
edit.commit();
//Any activity
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
pref.getString(key, defValue);
Regards!

You can do this using Intents & Extras.
String yourFileName = "path/to/your/file";
Intent intent = new Intent(currentActivity, newActivity.class);
intent.putExtra("FileName", yourFileName);
startActivity(intent);
Then in your new activity:
Bundle extras = getIntent().getExtras();
if (extras != null) {
String file = extras.getString("FileName");
}
Here is some reading on Intents: http://developer.android.com/reference/android/content/Intent.html

You could also do this using the Application class. I find it easier to work with than using bundles and intents.
To access your application class, just call getApplicationContext in any activity, and cast it to your class type which extends Application like so:
public class MyActivity extends Activity{
public void onCreate(Bundle bundle){
MyApplicationClass app = (MyApplicationClass)this.getApplication();
}
}

Related

New arraylist created automatically when fragment is put into view

I'm creating an app where the user can view their score histories and it works fine except that whenever I click on the fragment directly a new arraylist list is automatically created with the previous custom items. When I use the savebutton intent to get to the fragment no such issues arise and the recyclerview is updated as I want it to.
This is how I save scores using a navigation Menu item
case R.id.save_game:
Intent save = new Intent(getApplicationContext(), ScoreActivity.class);
Bundle extras = new Bundle();
extras.putString("EXTRA_DATE", format);
save.putExtras(extras);
startActivity(save);
Toast.makeText(this, "Saved", Toast.LENGTH_SHORT).show();
break;
I receive the intent in my ScoreFragment
public void saveScore(){
Intent intent = requireActivity().getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
String format = extras.getString("EXTRA_DATE");
mScoreList.add(new ScoreItem(TeamAName, TeamBName, scoreTeamA, scoreTeamB, format));
saveData(); //Saves Arraylist to sharedpreferences
}
}
And then I call saveScore() in my oncreateView method
My Score Fragment is attached to ScoreActivity like this
public class ScoreActivity extends AppCompatActivity {
#Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_category);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.container,
new ScoreFragment()).commit();
}
}
}
I've tried putting my saveScore() method in onViewCreated() as well as onResume and onSaveInstanceState but it doesn't change anything.
Changing replace() to add() in my ScoreActivity also doesn't do anything.
Right after I inflate my rootView I call loadData() and I've been trying to call it somewhere else but it causes crahes.
private void loadData() {
SharedPreferences sharedPreferences = requireActivity().getSharedPreferences("shared preferences", Context.MODE_PRIVATE);
Gson gson = new Gson();
String json = sharedPreferences.getString("task list", null);
Type type = new TypeToken<ArrayList<ScoreItem>>() {
}.getType();
mScoreList = gson.fromJson(json, type);
if (mScoreList == null) {
mScoreList = new ArrayList<>();
}
}
How do I go about resolving this issue?
getIntent() always returns the Intent you used to create that Activity - so if you use that menu item to start a new one and add that extra
Intent save = new Intent(getApplicationContext(), ScoreActivity.class);
Bundle extras = new Bundle();
extras.putString("EXTRA_DATE", format);
save.putExtras(extras);
startActivity(save);
then that Activity will always return this Intent + Extras bundle when you call getIntent. So if your fragment has this in its onViewCreated:
Intent intent = requireActivity().getIntent();
Bundle extras = intent.getExtras();
and its parent activity was originally created with that Intent+Extras combo, then it will run your adding code
Honestly it depends on how your app is set up, so I can only give you ideas of things to look at
If you have an activity where fragments get swapped, so ScoreFragment can get re-added (you mentioned "using the navigation drawer to navigate to the fragment") then onViewCreated will run again with that Intent.
If it's off-screen and the system destroys its views to save memory, when it's recreated it will run onViewCreated again with that Intent.
If you call startActivity in different places, but an existing Activity gets reused (say your Activity is launched as singleTop or singleInstance) then it will have the Intent+Extras it was originally created with. So if you first create it through that menu item with the extras, and then call startActivity() without the extras from somewhere else, if the original activity gets used it will still have that Intent+Extras it was created with. (It'll receive the new intent throughonNewIntent() but it won't change the value of getIntent)
Also you're not actually checking if the extras Bundle has the EXTRA_DATE item, just if it has some extras, and then you're adding a new ScoreItem with whatever extras.getString("EXTRA_DATE") returns (which might be `null``). So if you're launching with other bundles of extras in different situations, you might still get the extra score added
I know that's a lot and it's not a solution but hope it helps! Honestly I'd recommend setting a breakpoint in saveScore, debug the app and use the debugger to see what getIntent is giving you, and if it looks right.
So I managed to solve the issue but I have no idea what I actually did. I decided to create an easy splash screen for my app and the problem just disappeared. I'm so confused right now and I would like some help in figuring it out so I can correct it in the future.
I created a new Activity called SplashScreenActivity
public class SplashScreenActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EasySplashScreen config = new EasySplashScreen(SplashScreenActivity.this)
.withFullScreen()
.withTargetActivity(MainActivity.class)
.withSplashTimeOut(5000)
.withBackgroundColor(Color.parseColor("#FF9800"))
.withHeaderText("Header")
.withFooterText("Footer")
.withBeforeLogoText("Before Logo Text")
.withAfterLogoText("After Logo Text")
.withLogo(R.mipmap.ic_launcher_round);
config.getHeaderTextView().setTextColor(Color.WHITE);
config.getFooterTextView().setTextColor(Color.WHITE);
config.getBeforeLogoTextView().setTextColor(Color.WHITE);
config.getAfterLogoTextView().setTextColor(Color.WHITE);
View easySplashScreen = config.create();
setContentView(easySplashScreen);
}
}
Then I moved MainActivity's intent-filter to the Splash Screen Activity in my Manifest.xml
file and this is what I think changed things.
<activity android:name=".SplashScreenActivity"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I moved it back to the MainActivity a couple of times and I realized the problem came back each time the intent filter was in MainActivity. Now I keep it in .SplashScreenActivity in the Manifest and I have no such issues. I really need some explanation for this.

Bundle is null from third activity

hi im using bundle to pass a string from my MainActivity to my second activity which is sub genre. but i also need the same string in my third activity.
i use my code like this in my main acitvity
Bundle getGenre_Bundle = new Bundle();
if (genre.equals(selector.Crime)) {
Intent i = new Intent(getBaseContext(),Crime.class);
getGenre_Bundle.putString("crime",selector.Crime);
i.putExtras(getGenre_Bundle);
startActivity(i);
then i call it in my second Activity using
Bundle p = getIntent().getExtras();
Genre = p.getString("crime");
this works great but if i try to call it on my third activity it returns an error in my log that my firebase child(Genre)cant be null.
Ive fixed the problem by making a new bundle in my second activity that recollects the String to pass to my third activity. but it seams a bit of a messy way of doing it. is there an easier/better way to pass strings to any activity?
You can fetch entire bundle from your previous activity in second activity and simply set in intent with putExtras()
Bundle old = getIntent().getExtras();
Intent thirdActivity = new Intent(this,thirdActivity.class);
thirdActivity.putExtras(p);

Passing values from Activity2 to Activity1 without visiting Activity1

I have a loginActivity and a MainActivity
I have used SharedPreferences to store some values in some variables in the loginActivity. Now I want to use these values(They're boolean values) in MainActivity without re=opening MainActivity. How do I do this?
Also, the SharedPreferences are in an onClick method for a button .
Thank you!
I'm assuming that MainActivity starts first, and loginActivity is on top of it in the stack. When loginActivity finishes, you can read the SharedPreferences in MainActivity#onResume.
If you mean that you want to do things in MainActivity while it's in the background or backstack, don't. An activity that is not in the foreground should not be doing any work, and in fact cannot be counted on to exist at all.
There are two ways
1.If you have set the values in shared preferences you can access them from any activity with relevant permissions.
2.Pass when moving from one to another activity and close the other one if need.
Intent toMain = new Intent(LoginActivity.this, MainActivity.class);
toMain.putExtra("bool1", "true"); //Optional parameters
LoginActivity.this.startActivity(toMain);
//To prevent go back to login
finish();
then from onCreate of mainActivity
Bundle fromLogin = getIntent().getExtras();
if (extras != null) {
String value = extras.getString("bool1");
//convert this to boolean
}

Passing String Values between Activities using intents

I understand how to pass string values from the MainActivity to the SecondaryActivity using intents, but how would you do that Vise Versa. Here is the code that I am using, I just don't know where to put the Recieving classes code.
In my SecondActivity
Intent intent = new Intent(SecondActivity.this, MainActivity.class);
String TimeValue = ("00:00:00");
intent.putExtra("TimeValue", TimeValue);
startActivity(intent)
and This is the code that I am not sure where to put so it doesn't crash when the app starts
String intent = getIntent().getExtras().getString("TimeValue");
TextView timeText = (TextView)findViewById(R.id.timeText);
timeText.setText(intent);
The problem is that MainActivity won't always be created with an intent coming from SecondActivity. It will also be created just when the app is launched.
You need to make sure that extras actually exists before trying to get extras from it! It could be null!
So this should be in your onCreate method, after you inflate the view.
Bundle extras = getIntent().getExtras();
String intentString;
if(extras != null) {
intentString = extras.getString("TimeValue");
} else {
intentString = "Default String";
}
TextView timeText = (TextView)findViewById(R.id.timeText);
timeText.setText(intentString);
I also highly recommend that you change the name of your String to "intentString" instead of "intent." The name "intent" is typically used for actual Intent objects, not the String that you get out of the Intent. So naming it "intentString" makes things more readable for other developers.
If you're trying to pass data back from SecondActivity to the MainActivity, then use startActivityForResult instead.
Once you have launched your SecondActivity and ready to pass the data back to the MainActivity, create a new Intent and use SecondActivity.setResult(resultCode, Intent);. Then call finish, to finish the SecondActivity.
Now, in your MainActivity, you will get a call to onActivityResult() which will give you the Intent you passed in the SecondActivity as a data parameter.
You can look at this link for more info: http://developer.android.com/training/basics/intents/result.html

Take the information inside a ListItem and send it to the next Activity

I am relatively new to the Eclipse & ADT plugin world, so any answers can you please explain what it's doing? It would be very helpful.
Basically, I have a list in one activity that will be populated by a HTTP request from a database API, this I am still working on. However, what I wish to know, is am I able to take the string in the ListItem and give that to a TextView in the next activity?
So for example, I tap 'Record 1' and it takes 'Record 1' and puts it inside a variable, then sends the user to the next screen, and inserts the variable into a TextView. Is this possible?
Thank you.
Get what you want from the adapter, then put that into the Intent that starts the new activity:
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String string = parent.getAdapter().getItem(position);
Intent intent = new Intent(this, nextActivity.class);
intent.putExtra("text", string);
startActivity(intent);
}
});
In the new Activity you then get the Intent that started the new Activity and get the String you put into it:
String data = getIntent().getStringExtra("text");
Implement the setOnItemClickListener() for the listItem where you will capture the listItem clicked and the String you require and then using intent.putExtra(String id, STRING_VALUE) you can pass your string to the next activity.
Yes, it is possible.
You can send information to another activity using Extra. See this code below:
Intent i = new Intent(this, NoteEdit.class);
i.putExtra(NotesDbAdapter.KEY_ROWID, id);
startActivityForResult(i, ACTIVITY_EDIT);
You use putExtra to put your data do you want to send to the activity. In the example NotesDbAdapter.KEY_ROWID is the name you give to access the data and id is the data itself.
And, this is how you can get the data from the activity:
Bundle extras = getIntent().getExtras();
mRowId = (extras == null) ? null : extras.getLong(NotesDbAdapter.KEY_ROWID);

Categories

Resources