Fragment already active - When trying to setArguments - android

I am using the example give in the below link
http://android-er.blogspot.in/2013/04/handle-onlistitemclick-of-listfragment.html
Here i have two classes one extending List Fragment and other extending Fragment.
Now i am passing object to detailfragment in this way :
*from ListFragment *
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Detailfragment detailFragment = (Detailfragment)getFragmentManager().findFragmentById(detailFragmentID);
Bundle bundle = new Bundle();
bundle.putSerializable(BUNDLE_KEY, obj);// passing this object
detailFragment.setArguments(bundle);
detailFragment.setUpLayout();// update the UI
}
Now in the Fragment class i receive it,basic goal is to update the UI of the fragment based on the item selected in the list fragment, thats the reason i am sending the object
Bundle b = getArguments();
b.getSerializable(BUNDLE_KEY);
Now on item selected it says "Fragment already active".
What is the issue here? what am i doing wrong?

Another solution is to create an empty constructor for your fragment.
public Detailfragment() {
super();
// Just to be an empty Bundle. You can use this later with getArguments().set...
setArguments(new Bundle());
}
and in the onListItemClick method you use that bundle:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Detailfragment detailFragment = (Detailfragment)getFragmentManager().findFragmentById(detailFragmentID);
// Update the keys.
detailFragment.getArguments().putSerializable(BUNDLE_KEY, obj);// passing this object
detailFragment.setUpLayout();// update the UI
}
Now you can call the getArguments() methond in your setUpLayout() method.

From the Official Android development Reference:
public void setArguments (Bundle args) Supply the construction arguments for this fragment. This can only be called before the fragment has been attached to its activity; that is, you should call it immediately after constructing the fragment. The arguments supplied here will be retained across fragment destroy and creation.
Your fragment is already attached to its activity
i suggest you to use your own method, you don't need setArguments!
create your own setUIArguments(Bundle args) inside the fragment class and update the fragment UI inside this method
You will call this method in this way:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Detailfragment detailFragment = (Detailfragment)getFragmentManager().findFragmentById(detailFragmentID);
Bundle bundle = new Bundle();
bundle.putSerializable(BUNDLE_KEY, obj);// passing this object
detailFragment.setUIArguments(bundle); /* your new method */
}
in your fragment class
public void setUIArguments(Bundle args) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
/* do your UI stuffs */
}
}
}

You can check if there are already arguments, and if so just add/update them.
private static void initFrag(Fragment frag, Bundle args) {
if (frag.getArguments() == null) {
frag.setArguments(args);
} else {
//Consider explicitly clearing arguments here
frag.getArguments().putAll(args);
}
}
Optionally, you might want to clear away existing arguments if you can't safely assume that pre-existing arguments are still valid.

This one global variable:
private FragmentManager fragmentmanager;
private FragmentTransaction fragmenttransaction;
These code put in your "List Fragment" onCreate() Activity :
fragmenttransaction = fragmentmanager.beginTransaction();
fragmenttransaction.replace(detailFragmentID, detailFragment, "test");
fragmenttransaction.addToBackStack(null);
fragmenttransaction.commit();
These is Drawerlistitem click event:
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Bundle bundle = new Bundle();
fragmenttransaction = fragmentmanager.beginTransaction();
if(fragmentmanager.findFragmentById("test") != null) {
fragmenttransaction.remove(fragmentmanager.findFragmentByTag("test"));
}
Detailfragment detailFragment = (Detailfragment)getFragmentManager().findFragmentById(detailFragmentID);
bundle.putSerializable(BUNDLE_KEY, obj);// passing this object
detailFragment.setArguments(bundle);
fragmenttransaction.replace(detailFragmentID, detailFragment, "test");
fragmenttransaction.addToBackStack(null);
fragmenttransaction.commit();
}
Now Extending Fragment code as it is:
Bundle b = getArguments();
b.getSerializable(BUNDLE_KEY);

Dialogue fragment's public method
public void setBundle(final Bundle bundle) {
final Bundle arguments = getArguments();
arguments.clear();
arguments.putAll(bundle);
}
Show or update dialogue fragment
public void showMessageDialogue(final String tag, final Bundle bundle) {
final Fragment fragment = mFragmentManager.findFragmentByTag(tag);
if (fragment != null && fragment instanceof MessageDialogueFragment) {
((MessageDialogueFragment) fragment).setBundle(bundle);
} else {
final MessageDialogueFragment messageDialogueFragment = new MessageDialogueFragment();
messageDialogueFragment.setArguments(bundle);
messageDialogueFragment.show(mFragmentManager, tag);
}
}

Related

How can i pass adapter to fragment like in intent

