Calling fragment from a list adapter - android

I am using sliding menu/drawer pattern in my app. So the main activity has a leftView which is a ListFragment named topicsFragment() which loads set of topic items. When an item/topic is clicked it replaces the fragment on main view by calling the FeedsFragment(tag). FeedsFragment uses arraylist adapter to load the feeds which has various clickable items in each list item. I want to fetch another instance on the feedsFragment(tag) when an item is clicked within a list item.
holder.contextView= (TextView) newsView.findViewById(R.id.arcHeader);
if (item.hasArc()) {
holder.contextView.setVisibility(View.VISIBLE);
String arc;
try {
arc=item.getarc();
holder.contextView.setText(arc);
holder.contextView.setOnClickListener(new View.OnClickListener() {
//currently it loads a class
#Override
public void onClick(View v) {
Intent i = new Intent(context, SomeClass.class);
i.putExtra("tag", arc);
context.startActivity(i);
}
});
} catch (JSONException e) {
e.printStackTrace();
}
} else {
holder.contextView.setVisibility(View.GONE);
}
Currently it loads a new class. I want to define a fragment and then pass to main activity to replace with the current view but I cant use getSupportFragmentManager() inside an adapter class but only in a fragment or fragment activity. What should be an alternative to sweeping in a fragment from an adapter?

What I did was create this method in my main activity and just called it from other classes to change the fragment:
public void switchContent(Fragment fragment) {
mContent = fragment;
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment).commit();
slidemenu.showContent();
}

Solved it by using the context passed in the list adapter:
#Override
public void onClick(View v) {
Fragment newFragment = new ListFragmentClass(tag);
if (newFragment != null)
switchFragment(newFragment);
}
private void switchFragment(Fragment newFragment) {
if (context == null)
return;
if (context instanceof MainActivity) {
MainActivity feeds = (MainActivity) context;
feeds.switchContent(newFragment);
}
}
Here switchContent is method defined in your main activity for switching/replacing fragment as given in answer by Justin V.

Pass getFragmentManager() as a parameter in constructor of your adapter and use that.

Use an Interface to connect your side drawer ListFragment to the main activity. For example:
public class LeftDrawer extends ListFragment{
private DrawerCallback mCallback;
public interface DrawerCallback{
public void onListClick(String tag);
}
public void setCallback(DrawerCallback callback){
mCallback = callback;
}
}
As Fragments should have an empty constructor, use a public method within your Fragment to set the callback before completing the FragmentTransaction adding it to your drawer. At this point all that is left is notifying your Fragment that a click has occurred. What you should do is actually catch the click in your ListFragment directly rather than adding on onClickListener to every view in your adapter.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
/*
* Get item at the clicked position from your adapter and
* get its string tag before triggering interface
*/
mCallback.onListClick(tag);
}
Use the onListItemClick method to do this. You will get the list position that was clicked and can easily then get that item from your adapter and get its tag value to pass back to your host activity.

Related

Android - call fragment from a recycler view inside another fragment

