How to transfer data from different fragments in tabLayout? - android

I have a problem passing the selected Item of my ListView to another fragment.
I have a TabbedActivity with 2 tabs. 1st is called OngletCours and the 2nd is called OngletNotes.
I'm getting an error while passing the Item I clicked on.
I have tried the whole weekend but without sucess to transfer the Item I clicked on to the 2nd tab/fragment.
Here is the code from my 1st Fragment/Tab OngletCours (I'm only showing you the setOnItemClickListener :
l1.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
OngletNotes fragment = ((Onglets)getActivity()).getOngletNotes();
if(fragment == null) {
fragment = OngletNotes.newInstance();
}
//récupération de la position convertie en String de l'item que j'ai choisi
String item = l1.getItemAtPosition(i).toString();
Bundle args = new Bundle();
args.putString("Item",item);
fragment.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.container, fragment).addToBackStack(null).commit();
((Onglets)getActivity()).goToFragment(1);
}
});
My 2nd tab/Fragment OngletNotes looks like this :
public class OngletNotes extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.ongletnotes, container, false);
//where i want to insert the selectedItem
TextView Cours = (TextView)rootView.findViewById(R.id.TVCours);
Bundle bundle=getArguments();
String cours="";
//ERROR !
cours = bundle.getString("Item");
//Retrieve the value
Cours.setText(cours);
return rootView;
}
public static OngletNotes newInstance() {
OngletNotes fragment = new OngletNotes();
// put values which you want to pass to fragment
// Bundle args = new Bundle();
// fragment.setArguments(args);
return fragment;
}
I have the following error :
03-06 12:48:13.959 1033-1033/com.example.dasilvadd.students E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NullPointerException
at com.example.dasilvadd.students.OngletNotes.onCreateView(OngletNotes.java:23)
Line 23 is the following one :
Bundle bundle=getArguments();
Please help me solving this, I really need to advance in my project. Thank you in advance !

Use shared preferences, create a shared preference in OngletCours then read from in OngletNotes. there is a single instance of this class that all clients share , so in this case it makes sense.Go to this link to refresh it code syntax.https://developer.android.com/training/basics/data-storage/shared-preferences.html
hey just remember this for future purposes, serialize your data whenever your store it. a great library is gson. Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.Just something to think about still.

try this
Use Bundle to send String:
YourFragment fragment = new YourFragment();
Bundle bundle = new Bundle();
bundle.putString("YourKey", "YourValue");
fragment.setArguments(bundle);
//Inflate the fragment
getFragmentManager().beginTransaction().add(R.id.container,fragment).commit();
In onCreateView of the new Fragment:
//Retrieve the value
String value = getArguments().getString("YourKey");
i hope it will work for your case

Provide a constructor for your fragment
public OngletNotes () {
setArguments(new Bundle());
}

Don't use Bundle for transfer data if you have only two framgent in the tab.
I will explain you from the beginning..
For ViewPager you need list of Fragments right. Just like below
List<Fragment> fragmentsList = new ArrayList<Fragment>();
fragmentsList.add(Fragment1)-->OngletCours
fragmentsList.add(Fragment2)-->OngletNotes
You will pass the above list in ViewPagerAdapter.
Have one function in Fragment2 like below
public void getDataFromFragmentOne(String item){
// Do the mannipulation
}
When the item clicked in FragmentOne Just call the above function like below
((OngletNotes)getParentFragment.fragmentsList.get(1)).getDataFromFragmentOne(item)..
The above should work perfectly..Because you are not handling data in onCreateView or onCreate.. Whenever the item is clicked you will pass the data to the secondframent which is already there in viewpager because of offsreenpage limt.

in Case of kotlin you can create newInstance in fragment;
class TeamTwoFragment :Fragment {
lateinit var eventsX: EventsX
lateinit var stateList: StateList
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
eventsX = it.getParcelable (EVENT_X)!!
stateList = it.getParcelable(STATE_LIST)!!
}
}
fun newInstance(someInt: EventsX, events: StateList): TeamTwoFragment {
val myFragment = TeamTwoFragment().apply {
val args = Bundle()
args.putParcelable(EVENT_X, someInt)
args.putParcelable(STATE_LIST, events)
setArguments(args)
}
return myFragment
}
And from tablayout activity or fragments when setup tablayout:
setupViewPager(binding.viewPager,TeamOneFragment().newInstance(eventsX,events))

Related

