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.
Related
New to Android Studio. I'm creating an app project for practice and I am trying to create a Menu Activity. I want to test to see if I can mute sounds and hide the display of text (score) via a Menu UI. I get that I can use Intent to pass values back and forth between activities and that I can use those values to turn features on and off across the app.
I cannot figure out with a button and onClick how to get a variable to change so that I can pass it via Intent. I've only seen it done INSIDE the onClick. I'm trying to change the variable OUTSIDE the onClick.
Example Code:
public class Menu extends AppCompatActivity {
private boolean soundOn = true;
private Button isSoundOn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
isSoundOn = findViewById(R.id.isSoundOn_button);
isSoundOn.setOnClickListener(v -> {
soundOn = false;
});
Now when I attempt to access the soundOn parameter and pass it on via Intent to another activity the value remains true, it never changes after the button is clicked.
I did figure out one trick, I can use intent and pass the value to the same activity, like so:
soundOff.setOnClickListener(v -> {
Intent intent = new Intent(Menu.this, Menu.class);
intent.putExtra("soundOn", false);
startActivity(intent);
This reloads the Activity after the button is clicked, it makes it appear as though a glitch happened as it is run, but I think that issue could be resolved via altering the transition animation...I think. However, this seems like a clumsy approach, especially in a Menu Activity that could have numerous settings to edit (sound, score, language, timer, color, background, etc.).
I get that I can have the onClick go back to the original Activity with the change, but I want to create a menu where I can have multiple selections made and then pass them all back to the original Activity.
I hope this makes sense, I know this is rather basic, but I'm new to this and my searching hasn't been able to yield a solution. Thanks.
If you are doing an intent to the same Activity you should retreive your intent on the onCreate method:
isSoundOn = intent.getBooleanExtra("soundOn", true) //true is the default parameter in case intent does not contain that key;
That way you are always checking your intent in case you need it.
You also need to use your variable in the intent; right now you are always setting it to false:
soundOff.setOnClickListener(v -> {
Intent intent = new Intent(Menu.this, Menu.class);
intent.putExtra("soundOn", soundOn);
startActivity(intent);
}
There are other solutions, for example: you can use SharedPreferences for persisting your values and then call this.recreate to recreate Activity again and avoid using intents. Then you can retreive your SharedPreferencesvalues on the onCreate method to do whatever you want.
Now when I attempt to access the soundOn parameter and pass it on via
Intent to another activity the value remains true, it never changes
after the button is clicked.
Lets start with keeping track of soundOn
When Menu activity is first launched soundOn = true
When isSound button is clicked soundOn = false
Intent intent = new Intent(Menu.this, Menu.class);
intent.putExtra("soundOn", soundOn); // false is the value that is extra.
startActivity(intent);
When MenuActivity is again launched due to the intent soundOn = true this is because of this line
private boolean soundOn = true; //<---
You are passing Extra in intent but you arent storing the intents extra value in soundOn
Thats why it is true always
to solve this use need to Get the Intent Extra that you have passed and we do it in onCreate method
private boolean soundOn = true;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
Intent intent = getIntent();
if(intent != null) { // we need to get this cause when we first start our app we dont start it with any intents
soundOn = intent.getExtra("soundOn");
}
}
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);
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
Well, as I mentioned in heading, I can't get data from one activity, to another. I am making a really simple RSS reader, that loads data asynchroously, sends them to listview and opens the selected article in new activity's webview. And the problem is, that when i try to start an activity with webview, a can't pass data from the main activity.
So here is what I am doing:
1) In first activity (Main activity), i get data from my listview element, that user clicks on:
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
News clicked = (News) adapter.getItem(arg2);
String clickedTitle = clicked.title;
String clickedLink = clicked.link;
System.out.println("Title: " + clickedTitle + " / LINK: " + clickedLink); /*Here I can see my data in logs -> they are correct at this moment*/
Intent intent = new Intent(MainActivity.this, OpenFullArticle.class);
intent.putExtra(clickedTitle, "clickedTitle");
intent.putExtra(clickedLink, "clickedLink");
startActivity(intent);
}
});
So for now everything is okey, but than, when a new activity is started (OpenFullArticle activity), I am doing this:
public class OpenFullArticle extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_open_full_article);
String title = getIntent().getExtras().getString("clickedTitle");
String link = getIntent().getStringExtra("clickedLink");
System.out.println(title); //Tried link too, simultaneous each one - both ar null
}
So I'm stuck for this moment and have no idea, what I'm doing wrong. Tried debuger, checked the Intent, and it hadn't extras there, that I added in first activity.
Maybe you can give me a clue, what could cause such a strange issue.
P.S. If it's necessary, I can provide a full code or a full project in github.
Use following code in first activity
Intent intent = new Intent(MainActivity.this, OpenFullArticle.class);
intent.putExtra( "clickedTitle",clickedTitle);
intent.putExtra("clickedLink", clickedLink, );
startActivity(intent);
Change to
intent.putExtra("clickedTitle", clickedTitle);
// the first pram is the key
// the second is the value
intent.putExtra("clickedLink", clickedLink);
http://developer.android.com/reference/android/content/Intent.html#putExtra(java.lang.String, android.os.Bundle)
Also use Log instead of System.out.println.
http://developer.android.com/reference/android/util/Log.html
The mistake is in this line:
intent.putExtra(clickedTitle, "clickedTitle");
intent.putExtra(clickedLink, "clickedLink");
You need to give key first and then the value:
intent.putExtra("clickedTitle", clickedTitle);
Replace
intent.putExtra(clickedTitle, "clickedTitle");
intent.putExtra(clickedLink, "clickedLink");
with
intent.putExtra("clickedTitle",clickedTitle);
intent.putExtra("clickedLink",clickedLink);
Use the following code in your first activity
Intent intent = new Intent(MainActivity.this, OpenFullArticle.class);
intent.putExtra( "clickedTitle",clickedTitle);
intent.putExtra("clickedLink", clickedLink, );
startActivity(intent);
Initially try to isolate the issue by passing some hardcoded values to extras
like
intent.putExtra("id",1);
intent.putExtra("name","abc");
and check whether OpenFullArticle activity has the extras.
I'm trying to work with Tabhost, I have 2 tabs, each one loads one Activity, each Activity has an aSync method to parse some data. If I do setCurrentTab(0) when creating the Tabmenu Activity everything works fine, but if I try to start the app on the second tab(setCurrentTab(1)) it tries to load the first tab, and does the aSync method of the first tab and crashes because some data is lacking for method to work, which wasn't supposed to be called at all.
Here's the TabMenu.Activity:
public class TabMenu extends TabActivity {
TabHost tabHost = null;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
setResult(resultCode);
this.finish();
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
Intent intentToGet = getIntent();
tabHost = getTabHost();
TabHost.TabSpec spec;
Intent intent;
TabHost.TabSpec spec2;
Intent intent2;
intent = new Intent().setClass(this, HoursActivity.class);
intent.putExtra("student", intentToGet.getStringExtra("student"));
intent.putExtra("pass", intentToGet.getStringExtra("pass"));
intent.putExtra("un", intentToGet.getStringExtra("un"));
spec = tabHost
.newTabSpec("hours")
.setIndicator("Hours")
.setContent(intent);
tabHost.addTab(spec);
intent2 = new Intent().setClass(this, NotesActivity.class);
intent2.putExtra("student", intentToGet.getStringExtra("student"));
intent2.putExtra("pass", intentToGet.getStringExtra("pass"));
intent2.putExtra("un", intentToGet.getStringExtra("un"));
spec2 = tabHost
.newTabSpec("notes")
.setIndicator("Notes")
.setContent(intent2);
tabHost.addTab(spec2);
tabHost.setCurrentTab(1);
}
}
Any ideas?
In the past I have had to do something similar and solved it by doing the following:
Create a static boolean variable CAN_LOAD = false and HAS_LOADED = false in your HoursActivity class.
Once whatever needs to happen in the NotesActivity that will allow your HoursActivity class to be loaded, set CAN_LOAD to true.
In HoursActivity, on your onCreate and onResume call the loading function you want to be run, and within that function test for CAN_LOAD == true && HAS_LOADED == false and and load only if both pass, setting HAS_LOADED = true in the function so that it does not get run multiple times.
So when you click on the tab, the onResume will be called and the Activity can do whatever set up is needed. There may be a problem with performance if the load function is slow to perform, in which case you will need to modify it slightly to not wait until the onResume to load (keeping it async). But that should at least get you started off.