I am trying in vain to simply take a value from FormActivity and use it to fill a EditText in a Fragment. I have to wait for activity to retrieve the value from a remote server and populate the local SQLite table with it, this means no solution I have tried from within the fragment has worked (null error because it hasn't been populated that early).
I need help.
Relevant section of FormActivity.java
public void DrawText() {
// Fetching user details from sqlite
HashMap<String, String> user = db.getUserDetails();
if (user.size() != 0) {
Log.e(TAG, "string surname: " + surname);
// Displaying the user details on the fragment
FirstFragment f1 = new FirstFragment();
//put info into a bundle to pass to fragments
Bundle drawbundle = new Bundle();
drawbundle.putString("surname", surname);
f1.setArguments(drawbundle);
FragmentManager FM = getSupportFragmentManager();
FragmentTransaction FT = FM.beginTransaction();
FT.add(R.id.something, f1);
FT.commit();
}else{
Log.e(TAG, "table was empty");
}
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return FirstFragment.newInstance("#string/form_instruct");
case 1: return SecondFragment.newInstance("SecondFragment, Instance 1");
case 2: return ThirdFragment.newInstance("ThirdFragment, Instance 1");
case 3: return FourthFragment.newInstance("FourthFragment, Instance 1");
//case 4: return FifthFragment.newInstance("ThirdFragment, Instance 3");
default: return FirstFragment.newInstance("FirstFragment, Default");
}
}
Obviously, id.something is not correct, I do not know how to get the id. I read I can use a tag, but my attempt at that did not work. I tried the following:
FirstFragment fragA = (FirstFragment) getSupportFragmentManager().findFragmentByTag("fragA");
Here is my FirstFragment.java
public class FirstFragment extends android.support.v4.app.Fragment {
//create variables & Logcat tag
private static final String TAG = FirstFragment.class.getSimpleName();
private EditText inputTitle;
private EditText inputName;
private EditText inputSurname;
//private SQLiteHandler db;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_first, container, false);
TextView tv = (TextView) v.findViewById(R.id.tvFragFirst);
tv.setText(getArguments().getString("msg"));
inputSurname = (EditText) getActivity().findViewById(R.id.surnameText);
inputSurname.setText(getArguments().getString("surname"));
return v;
}
public static FirstFragment newInstance(String text) {
FirstFragment f = new FirstFragment();
Bundle b = new Bundle();
b.putString("msg", text);
f.setArguments(b);
return f;
}
I'm going around in circles with this, can anyone please help?
if you are using a ContentProvider you could use a ContentObserver to get notified when your table is filled up, and when onChange is invoked, you can update the TextView. If you are not using a ContentProvider, yo could use the LocalBroadcastManger and a BroadcastReceiver to achieve the same thing
Create interface implement your fragment with it after fragment creation access your activity and save your interface reference in activity, after your operation will complete access your method from activity using saved interface reference and update your fragment.
Second option add your fragment with tag and using this fragment manager find your fragment by tag than you have the reference of your fragment than simply call your method inside your activity
Related
I am a newbie in Android development. I am facing an issue. I need some help from you guys.
Firstly, I am working on an application that is similar to BookMyShow.
I have an activity that contains a fragment. The activity contains a list of timeslots in a recycler view.
When I click on one of the timeslots, I go to new activity where I book the show with the specific details like username, id, timeslot_selected, etc and once he submits the "SUBMIT" button in the activity, it should come back to the same fragment that he was in, earlier, and show his details on the fragment. Initial there is nobody in the recycler view, now the user should see himself in that recycler view at the selected timeSlot as an icon.
I have the next button as well. When the user clicks on it, I am replacing the fragment with the following date. If the user clicks on one of the slots, he would be redirected to the same booking activity and once he submits, he should come back to the previous fragment with the same date that he was on earlier and with an updated icon of himself.
Now, I am unable to show that updated icon in the previous fragment once he clicks submit on the booking activity. Can you please suggest what should I do?
I tried detaching and attaching the fragment but to no avail. Please help me with a solution. Thanks in Advance!
SampleActivity.java:
public class SampleActivity extends AppCompatActivity {
TextView text;
Person person;
String id, name, date;
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
Intent intent = getIntent();
id = intent.getStringExtra("id");
name= intent.getStringExtra("name");
date= intent.getStringExtra("date");
person= (Person) getIntent().getSerializableExtra("person");
text= findViewById(R.id.name);
text.setText(name);
Bundle bundle = new Bundle();
bundle.putString("id", id);
bundle.putString("name", name);
bundle.putString("date", date);
bundle.putSerializable("Person", person);
FragmentA newFragment = new FragmentA();
newFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.mainFrameLayout, newFragment, "main_fragment").commit();
}
FragmentA.java:
public class FragmentA extends Fragment implements View.OnClickListener {
RecyclerView recyclerView;
public FragmentA() {
}
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_new, container, false);
recyclerView = view.findViewById(R.id.slots);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
requestQueue = VolleySingleton.getmInstance(getActivity()).getRequestQueue();
newList = new ArrayList<>();
next = view.findViewById(R.id.nextButton);
timeView = view.findViewById(R.id.timeOn);
dateText= view.findViewById(R.id.date);
Bundle bundle = getArguments();
assert bundle != null;
id= bundle.getString("id");
name = bundle.getString("name");
date = bundle.getString("date");
person = (Person) bundle.getSerializable("Person");
next.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
if (v.getId()== R.id.nextButton) {
replaceFragment();
}
}
private void replaceFragment() {
Bundle bundle = new Bundle();
bundle.putString("id", id);
bundle.putString("name", name);
bundle.putString("date", date);
bundle.putSerializable("Person", person);
bundle.putSerializable("hashmap", (Serializable) hashmap);
fm = requireActivity().getSupportFragmentManager();
ft = fm.beginTransaction();
f = new FragmentFirst();
f.setArguments(bundle);
ft.replace(R.id.fragmentLayout, f, "main_fragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void refreshData() {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentByTag("main_fragment");
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if(currentFragment != null) {
fragmentTransaction.detach(currentFragment);
fragmentTransaction.attach(currentFragment);
fragmentTransaction.commit();
}
}
}
As I see you are trying to go to a new instance of FragmentA in your booking activity. If you want to send data to an activity, process the data and return the result, in your case you could do it by starting new activity for result by startForActivityResult and also set the result before finish the activity with setResult method in your booking activity. In this case you can use the result via onActivityResult method. But I suggest you to use fragment for the booking process as well instead of activity.
I have a ListView in a Fragment that is populated when the app starts.
I put a ParcelableArrayList in a Bundle in my newInstance method, and I get it back in my OnCreateView after passing the ArrayList in the newInstance method in my Activity (which is the data read from the SQLite database).
This part works, as I display my data in my Fragment correctly.
I implemented a button that removes all data from the table, and I would now like to update my view after I cleaned the table.
The remove all button is handled in my main activity where I call my database handler to empty the table.
What is the best way to do that ? Here are the parts of the code that seem relevant to me :
My Fragment class :
public class MainFragment extends Fragment {
public static final String RECETTES_KEY = "recettes_key";
private List<Recette> mRecettes;
private ListView mListView;
public MainFragment() {
// Required empty public constructor
}
public static MainFragment newInstance(List<Recette> r) {
MainFragment fragment = new MainFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(RECETTES_KEY, (ArrayList<? extends Parcelable>) r);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRecettes = getArguments().getParcelableArrayList(RECETTES_KEY);
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
configureListView();
}
// Configure ListView
private void configureListView(){
this.mListView = getView().findViewById(R.id.activity_main_list_view);
RecetteAdapter adapter = new RecetteAdapter(getContext(), mRecettes);
mListView.setAdapter(adapter);
}
}
Relevant parts from my Main acivity :
This is in my OnCreate method :
mDatabaseHandler = new DatabaseHandler(this);
mRecettes = mDatabaseHandler.readRecettes();
mDatabaseHandler.close();
This is in the method I use to show a fragment :
if (this.mMainFragment == null) this.mMainFragment = MainFragment.newInstance(mRecettes);
this.startTransactionFragment(this.mMainFragment);
Let me know if I should add more of my code, this is my first time posting :)
Lucile
In your R.layout.fragment_main, you can add an id to the root view, say with android:id#+id/fragment_root
And whenever you want to change the fragment view:
In activity:
MainFragment fragment = (MainFragment) getSupportFragmentManager().getFragmentById(R.id.fragment_root);
fragment.updateList(mRecettes);
And then create the new method updateList() in your MainFragment
public void updateList(List<Recette> recettes) {
mRecettes.clear();
mRecettes.addAll(recettes);
configureListView();
}
Also you can tag your fragment when you add it to your transaction instead of using its id, and then use getSupportFragmentManager().getFragmentByTag()
I am trying to call a function from my mainActivity to change a TextView in one of my fragments. I have read a couple posts on the best way of doing it but for some reason, none of them seem to work for me. I know the function is working because once a press the button the toast comes up but for some reason the text won't change. I was wondering what the issue could be, or if I am just missing an additional step.
here is the method being called in my mainActivity
public class MainActivity extends AppCompatActivity implements Tab1Fragment.OnCalcClickListener{
private static final String TAG = "MainActivity";
private SectionsPageAdapter mSectionsPageAdpater;
private ViewPager mViewPager;
Tab1Fragment tab1Fragment = new Tab1Fragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: Starting");
//initializing FragmentManager so the fragments can communicate
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, tab1Fragment);
fragmentTransaction.commit();
//declare sections page adapter
mSectionsPageAdpater = new SectionsPageAdapter(getSupportFragmentManager());
//Set up the view pager with the sections adapter
mViewPager = (ViewPager) findViewById(R.id.container);
setUpViewPager(mViewPager);
//create a tab layout object and set it's id to tabs (mainActivity.xml)
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
//
}
// create a sections page view adapter
private void setUpViewPager(ViewPager viewPager){
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(), "Day");
adapter.addFragment(new Tab2Fragment(), "Info");
adapter.addFragment(new Tab3Fragment(), "Week");
viewPager.setAdapter(adapter);
}
//initialise calculator object
Calculator mainCalculator = new Calculator();
#Override
public void calculateClick(int to_calculate) {
switch (to_calculate){
case 1:
Toast.makeText(getBaseContext(),"working", Toast.LENGTH_SHORT).show();
mainCalculator.freqDay = mainCalculator.freqDay + 1;
mainCalculator.freqWeek = mainCalculator.freqWeek + 1;
mainCalculator.getTotalDay();
tab1Fragment.updateInfo();
break;
}
}
Here is the code for my fragment
public class Tab1Fragment extends Fragment implements
View.OnClickListener{
private static final String TAG = "Tab1Fragment";
//Establishing the buttons & Methods
Button btn1;
Button btn2;
TextView dayView;
OnCalcClickListener onCalcClickListener;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tab1_fragment, container, false);
//Connecting the buttons to the xml
btn1 = (Button) view.findViewById(R.id.btn_1);
btn1.setOnClickListener(this);
btn2 = (Button) view.findViewById(R.id.btn_2);
btn2.setOnClickListener(this);
dayView = (TextView) view.findViewById(R.id.total_Sales_Day);
return view;
}
//Onclick listener for buttons
public void setOnClickListener(View.OnClickListener listener) {
btn1.setOnClickListener(listener);
btn2.setOnClickListener(listener);
}
//method that will bring data back from activity and set the text
public void updateInfo(){
Toast.makeText(getContext(),"65", Toast.LENGTH_SHORT).show();
dayView.setText("test");
}
To make calls to methods from your fragment in the activity class you need something like this:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Here the activity is calling the updateArticleView method from the fragment, instead of your updateInfo method, but you will get the idea.
Also pay attention to the one-pane scenario, where you need to swap the content and push the arguments using a Bundle object.
See Deliver a Message to a Fragment for more details.
When you add the fragment set a tag to it like this:
MyFragment frag = new MyFragment();
frag.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, frag, "TAG").commit();
While updating the textview get the instance of fragment using findFragmentByTag()
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("TAG");
fragment.updateInfo();
In my MainActivity I call a Fragment and set the boolean mFragment to true when its active. Now I set some Text in the TextViews declared in the Fragment and it works fine. But when a Button declared in the Fragment calls a Method in the MainActivity suddently mFragment is false and I can't use getText from the TextViews because they are null. I have no idea why this is so.
Main Activity
public class MainActivity extends AppCompatActivity implements SensorEventListener {
MainFragment mainFragment;
HistoryActivity historyFragment;
boolean mFragment = false;
//....
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainFragment = new MainFragment();
historyFragment = new HistoryActivity();
if(!mFragment) {
getMainFragment();
}
//...SenserManager and so on
#Override
public void onSensorChanged(SensorEvent event){
if (mFragment) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
DecimalFormat df = new DecimalFormat("0.000");
//This works constantly:
mainFragment.textViewX.setText("X = " + df.format(x));
mainFragment.textViewY.setText("Y = " + df.format(y));
mainFragment.textViewZ.setText("Z = " + df.format(z));
}
}
public void writeEntry(){ //called in Fragment
if(mFragment) {
//This doesn't work (isn't even called because mFragment is false)
String x = (String) mainFragment.textViewX.getText();
String y = (String) mainFragment.textViewY.getText();
String z = (String) mainFragment.textViewZ.getText();
}
}
public void getMainFragment() {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, mainFragment);
transaction.addToBackStack(null);
transaction.commit();
mFragment = true;
}
Fragment
public class MainFragment extends Fragment {
TextView textViewX;
TextView textViewY;
TextView textViewZ;
Button button;
MainActivity mainActivity = new MainActivity();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
textViewX = (TextView) view.findViewById(R.id.textViewX);
textViewY = (TextView) view.findViewById(R.id.textViewY);
textViewZ = (TextView) view.findViewById(R.id.textViewZ);
button = (Button) view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mainActivity.writeEntry();
}});
return view;
}
}
Use callback interface to interact from fragment back to activity. Please refer. It's a very recommended method. http://developer.android.com/training/basics/fragments/communicating.html#Implement
Your architecture has many flaws. You create a fragment instance and are then calling methods on it. You can't do this in android for components such as activities, fragments, services etc (You can only do this for Java classes). You cannot simply create an object of fragment like this. All Fragments, Activities and Services in Android must go through their respective lifecycles so that they have a valid context attached to them.
Also the fragment activity interaction should be done via interfaces. Not by simply calling methods on their objects which must not be created in the first place. You might get it working but ultimately it will keep causing you problems. I recently answered two questions this and this which had the same problem. Seems like lot of people have this doubt.
Your communication and a few point is wrong.
With below usage probably you wanted to access current MainAcitivity's method or fields. But this isn't the current instance of MainAcitivity. You just have instantiated a new one (also without lifecycle of activity)
MainActivity mainActivity = new MainActivity();
So this why the mFragment boolen variable is false and also other items are null, like textviews.
You could refer below links
http://developer.android.com/intl/es/training/basics/fragments/communicating.html
http://www.truiton.com/2015/12/android-activity-fragment-communication/
This question already has answers here:
How to pass values between Fragments
(18 answers)
Closed 7 years ago.
I want to pass a string call custID from one fragement to anopther. but I don't know how to pass it. Below is my code:
class TabsAdapter extends FragmentPagerAdapter {
public TabsAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
return 2;
}
#Override
public Fragment getItem(int i) {
switch(i) {
case 0: return MaterialUpConceptFakePage.newInstance();
case 1: return MaterialUpConceptFakePage.newInstance();
}
return null;
}
#Override
public CharSequence getPageTitle(int position) {
switch(position) {
case 0: return "Tab 1";
case 1: return "Tab 2";
}
return "";
}
}
Can someone help me on this?
Bundle bundle=new Bundle();
bundle.putString("ID", "value");
MyFragment obj=new MyFragment ();
obj.setArguments(bundle);
well you can use bundle as below -
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
getFragmentManager()
.beginTransaction()
.replace(R.id.body, fragment, null)
.commit();
and then inside onCreateView() you can receive as below -
Bundle args = getArguments();
int myInt = bundle.getInt(key, defaultValue);
User Bundle to pass any value from one Fragment to another. This is how you can pass string from one Fragment to another.
Put the value
SecondFragment secondFragment = new SecondFragment ();
Bundle args = new Bundle();
args.putString("MyKey", "MyValue");
secondFragment.setArguments(args);
Load the second fragment
getFragmentManager().beginTransaction().add(R.id.container, secondFragment).commit();
In onCreateView of the second Fragment:
//Retrieve the value
String value = getArguments().getString("MyKey");
While a simple Bundle like other answers works, I can already see you use the newInstance so I will show you an example while still using newInstance to make the code easier to maintain in the future.
In your fragment where you want the String to be add this code
public static YourFragmentName newInstance(String str) {
YourFragmentName fragment = new YourFragmentName ();
Bundle args = new Bundle();
args.putSerializable("customer_id", str);
fragment.setArguments(args);
return fragment;
}
Then looking at your code instead of
MaterialUpConceptFakePage.newInstance()
you should have
MaterialUpConceptFakePage.newInstance(customerid)
Then inside your onCreateView
String customer_id = (String) getArguments().get("customer_id");
SharedPreference is a good way for passing data between activities or fragment. You can send any data int,boolean, string int etc.
SharedPreferences preference;
//Initialize preference
preference = getActivity().getSharedPreferences("STATE",MODE_PRIVATE);
// it uses key-value pairs
// put string data to preference
preference.edit().putString("Your_String_Data", "anything").commit();
//use this to get that value in any fragment.
preference = getActivity().getSharedPreferences("STATE",
Context.MODE_PRIVATE);
String data = preference.getString("Your_String_Data",null);