Initialize and Declare Bundle in same line while sending data from one fragment to another

So the problem is not a technical issue, but more of an aesthetic kind.
I am passing data from one fragment to another fragment. So there are 3 fragments in total and the first two are calling the same 3rd fragment, so to identify in the third fragment from which of the first two it was invoked I am using the following code
in the first fragment
Bundle bundle = new Bundle();
bundle.putBoolean("isFirst", true)
Fragment fragment = new ThirdFragment();
fragment.setArguments(bundle);
loadFragment(fragment);
and in the second fragment as
Bundle bundle = new Bundle();
bundle.putBoolean("isFirst", false)
Fragment fragment = new ThirdFragment();
fragment.setArguments(bundle);
loadFragment(fragment);
and in the third fragment
Bundle bundle = this.getArguments();
Boolean isFirst = bundle.getBoolean("isFirst",false);
if(isFirst){
....
} else{
....
}
the code works fine but I think there should be a more elegant way of doing it. If not atleast make the whole thing into one line without additional declarations such as Bundle bundle and Fragment fragment
for example something like
loadFragment(new ThirdFragment().setArguments(new Bundle().putBoolean("isFirst",true)));
I am relatively new to android and java programming so please don't be harsh.
I think you should declare static method getInstance(Boolean isFirst) in ThirdFragment example
public static ThirdFragment getInstance(Boolean isFirst) {
Bundle bundle = new Bundle();
bundle.putBoolean("isFirst", isFirst)
Fragment fragment = new ThirdFragment();
fragment.setArguments(bundle);
return fragment
}
In First and SecondFragment call
loadFragment(ThirdFragment.getInstance(true));
you can create newIstance() in ThirdFragment like stated here
you can also achieve the same by the below code
public class Util {
static Fragment getThirdFragment(FragmentManager fragmentManager, Boolean isFirst, #NonNull ClassLoader classLoader, #NonNull String className) {
Bundle bundle = new Bundle();
bundle.putBoolean("isFirst", isFirst);
Fragment fragment = fragmentManager.getFragmentFactory().instantiate(classLoader, className);
fragment.setArguments(bundle);
return fragment;
}
}
and call it
loadFragment(Util.getThirdFragment(getSupportFragmentManager(),true/*is first boolean value*/, ThirdFragment.class.getClassLoader(), ThirdFragment.class.getName()));
Kotlin
put this code inside ThirdFragment
companion object {
#JvmStatic
fun newInstance(param1: Boolean) =
ThirdFragment().apply {
arguments = Bundle().apply {
putBoolean("isFirst", param1)
}
}
}
use bundleOf("key" to "value") ex :
findNavController(it).navigate(
R.id.action_sendSmsFragment_to_webViewFragment,
bundleOf(
"age" to 25,
"name" to "Michael",
"skill" to null
)
)

Android: Create different web from passing parameters in 1st activity using fragment

