I've a fragment register. this one has a view pager inside. I need every page to put a data into register hashmap variable . this what i've tried ..
this is a method that i want to access from every pages
public void addData(String key, String data){
Toast.makeText(this.getActivity(), data, Toast.LENGTH_LONG).show();
}
i've tried like :
FragmentManager fm = getFragmentManager();
fragment = (ArtistRegister)fm.findFragmentById(R.id.asd);
fragment.addData("asd", asd);
but it always return null pointer ..
First solution:
ArtistRegister artistRegister = ((ArtistRegister) getParentFragment());
artistRegister.addData("asd", "asd");
Second solution:
Create interface and pass it as argument for PagerAdapter constructor.
EDIT:
OP used getFragmentManager() instead of getChildFragmentManager() to initialize adapter, so he was constantly getting NullPointerExpception
Related
Situation:
At first fragment on button press I want to open second fragment with
sections
On second fragment I can create new section(or use existed) then on list item
click open third fragment
On third fragment I can write new service(or use existed) and then on button
click return to first fragment
and display Section(from second fragment) and Service(from third
fragment)
My idea is to use fragment.setArguments(bundle) on second fragment and transfer it to third fragment
On third fragment with interface A{public void sendData(data);} I will return variable to fragment one
How I should correctly return variables From AllServicesSectionFragmnet + AllServicecDescriptionFragment to CreateNewServiceFragment?
give Tag to fragmentA
fragmentTransaction.add(new FragmentA(),"frag_Tag")
and in third fragment add
FragmentA fback=FragmentManager.findfragmentByTag("frag_Tag")
and write in backButton method
if(fback!=null)
{
fback.show;
}
You can treat your Fragment as a function: it can be invoked from another Fragment and can return a value (using setTargetFragment and onActivityResult).
When you want another Fragment to give you a value, you invoke it with setTargetFragment and wait for onActivityResult to be called. When invoked fragment opens another Fragment to get its task done, it also should wait for onActivityResult and return a value to caller.
So, pseudocode:
fn fragment1() {
handleData(call fragment2(arg));
}
fn fragment2(arg: T) -> U {
return handle(call fragment3(arg));
}
fn fragment3(arg: T) -> U {
// handle some user input
return value;
}
can be represented as series of setTargetFragment and onActivityResult invocations.
I have three fragments inside an activity. Three text views inside this activities. I have three API calls inside each of the fragments. I need the count of ArrayList created in the three fragments. I tried to make the API call in activity and tried to find out the ArrayList from there and passing it to fragment. But I don't know how to pass this type of ArrayList (Arraylist array) to fragment. I only need three integer values in the activity. So the questions are,
1) Please give me a way to pass value from three fragments to activity by actually loading the view of one fragment and loading the rest of the fragment without views.
2) Or give me a way to pass an ArrayList of model-class created at the activity to three fragments.
1 - Get the size of Array from fragment:
In this case you need to get the instance of the added fragment, and retrieve the values you need from it's global variables.
In fragment:
public List<MyObject> myList;
In Activity:
int size;
MyFragment fragment = (MyFragment)getSupportFragmentManager().findFragmentByTag("myFragmentTag");
if(fragment != null && is fragment.isAdded())
size = fragment.myList.size();
PS: in the above case don't forget to add a TAG to the fragment when you add it
2 - Pass the Array to fragment:
In this case, you need to make the Object Serializable, add it as an argument to the fragment that is about to be added, and then, when the fragment is added, within the fragment, retrieve the previously added Object
Make the Object Serializable and add it to the Arguments from Activity
In Activity:
public MySerializableObjectList myList;
Add the array to fragment in Activity:
MyFragment myFragment = new MyFragment();
fragmentManager = getSupportFragmentManager();
Bundle bundle = new Bundle();
bundle.putSerializable("myArrayTag", myList);
myFragment.setArguments(bundle);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, myFragment,"myFragmentTag").commit();
In Fragment:
public MySerializableObjectList myList;
if(getArguments != null)
myList = (MySerializableObjectList)getArguments().getSerializable("myArrayTag");
List<MySerializableObject> myListObject;
if(myList != null)
myListObject = myList.getMySerializableObjectList();
putParcelableArrayList and getParcelableArrayList trough Bundle in the Fragment arguments.
Okey, lets see. In my opinion the best way to do it is query the info in the activity and passing to the fragment, it means, the second way you proposse.
to do this follow this steps
1) Obtain the List in activity onCreate method.
2) In the fragment, Create a variable and a method that recieve the object from the activity.
public class FormFragment extends Fragment {
List<Object> data;
public FormFragment() {
// Required empty public constructor
}
public void initFragment(List<Object> data){
this.data = data
}
}
3) After create the fragment, use this method to pass the info to the fragment
public class Activity extends AppCompat{
List<Object> data = //Query your data here
/....
FormFragment fragment = new FormFragment()
fragment.init(data)
}
and that is all, you can pass the info this way and works smoothly, also, you can use your data from the activity as you bless.
I have two fragment class named SessionTab and BillingTaband i am trying to create instance of those class using
SessionTab sessionTab = (SessionTab) getSupportFragmentManager().getFragments().get(1);
but sometimes index for those classes are reversed and then it causes ClassCastException
How can i get instance of those fragment class by passing class name instead of index or any way to make sure that index of those class stays the same everytime so it doesn't cause ClassCastException
Use one of this methods : findFragmentById() and findFragmentByTag() methods.
Reference : https://developer.android.com/reference/android/app/FragmentManager.html#findFragmentById(int)
Update :
ClassCastException is invoked when you are not casting the appropriate classes to one another. In your case, Your FragmentManager is returning different fragment than SessionTab, so the exception is thrown.
If you use findFragmentById() or findFragmentByTag() , then it will return the fragment exactly what you want, and exception will not be thrown.
Define a 'tag' for the Fragment while adding it like
getFragmentManager().beginTransaction().add(new Fragment(),"your_tag");
And while referencing it use
getFragmentManager().findFragmentByTag("your_tag");
In most cases, you would like to use YourFragment.class.getSimpleName() as your tag.
First of all, if you should understand that instance for any Fragment you can take from Java class api. Like below:
Class<?> class = Class.forName("example.package.BillingFragment");
Constructor<?> cons = class.getConstructor(BillingFragment.class);
BillingFragment object = (BillingFragment) cons.newInstance();
Code example show, how get Instance from any class in Java. But you talking a little bit other things. If I understand correct, you want to get Fragment from FragmentManager.
You can do it, in case if you already defined Fragment before! For example, you have base application flow, and then you want added Fragment. You can check FragmentManager if there are Fragments in stack. But in case of empty stack, you should manually add them:
String billingFragmentTag = BillingFragment.class.getSimpleName();
......
if (getFragmentManager.findFragmentByTag(billingFragmentTag) == null) {
BillingFragment fragment = new BillingFragment();
String billingFragmentTag = BillingFragment.class.getSimpleName();
FragmentTransaction fragTrans = getFragmentManager().beginTransaction();
fragTrans.add(fragment, billingFragmentTag).commit();
}
......
So after this, you can check if there your Fragment in stack and hook this active instance. This is correct and standard flow for using Fragments.
......
if (getFragmentManager.findFragmentByTag(billingFragmentTag) != null) {
BillingFragment fragment = getFragmentManager.findFragmentByTag(billingFragmentTag);
String billingFragmentTag = BillingFragment.class.getSimpleName();
FragmentTransaction fragTrans = getFragmentManager().beginTransaction();
fragTrans.add(fragment, billingFragmentTag).commit();
}
....
Welcome!
I'm going to be having multiple instances of the same fragments, and I'm trying to get values from within these fragments. The problem I'm having is that, because these are instances of the same fragment/s, the EditTexts/Spinners/Toggle Buttons naturally have the same id's if there are several instances of them. How would I go about getting values from them?
If I use something like
EditText exampleEditText = (EditText) findViewById(R.id.exampleId);
exampleEditText.getText().toString()
I get the value of the first instance, and none of the others.
it depends on for how long you need the data to be there, i mean if u need it even after the app restarts, the best approach would be to create a database and second approach would be TinyDB.
Hope it helps
Just to make sense how to get data from multiple instances of same fragment.
To simulate your example. You,
Have a SampleFragment
Have three instances of SampleFragment
Get value of EditText from an instance
Sample fragment
public class SampleFragment extends Fragment {
private EditText mSampleEditText;
public String getSampleValue(){
String value;
if(mSampleEditText != null){
value = mSampleEditText.getText().toString();
}
return value;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSampleEditText= (EditText) getActivity().findViewById(R.id.editText_sample);
}
}
Sample activity
public class SampleActivity extends AppCompatActivity {
String mInstance1Tag = "instance1";
String mInstance2Tag = "instance2";
String mInstance3Tag = "instance3";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// First instance
transaction.replace(R.id.fragment_container1, new SampleFragment(), mInstance1Tag);
// Second instance
transaction.replace(R.id.fragment_container2, new SampleFragment(), mInstance2Tag);
// Third instance
transaction.replace(R.id.fragment_container3, new SampleFragment(), mInstance3Tag);
transaction.commit();
}
private String getValueFromInstance(String instanceTag) {
SampleFragment fragment = (SampleFragment) getSupportFragmentManager()
.findFragmentByTag(instanceTag);
return fragment.getSampleValue();
}
}
EDIT
After your comment, the question is more clear and also you are right on the questions about tags like 'what would", "where you have".
I'm going to be having multiple instances of the same fragments,
Before start my post, i had supposed you'll have specified fragment instance count. So i set instance count to 3 in my example and then paired instances and tags. Because if you add fragment instances via unique tags, then you can get them.
And dont get stuck on their tags, to make simple i defined them as "instance1", "instance2"...
Trying to dynamically add Fragments to different pages in an Android ViewPager.
Dynamically adding a Fragment to the end of the list of Fragments works fine, but attempting to add to the next slot (the unseen page after the current viewable page). I've tried adding to the arraylist of fragments and using notifyDataSetChanged and trying to use set on each of the fragments after to set each to the previous item.
Edit: updated code
class MainPagerAdapter extends FragmentPagerAdapter {
public MainPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public PageFragment getItem(int position) {
return PageFragment.newInstance(Datamart.getInstance().getURLs().get(position));
}
#Override
public int getCount() {
return Datamart.getInstance().getURLs().size();
}
#Override
public int getItemPosition(Object object) {
PageFragment pageFragment = (PageFragment) object;
for ( int i = 0; i < getCount(); i++ ) {
if ( pageFragment.getURL().equals( Datamart.getInstance().getURLs().get(i) ) ) {
return i;
}
}
return POSITION_NONE;
}
}
Within the Datamart:
public class Datamart {
static Datamart instance;
private ArrayList<String> URLs;
private MainPagerAdapter mainPagerAdapter;
private ViewPager viewPager;
public Datamart() {
URLs = new ArrayList<>();
}
public static Datamart getInstance() {
if (instance == null) {
instance = new Datamart();
}
return instance;
}
public MainPagerAdapter getMainPagerAdapter() {
return mainPagerAdapter;
}
public void setMainPagerAdapter(MainPagerAdapter mainPagerAdapter) {
this.mainPagerAdapter = mainPagerAdapter;
}
public ViewPager getViewPager() {
return viewPager;
}
public void setViewPager(ViewPager viewPager) {
this.viewPager = viewPager;
}
public void addToEnd( String URL ) {
URLs.add(URL);
mainPagerAdapter.notifyDataSetChanged();
}
public void addNext( String URL ) {
URLs.add(viewPager.getCurrentItem() + 1, URL);
mainPagerAdapter.notifyDataSetChanged();
}
public ArrayList<String> getURLs() {
return URLs;
}
public void setURLs(ArrayList<String> URLs) {
this.URLs = URLs;
}
}
ViewPager is doing its darndest to try and keep track of where all the fragments go, and you got it confused because you inserted a fragment in the middle without telling it.
Let's do an example. Say that you have two pages so that you are displaying the first page and the second page is the offscreen page to the right. You have fragment0 for the first page and fragment1 for the second page.
First, keep in mind that since ViewPager is managing the offscreen pages to the immediate left and right, it already thinks it knows what the second page fragment is, which is fragment1.
When you insert a fragment between those existing page fragments, ViewPager is not going to ask you right away which fragment is at the second position, it's going to ask you if the fragment at the second position has changed.
This is where getItemPosition() comes in. You didn't implement getItemPosition() in your FragmentPagerAdapter, so the default behavior of getItemPosition() is to return POSITION_UNCHANGED. (As you'll see, this is why adding a fragment at the end doesn't cause an error.)
So when you called notifyDataSetChanged(), the ViewPager called getCount() and saw that instead of two pages, you now have three. It then called getItemPosition() for page 0 and page 1 (the pages it knew about) and your default implementation told it that nothing had changed.
But something did change, you inserted a page/fragment in the middle of the two existing pages. ViewPager asked you if the second page changed, and your getItemPosition() should have returned 2 instead of POSITION_UNCHANGED.
Now because your getCount() returned 3 instead of 2, ViewPager knows that there is a new page at the end that it doesn't know about, so it calls getItem() to get the new fragment.
Here is where the error occurs. Your getItem() method returned fragment1 for page 3, and ViewPager choked because you handed it the fragment that it already knew about. Specifically, it uses the fragment's tag for some housekeeping. It creates a tag out the the page's container id and the item position (page number). So at any given time it expects that either (a) the tag is null, or (b) the tag will be the same value that it already calculated from the container id and the item position. Neither of those conditions were true, so that's why IllegalStateException was thrown.
So how do you fix this?
You implement a getItemPosition() that does the right thing. When your getItemPosition() is called, you scan through your list of fragments, and when you find a matching fragment, you return the index of the fragment. If you removed a fragment such that there's no matching fragment in your list, you return POSITION_NONE to tell the ViewPager that the page should be removed. ViewPager will then call your getItem() method to get the new page. In this way, ViewPager can always stay in sync with your adapter.
When I write a FragmentPagerAdapter, I don't even use the fragments in the model. If I were writing your adapter, I would just have a list of URLs, since it looks like each page/fragment has it's own unique URL.
I would also implement a getUrl() method on the fragment class to get the URL that the fragment was created with.
So for getItemPosition(), I would call getUrl() on the fragment passed in, and search my adapter's list for that URL. Then I would return the index of the URL in the list, or POSITION_NONE if it's not there any more.
Then in getItem(), I would instantiate a new fragment using the URL at the list position that was passed in. My rule is that I never instantiate a fragment until the ViewPager specifically requests it by calling getItem().
This way, only the ViewPager is accessing the fragments, and I don't run into these types of issues.
Also, don't make any changes to the adapter model between the time when ViewPager calls startUpdate() to when it calls finishUpdate(). This is how ViewPager tells your adapter that it's in a "critical section" of figuring out where all the page fragments go.
PagerAdapters can be a bear to work with. Put some debug logging in your getCount(), getItemPosition(), and getItem() methods so that you can get a feel for how ViewPager uses your adapter to manage its pages.