transfer data between 2 fragments of a TabLayout Android Studio - java

So I have an app with a TabLayout. In there, I created 2 tabs (fragments).My first fragment is OngletCours and the 2nd one OngletNotes.
I have a ListView in the first tab/fragment. I would like to transfer the Item I clicked in that ListView to the 2nd Fragment to a TextView.
I have already tried something but I get a NullPointerException at line 23:
03-06 09:38:32.874 23677-23677/com.example.dasilvadd.students E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NullPointerException
at com.example.dasilvadd.students.OngletNotes.onCreateView(OngletNotes.java:23)
here's the code from my 1st tab OngletCours (Only the setOnItemClickListener):
final ListView l1 = (ListView) rootView.findViewById(R.id.ListCours);
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) {
l1.getItemAtPosition(i);
//Put the value
OngletNotes onotes = new OngletNotes();
Bundle args = new Bundle();
args.putString("Item","l1.getItemAtPosition(i)");
onotes.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.container, onotes).commit();
}
((Onglets)getActivity()).goToFragment(1);
}
});
return rootView;
}
Here's the code from my 2nd tab OngletNotes:
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);
//Retrieve the value
//THE ERROR IS HERE !
String cours = getArguments().getString("Item");
Cours.setText(cours);
return rootView;
}
public static OngletNotes newInstance() {
OngletNotes fragment = new OngletNotes();
return fragment;
}
So, I don't know how to transfer the selected Item into the 2nd tab.
Do I have to create methodes in my TabbedActivity called Onglets? Please tell me if you need the code for that class as well.
Thank you in advance.

I think you got a bit confused in your logic. You are checking for null and then not doing anything if the fragment is null.
You can simplify it like this:
First check if fragment is null , if so create a new instance, then
put the arguments outside the if/else so you make sure you get them every time.
Also put your string item in a variable.
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
OngletNotes fragment = ((Onglets)getActivity()).getOngletNotes ();
if(fragment == null) {
fragment = OngletNotes.getInstance();
}
String item = adapterView.getItemAtPosition(i).toString();
//Put the value
Bundle args = new Bundle();
args.putString("Item",item);
fragment.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.container, fragment).commit();
}

Related

How to amend an ArrayList with data sent between two fragments?

I have an array list which is responsible for storing a collection of exercises names as 'Workouts'. The array list, situated in Fragment A, gets its data from an argument sent through a Bundle in Fragment B.
When a user wants to pick an exercise they press an option of 2 buttons on Fragment A which populates different exercises names on Fragment B. When an exercise is picked in Fragment B then the exercise name is sent back to Fragment A.
The argument taken from Fragment B is meant to be appended to the array list in Fragment A, however every time the Fragment A is reloaded the array list is refreshed therefore removing the previous exercise that was saved. I know this is because new ArrayList<String>() is defined in the onCreateView of Fragment A but is there a way that it can only be created once? (on Fragment A's initial creation rather than every transition between Fragment B & A).
OnCreateView of Fragment A:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view =inflater.inflate(R.layout.fragment_editor, container, false);
//BUTTON SETUP
final Button addUpButton = (Button) view.findViewById(R.id.btnAddUpper);
addUpButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newExe(addUpButton);
}
});
final Button addLowButton = (Button) view.findViewById(R.id.btnAddLower);
addLowButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newExe(addLowButton);
}
});
ListView listView = (ListView) view.findViewById(R.id.lstWorkout);
//CREATE AN ARRAY LIST TO AMMEND WITH EXERCISES
workoutSave = new ArrayList<String>();
if (getArguments() == null) {
return view;
}
else{
getValue= getArguments().getString("Movement");
workoutSave.add(getValue);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(), R.layout.item_list, R.id.txtWorkout, workoutSave);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
}
return view;
}
How Fragment A is reloaded from Fragment B when list item is pressed:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String exercise = lstExe.get(position);
Fragment myFragment = new EditorFragment();
Bundle args = new Bundle();
args.putString("Movement", exercise);
myFragment.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.frame_layout,myFragment).commit();
}
});

How do I update my Fragment after data modification in my activity (SQLite)?

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()

Overriding an adapter

I use an adapter to manipulate my listView , to have a nicer result i overrided the adapter. the problem is that when i use "setOnItemClickListener" to open another fragment with getting the content of the clicked item nothing happened!
ClientAdapter adapter = new ClientAdapter(
getActivity(),R.layout.item_client, R.id.textV, clients);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3 {
FragmentManager fragmentManager = getFragmentManager();
Client t = (Client) lv.getItemAtPosition(arg2);
Modifier_Client fargmentACharger = new Modifier_Client();
fargmentACharger.setClient(t);
fragmentManager.beginTransaction().replace(R.id.container, fargmentACharger).addToBackStack(null).commit();
}
});
It's not a clear what the problem do you have
onItemClickListener don't work ?
You can't send data to another fragment ?
I don't see how you send data to another fragment, but you should use something like this:
Bundle args = new Bundle();
args.putString("client", t);
fargmentACharger.setArguments(args);
or parselable the class Client
An get it at fragment
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
.....
client = getArguments().getString("client");
}

How to run only one fragment on screen?