I have an application (Java) which originally had 5 sections. All of these are fragments and they are accessed by 5 icons in the bottom navigation. However, one of the sections (Lessons) is now being replaced by a different fragment which contains a recycler view. Under this new design, one of the items in the recycler view will call the Lessons fragment.
The question is, how can I call the Lessons fragment from within the Recycler View contained in the new fragment?
Usually inside a recycler view I'd use code like the following:
#Override
public void onClick(View v) {
int index = getAdapterPosition();
LessonItem item = lessonList.get(index);
Intent intent = new Intent(context, SomeActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("lesson", item);
intent.putExtras(bundle);
((Activity) context).startActivityForResult(intent, 1);
}
but in this case I'm not dealing with an activity. Is there a way I can accomplish this without having to convert the fragment to an activity?
As ismailfarisi mentioned before, if you use Navigation Component, it makes the transition easier.
However, if you want to still manage fragment replacements manually, you can interfaces as callback.
interface LessonItemListener {
void onItemClick(LessonItem item);
}
in your recycler view adapter
class YourAdapter {
public YourAdapter(LessonItemListener listener) {
this.listener = listener;
}
private LessonItemListener listener;
...
#Override
public void onClick(View v) {
int index = getAdapterPosition();
LessonItem item = lessonList.get(index);
listener.onItemClick();
}
}
in your fragment has recyclerview
class YourFragment {
private LessonItemListener listener;
public void setListener(LessonItemListener listener) {
this.listener = listener;
}
private void setupRecyclerView() {
YourAdapter adapter = new YourAdapter(listener);
recyclerView.setAdapter(adapter);
}
}
in your Activity contains those fragments
class YourActivity extends AppCompatActivity implements LessonItemListener {
private void setupFragments() {
YourFragment fragment = new YourFragment();
fragment.setListener(this);
}
...
#Override
public void onItemClick(LessonItem item) {
//you are in activity now
//make whatever you want here
//such as fragment replacement in your bottom nav
}
}
navigation component from jetpack is better for handling fragment transition
you can check this documentation https://developer.android.com/guide/navigation

Android: passing data back to fragment using interfaces

Hi in my Activity I have a fragmentA with a textview, when I click on the textview , this fragmentA is replaced with fragment which has a listview. Now when I click on the litsItem I have to goback to fragmentA and update the textview with the list item.
Implementation:
I created an interface in fragment,
public interface OnListItemSelectedListener {
public void onListItemSelected(String msg);
}
and in onAttach() I have the below code
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
try {
mListener = (OnListItemSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnListItemSelectedListener");
}
}
In my listitem OnClickListener() I have this
mListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String message = parent.getItemAtPosition(position).toString();
mListener.onListItemSelected(message);
}
});
then in my activity i implemented the interface
#Override
public void onListItemSelected(String msg) {
// TODO Auto-generated method stub
ISOFragment myFrag = (ISOFragment)
getSupportFragmentManager().findFragmentById(R.id.isomain);
if (myFrag != null) {
myFrag.incrementdata(msg);
} else {
ISOFragment newFrag = new ISOFragment();
Bundle args = new Bundle();
args.putString("selecteitem", msg);
newFrag.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.content_frame, newFrag);
transaction.addToBackStack(null);
transaction.commit();
}
}
Now since the fragmentA is not available it goes to else part now how should i get the bundle arguments to fragmentA and update the textview.
Suppose I am going from A to B and coming back from B to A, if i get arguments and update the textview in Fragment A in onCreateView(), if when i run for the first time it is checking for the arguments which will be null.
I had the same problem and the best solution for me was to extend activity and store shared data there. My new activity had a get data function that returned an object of class MyData implements Parcelable (Serializeable would work for simple data). The data was stored in onSaveInstanceState in the activity and restored in the activivitys onCreate.

What is the proper way to send data from one fragment to another?