I am a beginner in writing Android app.
I am confused when passing parameters from 1st activity to 2nd activity when 2nd activity is using fragment.
Here is what i would like to do. I would like to switch to webview activity that show corresponding webpage from the 1st activity parameter: routeName.
e.g. if routeName = A, display A.html. otherwise display default.html
Here are my coding:
In 1st activity:
Intent intent = new Intent(getActivity(), RouteInfoWebActivity.class);
intent.putExtra("routeName", routeName);
startActivity(intent);
WebView Activity and Fragment class
public class RouteInfoWebActivity extends FragmentHolder {
private RouteInfoWebFragment routeInfoWebFragment;
public RouteInfoWebActivity() {
routeInfoWebFragment = new RouteInfoWebFragment(getIntent().getExtras().getString("routeName","defaultKey"));
}
protected Fragment fragment() { return routeInfoWebFragment; }
#Override
public void onBackPressed() {
RouteInfoWebFragment routeWeb = (RouteInfoWebFragment) routeInfoWebFragment;
WebView htmlView = routeWeb.getWebView();
if (htmlView.canGoBack()) {
htmlView.goBack();
} else {
super.onBackPressed();
}
}
}
public class RouteInfoWebFragment extends LocalWebFragment {
String url = "";
public RouteInfoWebFragment(String routeName) {
If (routename == 'A') {
url == 'A.html';
} else {
url = 'default.html';
}
super("file:///android_asset/"+url, R.layout.route_web);
}
#Override
public View onCreateView(final LayoutInflater inflater,
final ViewGroup container,
final Bundle savedInstanceState) {
final View routeWebView = super.onCreateView(inflater, container, savedInstanceState);
return routeWebView;
} // onCreateView
However, I saw the warning in Fragment class when doing so:
Avoid non-default constructor in Fragment.
As I have set all corresponding properties in "LocalWebFragment" which I do not want to change it.
I know in Fragment I can use new instance to pass parameters before linking it to activity. However, wondering how can it be done on my case please? Is there any easy way to do so apart from creating a new Fragment parent?
Thank you for your help.
You can pass the arguments in the form of a bundle and call setArguments(Bundle bundle) on your fragment object. In your fragment you can get the values by calling getArguments() and extracting what you want from that bundle.
EDIT
First of all, you need to get a object of your fragment and set the arguments.
Fragment fragment = new RouteInfoWebFragment();
Bundle bundle = new Bundle();
bundle.putString("routeName", routeName);
fragment.setArguments(bundle);
Then in your fragment class you can simply get the value of routeName
Bundle arguments = getArguments();
String routeName = arguments.getString("routeName");

How do I use the same fragment for three tabs with different content?

I have an enum describing three different sports:
public enum MatchType {
S1(0, "Sport1", "xml stream address", R.id.match_list, R.layout.fragment_match_list, R.color.separator_sport1),
S2(0, "Sport2", "xml stream address", R.id.match_list, R.layout.fragment_match_list, R.color.separator_sport2),
S3(0, "Sport3", "xml stream address", R.id.match_list, R.layout.fragment_match_list, R.color.separator_sport3);
...getters/setters
}
I then have fragment with
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
matchesArrayAdapter = new MatchListAdapter(getActivity(), new ArrayList<Match>());
return inflater.inflate(matchType.getLayout(), container, false);
}
Also in my fragment I have an AsyncTask where I have this
#Override
protected void onPostExecute(final List<Match> matches) {
if (matches != null) {
matchListView = (ListView) getActivity().findViewById(matchType.getRId());
[setup listeners]
matchesArrayAdapter.matchArrayList = matches;
matchListView.setAdapter(matchesArrayAdapter);
}
}
EDIT:
In my Activity I have an AppSectionsPagerAdapter with
public Fragment getItem(int i) {
MatchListSectionFragment fragment = new MatchListSectionFragment();
Bundle bundle = new Bundle();
bundle.putInt(Constants.MATCH_TYPE, i);
fragment.setArguments(bundle);
return fragment;
}
EDIT 2:
Here's my onCreate and onCreateView from my fragment:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
matchType = MatchType.getMatchType(bundle.getInt(Constants.MATCH_TYPE));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
matchesArrayAdapter = new MatchListAdapter(getActivity(), new ArrayList<Match>());
return inflater.inflate(matchType.getLayout(), container, false);
}
The AsyncTask reads an xml stream for each of the sports in my enum but my problem is that tab #1 is overwritten with data from tab #2 and subsequently tab #3.
Before I had a fragment defined for each sport but surely that can't be necessary?
How do I go about using the same fragment with the same layout for each sport?
When instantiating your fragment in your Activity set the Fragment's arguments with a Bundle.
Bundle myBundle = new Bundle();
myBundle.putInt(MY_EXTRA, 1);
myFragment.setArguments(myBundle);
In your bundle put some Extra that will be read in the fragment's onCreate() callback.
int i = getArguments().getInt(MY_EXTRA);
I am on mobile.
Put three FrameLayouts in a LinearLayout, named frame1, frame2 and frame 3. This will be your main Activity's layout.
Then in the Activity's oncreate() method, call getFragmentManager().getFragmentTransaction().
Instantiate the three fragments and send them the data, preferably through a Bundle.
On the Fragment Transaction call the add() or replace() method for each fragment, the first parameter is the id of the respective FrameLayout, the second parameter is the fragment itself.
Call commit().
You should create the newInstance method in your fragment, also you should store MatchType instansce in you fragment.
MatchType matchType;
public static MyFragment newInstance(MatchType matchType) {
MyFragment fragment = new MyFragment();
fragment.matchType = matchType;
return fragment;
}
In your Activity you should to create 3 instances of MyFragment with this method (with related to each fragment it owns MatchType). Then in onCreateView method you should insert data to your views from matchType.
Sorry, I'm on mobile. And sorry for my English.
Update
Check your variable matchType. Maybe it declared as static?