I am new to android and I am trying to call my MapFragment from adapter after on click using intent below is my code
Below is adapter code:
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
final BusInfo info = getItem(position);
View view = LayoutInflater.from(context).inflate(R.layout.bus_only_list,null);
TextView busname;
busname = (TextView) view.findViewById(R.id.busname);
busname.setText(info.name);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pref = context.getSharedPreferences("busInfo",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putString("bus_name",info.name);
editor.commit();
Intent intent = new Intent(context, MapsFragment.class);
intent.putExtra("name",info.name);
context.startActivity(intent);>
}
});
return view;
}
I want to pass to mapfragment using intent but it redirect to MainActivity instead of MapFragment. How can I stop transferring to MainActivity?
Thank you.
A common pattern to passing a value to a Fragment is using newInstance method. In this method you can set Argument to fragment as a means to send the value.
First, create the newInstance method:
public class YourFragment extends Fragment {
...
// Creates a new fragment with bus_name
public static YourFragment newInstance(String busName) {
YourFragment yourFragment = new YourFragment();
Bundle args = new Bundle();
args.putString("bus_name", busName);
yourFragment.setArguments(args);
return yourFragment;
}
...
}
Then you can get the value in onCreate:
public class YourFragment extends Fragment {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the value from arguments
String busName = getArguments().getString("bus_name", "");
}
...
}
You can set the value to the Fragment from your activity with:
FragmentTransaction fragTransaction = getSupportFragmentManager().beginTransaction();
YourFragment yourFragment = YourFragment.newInstance("bus_name_value");
fragTransaction.replace(R.id.fragment_place_holder, yourFragment);
fragTransaction.commit();
You can use the above codes to send the value in Fragment initialization.
If you want to set the value to the already instantiated fragment, you can create a method then invoke the method to set the value:
public class YourFragment extends Fragment {
...
public setBusName(String busName) {
// set the bus name to your fragment.
}
...
}
Now, In the activity, you can invoke it with:
// R.id.yourFragment is the id of fragment in xml
YourFragment yourFragment = (YourFragment) getSupportFragmentManager()
.findFragmentById(R.id.yourFragment);
yourFragment.setBusName("bus_name_value");
You cannot pass an intent to a Fragment. Try using a Bundle instead.
Bundle bundle = new Bundle();
bundle.putString("name", info.name);
mapFragment.setArguments(bundle)
In your Fragment (MapsFragment) get the Bundle like this:
Bundle bundle = this.getArguments();
if(bundle != null){
String infoName = bundle.getString("name");
}
As guys mentioned before:
1. Use callback or just casting on your context (your activity must handle changing fragments itself).
2. To change fragments use activity's FragmentManager - intent is used to start another activity.
Fragments Documentation

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.

Trouble Passing object Fragment to Fragment

I am trying to pass an object Fragment -> Activity -> Fragment.
My 2nd Fragment says my object is null when getting arguments:
Fragment A: (Sending Object, communicator is interface to Main Activity)
meetsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Meet meet = new Meet();
meet = meetList.get(position); // meet is not null here
communicator.changeToolbarTitle(meet.getName());
****** Sends Meet object to main activity ********
communicator.sendMeetToMeetProfile(meet);
}
});
Main Activity:
#Override
public void sendMeetToMeetProfile(Meet meet) {
MeetAthletesListContainer meetAthletesListContainer = new MeetAthletesListContainer();
***** Fragment is not replaced just called *******
MeetAthletesMales meetAthletesMales = new MeetAthletesMales();
MeetAthletesFemales meetAthletesFemales = new MeetAthletesFemales();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Bundle bundleMales = new Bundle();
bundleMales.putParcelable("meetAthletesMales", meet);
meetAthletesMales.setArguments(bundleMales);
Bundle bundleFemales = new Bundle();
bundleFemales.putParcelable("meetAthletesFemales", meet);
meetAthletesFemales.setArguments(bundleFemales);
******* Replaces current fragment with container that contains above (2) fragments *******
transaction.replace(R.id.frameLayout, meetAthletesListContainer, "meetAthletesListContainer");
transaction.addToBackStack(null);
transaction.commit();
}
Fragment B: (Fragment is contained inside another fragment)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_meet_athletes_males, container, false);
Log.e("", "Fragment onCreateView Called!");
initializeVar();
*****Says this meet object is null*****
meet = getArguments().getParcelable("meetAthletesMales");
}
I am replacing a fragment with another but passing the object to a fragment which is inside another fragment(meet_container_fragment). So my object is being sent directly to the fragment. I got this working in another instance where I actually replace the fragment but I want to replace the FRAGMENT CONTAINER, not the actual fragment B
Try this
MeetAthletesListContainer meetAthletesListContainer = new MeetAthletesListContainer();
***** Fragment is not replaced just called *******
MeetAthletesMales meetAthletesMales = new MeetAthletesMales();
MeetAthletesFemales meetAthletesFemales = new MeetAthletesFemales();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Bundle bundle = new Bundle();
bundle.putParcelable("meetAthletesMales", meet);
bundle.putParcelable("meetAthletesFemales", meet);
meetAthletesFemales.setArguments(bundle);
******* Replaces current fragment with container that contains above (2) fragments *******
transaction.replace(R.id.frameLayout, meetAthletesListContainer, "meetAthletesListContainer");
transaction.addToBackStack(null);
transaction.commit();
Try this,
main activity
FragmentB fragmentb = FragmentB.newInstance(appContext,meet);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.contentContainer, fragmentb , tag);
Fragment B
public static FragmentB newInstance(AppContext appContext, Meet meet) {
FragmentB fragment = new FragmentB();
Bundle args = new Bundle();
args.putSerializable(ARG_APP_CONTEXT, appContext);
args.putString(ARG_MEET_NAME, meet.name);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
appContext = (AppContext) getArguments().get(ARG_APP_CONTEXT);
name= getArguments().getString(ARG_MEET_NAME);
}
}
also make Meet implements Serializable

