In my FirstActivity, user will log in. If the user exists in the database, it is loaded and should be "passed" to the SecondActivityFragment which is within the SecondActivity. The need is to check whether the user is with incomplete register, if so, the toolbar will display a warning menu item telling it to complete the registration.
┌FirstActivity
├─SecondActivity
└──SecondActivityFragment
Every tutorial that I see showing how pass data through Activity and Fragment talking about replace fragments and so on, I think that's not my case.
I created newInstance() on my SecondActivityFragment but I'm kinda lost.
public static SecondActivityFragment newInstance(User user) {
Bundle args = new Bundle();
args.putSerializable("user", user);
SecondActivityFragment fragment = new SecondActivityFragment();
fragment.setArguments(args);
return fragment;
}
And when user clicks in login button
if (userExists()) {
userManager = new UserManager();
User user = userManager.getByEmailPwd(editEmail.getText().toString(), editPwd.getText().toString());
Intent secondActivity = new Intent(getContext(), SecondActivity.class);
SecondActivityFragment.newInstance(user);
startActivity(secondActivity);
}
Try to put user into your secondActivity intent.
Then in the SecondActivity's onCreate method get the user class using getIntent().getSerializable() and create an instance of SecondActivityFragment.
Calling
SecondActivityFragment.newInstance(user);
that way, will not cause any effects in what will got presented.
If you want to present the fragment in the context of Second activity, consider passing the data that the fragment need to know to the Second activity - it should be sth like:
secondActivity.putSerializable("user", user)
Then in SecondActivity's onCreate, or in other method, you have to replace fragment being displayed, for your SecondActivityFragment instance:
User user = null;
final Bundle args = getIntent().getExtras();
if(args.getSerializable("user") instanceof User){
user = (User)args.getSerializable("user");
}
if(user != null){
Fragment secondActivityFragment = SecondActivityFragment.newInstance(user);
FragmentMenager fragmentMenager = getFragmentMenager();
FragmentTransaction fragmentTransaction = fragmentMenager.beginTransaction();
fragmentTransaction.replace(R.id.frame_for_your_fragment, secondActivityFragment);
}
Related
Multiple Fragments are created in one Activity to switch pages to Fragment binding. At this point, the data in Main Activity must be used by all fragments.
So I did it like this.
I called method in Activity that return data in activity.
↓ fragment.java
MainActivity main = (MainActivity) getActivity();
data = main.getCurrentUserID();
And this is getCurrentUserID() in MainActivity.
public String getCurrentUserID() {
Intent intent = new Intent();
String curUser = intent.getStringExtra("USER ID");
return curUser;
}
This way, no data is loaded. Why is that? How can I take out items in one Bundle from multiple fragments to use Bundle?
I got an assignment to create an application. At the Splash screen stage, it is instructed to get a list from SQLite while in a Splash screen, and pass it to a Fragment (I did so by using an Intent).
My question is why not get it from the Fragment rather than passing it from the Splash screen to the Main Activity, and from there to the Fragment? It may seem unnecessary if it wasn't for some reason that's unknown to me.
When looking for information on this question I couldn't find anything. I guess it didn't come up previously, or at least I couldn't find the phrasing that was previously used.
The method that gets the list and passes it to the MainActivity:
private void toMainActivity(ArrayList<Movie> moviesList) {
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
intent.putParcelableArrayListExtra("moviesList", moviesList);
startActivity(intent);
finish();
}
At MainActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<Movie> moviesList = this.getIntent().getParcelableArrayListExtra("moviesList");
Bundle listBundle = new Bundle();
listBundle.putParcelableArrayList("moviesList", moviesList);
Fragment mlf = new MoviesListFragment();
mlf.setArguments(listBundle);
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragments_container, mlf);
ft.commit();
}
At the Fragment:
Bundle listBundle = getArguments();
if (listBundle != null) {
moviesList = getArguments().getParcelableArrayList("moviesList");
moviesAdapter.attachMoviesList(moviesList);
}
That's usually a matter of making sure you're working on the same instance of something. When passing something in a Bundle you're securing that the next screen will work on the same instance of the passed data that the previous screen was.
Whether it's better or worse than querying a db every time is a case-by-case thing. Sometimes you want to maintain data "continuity" between screens and sometimes you want to get the newest copy of the data (which could've been modified asynchronously).
I want to transfer data from an activity with edit texts to a fragment class with a list to only display the edit_name box. I want to be able to click a button in the activity class and for it to save all of the information and display only the edit_name box. Anyone have any idea how to do this?
Basically you could use Intents to do this, here is an example :
https://stackoverflow.com/a/12739968/5552022
Otherwise, you could use a library like EventBus which handles the process pretty efficiently :
https://github.com/greenrobot/EventBus
// Create a new Intent object as container for the result
final Intent data = new Intent();
// Add the required data to be returned to the MainActivity
data.putExtra(EXTRA_DATA, "Some interesting data!");
// Set the resultCode as Activity.RESULT_OK to
// indicate a success and attach the Intent
// which contains our result data
setResult(Activity.RESULT_OK, data);
// With finish() we close the DetailActivity to
// return back to MainActivity
finish();
You can tranfer your data via bundle:
From your activity use below code to addd data in bundle:
Bundle bundle = new Bundle();
bundle.putString("key", "your string");
// set Fragmentclass data as fragment arguments
YourFragment fobj = new YourFragment();
fobj.setArguments(bundle);
and in Fragment you can get your data:
String strtext = getArguments().getString("key");
Currently trying to use a bundle to transfer information from both my IncomeFragment and ExpenseFragment to HomeFragment but I'm unsure as to how to do it. I've tried implementing doubleA's code which he provided.
This is my onAcceptClicked method from my MainActivity which takes the value of the total income/expense from the relevant fragment and transfers it to the HomeFragment:
public void onAcceptClicked(String fragment, String total) {
final FragmentManager fm = getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
if (fragment == "income") {
HomeFragment homeFrag = new HomeFragment();
Bundle incomeBundle = new Bundle();
incomeBundle.putString(IncomeFragment.TAG, total);
//homeFrag.newInstance(total);
ft.replace(R.id.content_layout, homeFrag, HomeFragment.TAG);
ft.commit();
}
else if (fragment == "expense"){
HomeFragment homeFragment = new HomeFragment();
Bundle expenseBundle = new Bundle();
expenseBundle.putString("bundleIncome", total);
homeFragment.setArguments(expenseBundle);
ft.replace(R.id.content_layout, homeFragment, HomeFragment.TAG);
ft.commit();
}
}
I have an interface in my IncomeFragment which I use to communicate with my MainActivity so I can use the onAcceptClicked method to transfer my totals over. I plan on basically doing the same thing with my ExpenseFragment. The code below is a snippet from my IncomeFragment:
public interface SendIncomeData {
public void onAcceptClicked(String fragment, String total);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_accept:
//Toast.makeText(getActivity(), stringIncomeTotal, Toast.LENGTH_LONG).show();
sendIncomeData.onAcceptClicked("income", stringIncomeTotal);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Unfortunately I'm getting an error with this line of code
sendIncomeData.onAcceptClicked("income", stringIncomeTotal);
This is the error
java.lang.NullPointerException: Attempt to invoke interface method 'void mos.myapplication.IncomeFragment$SendIncomeData.onAcceptClicked(java.lang.String, java.lang.String)' on a null object reference
I don't know why it's saying there's a null object reference and/or how I could fix this error.
I'm guessing there's probably going to be an error displaying my totals in my HomeFragment because I haven't called the method below anywhere within my code in my MainActivity or my IncomeFragment / ExpenseFragment. The reason I haven't used it is because I wasn't sure how to get it so that the HomeFragment opens first when the application is launched.
static HomeFragment newInstance(String total)
{
HomeFragment frag = new HomeFragment();
Bundle args = new Bundle();
args.putString(TAG, total);
frag.setArguments(args);
return frag;
}
I don't even mind starting from scratch, as long as I can transfer totals and display them from IncomeFragment > HomeFragment and also ExpenseFragment > HomeFragment
You need to check if bundle is null in the first place:
bundle = this.getArguments();
if (bundle != null)
{
// continue with your logic
}
Also, all Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly. See below links for more info:
http://developer.android.com/training/basics/fragments/communicating.html
http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
A lot of people will argue that using interfaces is the best way to do that, which isn't really wrong but there are much simpler ways. Edit: not necessarily simpler
-One way is to get a reference to the activity within the fragment by calling
this.getActivity();
then in your activity class you can have a method that passes the data to the other fragment since it has a reference to both fragments.
-Then there's an even better way to do it actually (though that first part is probably helpful too):
In the fragment that has the data that needs to be moved, you can get a reference to the other fragment from the FragmentManager. This assumes that you created that fragment with a string ID like so:
Fragment otherFragment;
getSupportFragmentManager().beginTransaction().add(otherFragment, "otherFrag").commit();
Then in the fragment with the data, you'll do:
FragmentActivity fragmentActivity = (FragmentActivity)getActivity();
OtherFragment otherFragment = (OtherFragment)fragmentActivity.getSupportFragmentManager().findFragmentByTag("otherFrag");
Then with a reference to OtherFragment (in this case), you can do something like:
otherFragment.dataString = "myData";
But you'll probably want to have a test to make sure the other fragment doesn't come back null, and if it is null you might just want to create it then and there since you already have a reference to the FragmentManager.
Edit: I'm just going to say that I like this method more, subjectively.
I am attempting to expand my application by adding a TabHost and some tabs to navigate extra features. The current app basically searches a database. The current application workflow:
App loads to a login screen
User logs in
User gets a search form and inputs data, presses "search"
Search loads a list activity of results...
With the new tabs, there is a separate tab for searching. I want all the seach activities to remain inside that tab group. So I've created an activity group to handle all of these:
public class searchGroup extends ActivityGroup {
public static searchGroup group;
private ArrayList<View> history;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.history = new ArrayList<View>();
group = this;
View view = getLocalActivityManager().startActivity("search", new Intent(this,search.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
replaceView(view);
}
public void replaceView(View v) {
history.add(v);
setContentView(v);
}
public void back() {
if(history.size() > 0) {
history.remove(history.size()-1);
setContentView(history.get(history.size()-1));
}else {
finish();
}
}
#Override
public void onBackPressed() {
searchGroup.group.back();
return;
}
}
In my search activity's Search button onClickListener:
view = searchGroup.group.getLocalActivityManager().startActivity("search_results",new Intent(search.this, search_results.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
searchGroup.group.replaceView(view);
This is where I get the crash:
02-11 13:43:49.481: E/AndroidRuntime(1165): java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.myApp/com.myApp.search_results}:
android.view.WindowManager$BadTokenException: Unable to add window --
token android.app.LocalActivityManager$LocalActivityRecord#40543360 is
not valid; is your activity running?
However, if I uncomment a line from the search_result activity's onCreate:
new LoadSearches().execute();
no crash, but I get nothing obviously. LoadSearches() is an AsyncTask that does the heavy lifting of going out to the server and running the search string and then populating the returned data into the ListActivity in onPostExecute().
I don't quite understand why its crashing here and not normally when I switch activities. How should I tackle this? Is there a better way? I've read a little bit about Fragments but haven't done anything with it yet.
I have decided, after much pulling my hair out, to go with fragments. Some resources I found useful for converting my existing app to use Fragments and tabs:
Fragments in Android 2.2.1, 2.3, 2.0. Is this possible?
http://www.e-nature.ch/tech/?p=55
http://thepseudocoder.wordpress.com/2011/10/04/android-tabs-the-fragment-way/
I also had an issue with pass data between my activities. The way to pass data between activities using an intent/bundle doesn't really work the same but can modified slightly and still work.
The old way (passing data from Activity1 to Activity2):
Activity1
Intent myIntent = new Intent(search.this, search_results.class);
Bundle b = new Bundle();
b.putString("SEARCHSTRING", strSearch);
myIntent.putExtras(b);
startActivityForResult(myIntent, 0);
Activity2
Bundle b = getIntent().getExtras();
strSearch = b.getString("SEARCHSTRING");
Using fragments I had to create an initializer for Activity2:
public search_results newInstance(String strSearch){
search_results f = new search_results();
Bundle b = new Bundle();
b.putString("SEARCHSTRING", strSearch);
f.setArguments(b);
return f;
}
using this, the new method using Fragments:
Avtivity1
Fragment newFragment = new search_results().newInstance(strSearch);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.realtabcontent, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
Activity2 (onCreateView)
Bundle b = getArguments();
strSearch = b.getString("SEARCHSTRING");
I hope this helps someone as it was difficult for me to find all this information in one spot.