Passing an Object from an Activity to a Fragment

I have an Activity which uses a Fragment. I simply want to pass an object from this Activity to the Fragment.
How could I do it?
All the tutorials I've seen so far where retrieving data from resources.
EDIT :
Let's be a bit more precise:
My Activity has a ListView on the left part. When you click on it, the idea is to load a Fragment on the right part.
When I enter this Activity, an Object Category is given through the Intent. This Object contains a List of other Objects Questions (which contains a List of String). These Questions objects are displayed on the ListView.
When I click on one item from the ListView, I want to display the List of String into the Fragment (into a ListView).
To do that, I call the setContentView() from my Activity with a layout. In this layout is defined the Fragment with the correct class to call.
When I call this setContentView(), the onCreateView() of my Fragment is called but at this time, the getArguments() returns null.
How could I manage to have it filled before the call of onCreateView() ?
(tell me if I'm not clear enough)
Thanks
Create a static method in the Fragment and then get it using getArguments().
Example:
public class CommentsFragment extends Fragment {
private static final String DESCRIBABLE_KEY = "describable_key";
private Describable mDescribable;
public static CommentsFragment newInstance(Describable describable) {
CommentsFragment fragment = new CommentsFragment();
Bundle bundle = new Bundle();
bundle.putSerializable(DESCRIBABLE_KEY, describable);
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
mDescribable = (Describable) getArguments().getSerializable(
DESCRIBABLE_KEY);
// The rest of your code
}
You can afterwards call it from the Activity doing something like:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = CommentsFragment.newInstance(mDescribable);
ft.replace(R.id.comments_fragment, fragment);
ft.commit();
In your activity class:
public class BasicActivity extends Activity {
private ComplexObject co;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_page);
co=new ComplexObject();
getIntent().putExtra("complexObject", co);
FragmentManager fragmentManager = getFragmentManager();
Fragment1 f1 = new Fragment1();
fragmentManager.beginTransaction()
.replace(R.id.frameLayout, f1).commit();
}
Note: Your object should implement Serializable interface
Then in your fragment :
public class Fragment1 extends Fragment {
ComplexObject co;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Intent i = getActivity().getIntent();
co = (ComplexObject) i.getSerializableExtra("complexObject");
View view = inflater.inflate(R.layout.test_page, container, false);
TextView textView = (TextView) view.findViewById(R.id.DENEME);
textView.setText(co.getName());
return view;
}
}
You should create a method within your fragment that accepts the type of object you wish to pass into it. In this case i named it "setObject" (creative huh? :) ) That method can then perform whatever action you need with that object.
MyFragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
fragment = new MyFragment();
getSupportFragmentManager().beginTransaction().add(android.R.id.content, detailsFragment)
.commit();
} else {
fragment = (MyFragment) getSupportFragmentManager().findFragmentById(
android.R.id.content);
}
fragment.setObject(yourObject); //create a method like this in your class "MyFragment"
}
Note that i'm using the support library and calls to getSupportFragmentManager() might be just getFragmentManager() for you depending on what you're working with
Get reference from the following example.
1. In fragment:
Create a reference variable for the class whose object you want in the fragment. Simply create a setter method for the reference variable and call the setter before replacing fragment from the activity.
MyEmployee myEmp;
public void setEmployee(MyEmployee myEmp)
{
this.myEmp = myEmp;
}
2. In activity:
//we need to pass object myEmp to fragment myFragment
MyEmployee myEmp = new MyEmployee();
MyFragment myFragment = new MyFragment();
myFragment.setEmployee(myEmp);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_layout, myFragment);
ft.commit();
Passing arguments by bundle is restricted to some data types. But you can transfer any data to your fragment this way:
In your fragment create a public method like this
public void passData(Context context, List<LexItem> list, int pos) {
mContext = context;
mLexItemList = list;
mIndex = pos;
}
and in your activity call passData() with all your needed data types after instantiating the fragment
WebViewFragment myFragment = new WebViewFragment();
myFragment.passData(getApplicationContext(), mLexItemList, index);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.my_fragment_container, myFragment);
ft.addToBackStack(null);
ft.commit();
Remark: My fragment extends "android.support.v4.app.Fragment", therefore I have to use "getSupportFragmentManager()". Of course, this principle will work also with a fragment class extending "Fragment", but then you have to use "getFragmentManager()".
To pass an object to a fragment, do the following:
First store the objects in Bundle, don't forget to put implements serializable in class.
CategoryRowFragment fragment = new CategoryRowFragment();
// pass arguments to fragment
Bundle bundle = new Bundle();
// event list we want to populate
bundle.putSerializable("eventsList", eventsList);
// the description of the row
bundle.putSerializable("categoryRow", categoryRow);
fragment.setArguments(bundle);
Then retrieve bundles in Fragment
// events that will be populated in this row
mEventsList = (ArrayList<Event>)getArguments().getSerializable("eventsList");
// description of events to be populated in this row
mCategoryRow = (CategoryRow)getArguments().getSerializable("categoryRow");
If the data should survive throughout the application lifecycle and shared among multiple fragments or activities, a Model class might come into consideration, which has got less serialization overhead.
Check this design example
This one worked for me:
In Activity:
User user;
public User getUser(){ return this.user;}
In Fragment's onCreateView method:
User user = ((MainActivity)getActivity()).getUser();
Replace the MainActivity with your Activity Name.