Fragment communication not working, my app keeps crashing

I have tried many things, such as the 2 references: http://developer.android.com/training/basics/fragments/communicating.html & http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity along with some help from others on StackOverflow and I just cannot get my ListFragment (FragmentA) to send just a simple string to another ListFragment (FragmentB). My app keeps crashing telling me there is a NullPointerException when I click the list in FragmentA going into FragmentB. I have been stuck on this for 2 days now and I just feel like smashing my head against a wall. If anyone knows what is wrong please post code to fix my problem.
MainActivity:
import com.example.fragmentcommunication.FragmentB.OnDataPass;
public class MainActivity extends Activity implements OnDataPass{
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
String librarySelected = libraryList[position];
Fragment newFragment = null;
if (librarySelected.equals("Item1")){
newFragment = new FragmentA();
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.tab2, newFragment, "FragA");
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.commit();
}
});
}
public void onDataPass(String data) {
// TODO Auto-generated method stub
FragmentB transaction1 = ((FragmentB) getFragmentManager().findFragmentByTag("FragB"));
transaction1.use(data);
}
}
FragmentA:
public class FragmentA extends ListFragment{
...
OnDataPass dataPasser;
public interface OnDataPass{
public void onDataPass(String data);
}
#Override
public void onAttach(Activity a) {
super.onAttach(a);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
dataPasser = (OnDataPass) a;
} catch (ClassCastException e) {
throw new ClassCastException(a.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
String libraryList;
//Get the position the user clicked.
Fragment newFragment = null;
libraryList = l.getItemAtPosition(position).toString();
dataPasser.onDataPass(libraryList);
if(libraryList.equals("Ranged")){
newFragment = new FragmentB();
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.tab2, newFragment, "FragB");
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.commit();
}
}
FragmentB:
public class FragmentB extends ListFragment{
...
String getListInfo;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
//Testing to see if the String was passed from Fragment A.
System.out.println(getListInfo);
...
public void use(String data) {
// TODO Auto-generated method stub
this.getListInfo = data;
}
}
I just cannot get my ListFragment (FragmentA) to send just a simple string to another ListFragment (FragmentB).
Since the primary point behind fragments is that they might not both exist on the screen at the same time (e.g., on -normal screens), FragmentA should not be trying to "send just a simple string to" FragmentB. FragmentB may not exist.
If an event occurs in FragmentA that may have UI effects beyond FragmentA, FragmentA should tell its hosting activity about the event. The hosting activity can then route the event to the other fragment, either by directly calling a method on it (if the activity hosts FragmentB as well), creating it and adding it to the UI (and passing in the data using a factory method, like newInstance()), or by calling startActivity() to launch another activity (if there is insufficient room for FragmentA and FragmentB, and therefore we have a separate activity showing FragmentB).
With respect to your existing code, getListInfo is null because you never assign any value to it.

pass ArrayList<HashMap<String, String>> to a fragment

i have 3 ArrayList> that I want to pass to 3 fragments. Besides making them static, what is the best approach to do this?
You can use the setArguments in the Fragment. Take a look at http://developer.android.com/guide/components/fragments.html, basically, you create a Bundle before create your Fragment and then setup as an Argument.
Example from the Android Documentation:
public static class DetailsActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
}
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
Instead of use getIntent().getExtras(), you create you bundle and set the arguments
Bundle bundle = new Bundle();
bundle.putSerializable(YOUR_KEY, yourObject);
fragment.setArguments(bundle);
And for your Fragment:
public static class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());
int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
4, getActivity().getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);
text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
return scroller;
}
}
You can create listener callback interfaces and implement them in your fragments. Something like this:
#Override
public void onSomeEvent(List<SomeData> data) {
//do something with data
}
In your activity create this interface:
public interface OnSomeEventListener {
onSomeEvent(List<SomeData> data);
}
then obtain your fragment by using findFragmentById or findFragmentByTag and assign it to a listener:
this.onSomeEventListener = fragment;
You can then call methods of that interface and your fragment will receive callbacks.
The second and more easier way of communication between fragments and activities is BroadcastReceivers. You can register some BroadcastReceiver in your fragments and then call sendBroadcast() from activity. Your list of data can be put in a bundle of that broadcast message.

Categories

Resources