I have a Fragment with a "pick a year" button. This button adds a ListFragment to the backstack, where the user can pick a year. Once a year is chosen, I want to dispose of the ListFragment and return to the first fragment. What is the best way to update the first fragment, with the data that was selected in the ListFragment?
TL;DR: Fragment1 opens Fragment2, user chooses option in Fragment2. How do I update Fragment1 with this data?
My current solution is a public class with static members, but I'm wondering if Android has a better way.
All Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly. [Source]
Define an interface in Fragment2, and implement this interface in the host Activity. When you call the interface method from Fragment2, you can then access Fragment1 from inside the interface method on the Activity and pass the appropriate data to Fragment1 via its public methods.
Create an interface:
public class Fragment2 extends ListFragment {
OnItemSelectedListener mCallback;
public interface OnItemSelectedListener {
public void onItemSelected(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (OnItemSelectedListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnItemSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCallback.onItemSelected(position);
}
}
Add implements Fragment2.OnItemSelectedListener to your activity definition, and define the onItemSelected method:
public void onItemSelected(int position) {
Fragment1 fragment = (Fragment1)
getSupportFragmentManager().findFragmentById(R.id.fragment1);
if (fragment != null) {
fragment.updateValue(position);
}
}

Sending data from nested fragments to parent fragment

I have a Fragment FR1 that contains several Nested Fragments; FRa, FRb, FRc. These Nested Fragments are changed by pressing Buttons on FR1's layout. Each of the Nested Fragments have several input fields within them; which include things like EditTexts, NumberPickers, and Spinners. When my user goes through and fills in all the values for the Nested Fragments, FR1 (the parent fragment) has a submit button.
How can I then, retrieve my values from my Nested Fragments and bring them into FR1.
All Views are declared and programmatically handled within each Nested Fragment.
The parent Fragment, FR1 handles the transaction of the Nested Fragments.
I hope this question is clear enough and I am not sure if code is necessary to post but if someone feels otherwise I can do so.
EDIT 1:
Here is how I add my Nested Fragments:
tempRangeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, tempFrag)
.commit();
}
});
scheduleButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, scheduleFrag)
.commit();
}
});
alertsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getChildFragmentManager().beginTransaction()
.add(R.id.settings_fragment_tertiary_nest, alertsFrag)
.commit();
}
});
submitProfile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
constructNewProfile();
}
});
where my constructNewProfile() method needs the values from my Nested Fragments.
public Fragment tempFrag = fragment_profile_settings_temperature
.newInstance();
public Fragment scheduleFrag= fragment_profile_settings_schedules
.newInstance();
public Fragment alertsFrag = fragment_profile_settings_alerts
.newInstance();
The above refers to the fields of the parent fragment; and how they are initially instantiated.
The best way is use an interface:
Declare an interface in the nest fragment
// Container Activity or Fragment must implement this interface
public interface OnPlayerSelectionSetListener
{
public void onPlayerSelectionSet(List<Player> players_ist);
}
Attach the interface to parent fragment
// In the child fragment.
public void onAttachToParentFragment(Fragment fragment)
{
try
{
mOnPlayerSelectionSetListener = (OnPlayerSelectionSetListener)fragment;
}
catch (ClassCastException e)
{
throw new ClassCastException(
fragment.toString() + " must implement OnPlayerSelectionSetListener");
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
onAttachToParentFragment(getParentFragment());
// ...
}
Call the listener on button click.
// In the child fragment.
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.tv_submit:
if (mOnPlayerSelectionSetListener != null)
{
mOnPlayerSelectionSetListener.onPlayerSelectionSet(selectedPlayers);
}
break;
}
}
Have your parent fragment implement the interface.
public class Fragment_Parent extends Fragment implements Nested_Fragment.OnPlayerSelectionSetListener
{
// ...
#Override
public void onPlayerSelectionSet(final List<Player> players_list)
{
FragmentManager fragmentManager = getChildFragmentManager();
SomeOtherNestFrag someOtherNestFrag = (SomeOtherNestFrag)fragmentManager.findFragmentByTag("Some fragment tag");
//Tag of your fragment which you should use when you add
if(someOtherNestFrag != null)
{
// your some other frag need to provide some data back based on views.
SomeData somedata = someOtherNestFrag.getSomeData();
// it can be a string, or int, or some custom java object.
}
}
}
Add Tag when you do fragment transaction so you can look it up afterward to call its method. FragmentTransaction
This is the proper way to handle communication between fragment and nest fragment, it's almost the same for activity and fragment.
http://developer.android.com/guide/components/fragments.html#EventCallbacks
There is actually another official way, it's using activity result, but this one is good enough and common.
Instead of using interface, you can call the child fragment through below:
( (YourFragmentName) getParentFragment() ).yourMethodName();
The best way to pass data between fragments is using Interface. Here's what you need to do:
In you nested fragment:
public interface OnDataPass {
public void OnDataPass(int i);
}
OnDataPass dataPasser;
#Override
public void onAttach(Activity a) {
super.onAttach(a);
dataPasser = (OnDataPass) a;
}
public void passData(int i) {
dataPasser.OnDataPass(i);
}
In your parent fragment:
public class Fragment_Parent extends Fragment implements OnDataPass {
...
#Override
public void OnDataPass(int i) {
this.input = i;
}
btnOk.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag("0");
((Fragment_Fr1) fragment).passData();
}
}
}
You can use share data between fragments.
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, item -> {
// Update the UI.
});
}
}
More Info ViewModel Architecture
You can use getChildFragmentManager() and find nested fragments, get them and run some methods to retrieve input values
Check for instanceOf before getting parent fragment which is better:
if (getParentFragment() instanceof ParentFragmentName) {
getParentFragment().Your_parent_fragment_method();
}
Passing data between fragments can be done with FragmentManager. Starting with Fragment 1.3.0-alpha04, we can use setFragmentResultListener() and setFragmentResult() API to share data between fragments.
Official Documentation
Too late to ans bt i can suggest create EditText object in child fragment
EditText tx;
in Oncreateview Initialize it. then create another class for bridge like
public class bridge{
public static EditText text = null;
}
Now in parent fragment get its refrence.
EditText childedtx = bridge.text;
now on click method get value
onclick(view v){
childedtx.getText().tostring();
}
Tested in my project and its work like charm.

Button in Fragment's ListView item Interface Definition?

In my app, I have an activity that has two fragments in actionbar tabs navigation mode, just like the android developer site example.
in my first fragment I have a listview (which has it's own adapter ) and each item of the listview has a button called +1. I want to refresh the second fragment that shows the items in listview in first fragment that their +1 button's clicked.
I know i have to use interfaces. but I cant figure how to use them. where do I have to define the interface? how to use it? and how to access it from the activity to refresh the second fragment?
a quick help would be great. thanks.
If you want it on List Item Click
Fragment A:
public class FragmentA extends ListFragment {
OnItemSelectedListener mListener;
...
// Container Activity must implement this interface
public interface OnItemSelectedListener {
public void onItemSelected(int position);
}
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnItemSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnItemSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
mCallback.onItemSelected(position);
}
}
ContainerActivity:
public class ContainerActivity extends FragmentActivity
implements FragmentA.OnItemSelectedListener
{
//...
public void onItemSelected(int Position/*pass anything which u want*/)
{
SecondFragment second_fragment = (SecondFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentB);
if(second_fragment !=null)
{
second_fragment.UpdateUI(Position);
}
}
}
Second Fragment:
public class SecondFragment extends Fragment {
...
public void UpdateUI(Position)
{
}
}
Hope this helps. On click of a Button inside each listitem might be bit difficult, but try the same approach. May be you have to write the interface declaration and call in your custom adapter.

Categories

Resources