How to use setArguments() and getArguments() methods in Fragments?

I have 2 fragments: (1)Frag1 (2)Frag2.
Frag1
bundl = new Bundle();
bundl.putStringArrayList("elist", eList);
Frag2 dv = new Frag2();
dv.setArguments(bundl);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.the_fragg,dv);
ft.show(getFragmentManager().findFragmentById(R.id.the_fragg));
ft.addToBackStack(null);
ft.commit();
How do I get this data in Frag2?
Just call getArguments() in your Frag2's onCreateView() method:
public class Frag2 extends Fragment {
public View onCreateView(LayoutInflater inflater,
ViewGroup containerObject,
Bundle savedInstanceState){
//here is your arguments
Bundle bundle=getArguments();
//here is your list array
String[] myStrings=bundle.getStringArray("elist");
}
}
EDIT:
Best practice is read and save arguments in onCreate method. It's worse to do it in onCreateView because onCreateView will be called each time when fragment creates view (for example each time when fragment pops from backstack)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
}
Eg: Add data:-
Bundle bundle = new Bundle();
bundle.putString("latitude", latitude);
bundle.putString("longitude", longitude);
bundle.putString("board_id", board_id);
MapFragment mapFragment = new MapFragment();
mapFragment.setArguments(bundle);
Eg: Get data :-
String latitude = getArguments().getString("latitude")
You have a method called getArguments() that belongs to Fragment class.
in Frag1:
Bundle b = new Bundle();
b.putStringArray("arrayname that use to retrive in frag2",StringArrayObject);
Frag2.setArguments(b);
in Frag2:
Bundle b = getArguments();
String[] stringArray = b.getStringArray("arrayname that passed in frag1");
It's that simple.
Instantiating the Fragment the correct way!
getArguments() setArguments() methods seem very useful when it comes
to instantiating a Fragment using a static method.
ie Myfragment.createInstance(String msg)
How to do it?
Fragment code
public MyFragment extends Fragment {
private String displayMsg;
private TextView text;
public static MyFragment createInstance(String displayMsg)
{
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.setString("KEY",displayMsg);
fragment.setArguments(args); //set
return fragment;
}
#Override
public void onCreate(Bundle bundle)
{
displayMsg = getArguments().getString("KEY"): // get
}
#Override
public View onCreateView(LayoutInlater inflater, ViewGroup parent, Bundle bundle){
View view = inflater.inflate(R.id.placeholder,parent,false);
text = (TextView)view.findViewById(R.id.myTextView);
text.setText(displayMsg) // show msg
returm view;
}
}
Let's say you want to pass a String while creating an Instance. This
is how you will do it.
MyFragment.createInstance("This String will be shown in textView");
Read More
1) Why Myfragment.getInstance(String msg) is preferred over new MyFragment(String msg)?
2) Sample code on Fragments
for those like me who are looking to send objects other than primitives,
since you can't create a parameterized constructor in your fragment, just add a setter accessor in your fragment, this always works for me.
If you are using navigation components and navigation graph create a bundle like this
val bundle = bundleOf(KEY to VALUE) // or whatever you would like to create the bundle
then when navigating to the other fragment use this:
findNavController().navigate(
R.id.action_navigate_from_frag1_to_frag2,
bundle
)
and when you land the destination fragment u can access that bundle using
Bundle b = getArguments()// in Java
or
val b = arguments// in kotlin

Categories

Resources