I want to run a single fragment from another fragment. I try:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.lecturers_fragment,
container, false);
ListView list = (ListView) rootView.findViewById(R.id.lecturersList);
final List<Lecturer> allLecturersList = LecturerDatabaseHelper
.getAllLecturers(getActivity());
if (allLecturersList != null) {
LecturerItemAdapter lecturerAdapter = new LecturerItemAdapter(
mCurrentActivity, allLecturersList);
list.setAdapter(lecturerAdapter);
}
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view,
int index, long id) {
Lecturer lecturer = allLecturersList.get(index);
L.i("Boulder name is playing link it contains"
+ lecturer.getName());
Intent intent_lecturer = new Intent(mCurrentActivity,
LecturerFragment.class);
intent_lecturer.putExtra(LecturerFragment.SELECTED_LECTURER,
lecturer);
mCurrentActivity.startActivity(intent_lecturer);
}
});
return rootView;
}
In my logcat i have this:
03-25 22:04:36.092: E/AndroidRuntime(12453): Caused by: java.lang.ClassCastException: com.asi.sesjaapp.view.LecturerFragment cannot be cast to android.app.Activity
How can I do it?
Intent intent_lecturer = new Intent(getActivity(), YourActivity.class);
intent_lecturer.putExtra(LecturerFragment.SELECTED_LECTURER, lecturer);
mCurrentActivity.startActivity(intent_lecturer);
You are in a fragment, instead of mCurrentActivity just give your parent activity, something like this:
new Intent(getActivity() , LecturerFragment.class);
and again it looks like LecturerFragment.class is a fragment it should be an activity.
Note: Make sure your parent activity extends FragmentActivity
If this answer didn't help you please post your Parent Activity code and fragments code.

Fragment replace doesn't work always

This is my situation:
I have several fragments added dynamicly to an FragmentStatePagerAdapter, this works fine. But now i want to be able to replace an fragment when I push on an button.
public class QuestionFragment extends UpperFragment {
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setRetainInstance(true);
CustomViewPager.enabled = true;
View rootView = inflater.inflate(R.layout.question, container, false);
Button btn = ((Button) rootView.findViewById(R.id.bQuestion));
if (how == true) {
btn.setVisibility(View.VISIBLE);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// lijst afgaan met alle how en kijken welke id nodig is
for (int i = 0; i < XmlParserSax.howFragments.size(); i++) {
Fragment how = XmlParserSax.howFragments.get(i);
if (howId.equals(((UpperFragment) how).getIdNum())) {
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction
.replace(R.id.flQuestion, how, "howFragment")
.setTransition(
FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(null).commit();
break;
}
}
}
});
} else {
btn.setVisibility(View.GONE);
}
return rootView;
}
So when i press the button the current layout (R.id.flQuestion) is replaced with the new fragment. This works, but the tricky part comes here:
When I slide to the next fragment and the slide to the fragment with the button it keeps working but if i slide 2 times to the next fragment (of the same type QuestionFragment) it does the functionallity of the new fragment but it doesn't show the new fragment.. So it seems that it can't replace the R.id.flQuestion because it is stored in memory maybe?
I need to be sure that the fragment is always replaced even if the next 2 fragments are of the same type and same layout (R.id.flQuestion)..
This is the class layout of the new frag
public class HowFragment extends UpperFragment {
..
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setRetainInstance(true);
View rootView = inflater.inflate(R.layout.how, container, false);
//if back key pressed return to layout of Question
rootView.setFocusableInTouchMode(true); //this line is important
rootView.requestFocus();
rootView.setOnKeyListener( new View.OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
CustomViewPager.enabled = true;
return false;
}
return true;
}
} );
//don't allow pushing button again
rootView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return true;
}
});
return rootView;
}
Also important to tell: i'm using framelayouts for both the fragments (so no hard coded fragment tag in the xml)
To make it clear:
This happens when the next fragment is from different class, no problem
This happens when next fragments are from the same layout and class:
I'll have to test the code, but from what I see, easiest way to make this work is to grab new Fragment even if it is the same fragment class.
Fragment how = XmlParserSax.howFragments.get(i);
If this function is returning new instance of a fragment, it should work.
Hope that helps
Edit :
I'm pretty sure the activity can access the button after the fragments are created.
Otherwise you need a handler to pass the click to handle it in the adapter. I'm seeing the your list of fragments are static (Not recommended). Since you haven't added any codes for how you setup the pageradapter, I have no idea what list you are using, but you need to change out the item in that list. From the Activity where you initialized the pager, you can call the public function to replace the current pager item pager. (you can use ViewPager.getCurrentItem())
I haven't tested, so you might have to tweak and play around to perfect it.
Hope this helps.
Here is a sample :
public static class MyAdapter extends FragmentStatePagerAdapter {
ArrayList<Fragment> fragmentArray = new ArrayList<Fragment();
public MyAdapter(FragmentManager fm) {
super(fm);
}
//didn't put in the function to populate the list with fragments
public void replaceItem(Fragment newFrag, int pos){
fragmentArray.remove(pos);
fragmentArray.add(pos,newFrag);
notifyDataSetChanged();
}
#Override
public int getCount() {
return fragmentArray.size();
}
#Override
public Fragment getItem(int position) {
return fragmentArray.get(position);
}
}

Categories