I have listview in one fragment that displays item from a sqlite database. When I click on one item it opens a menu to allow to open, add to another listview or delete. I want to be able to add it to another listview in another fragment on press. I tried adding it to another listview using bundles but I had no luck. I have a plan of creating another database table to store the added data and display it in a new listview. Would this work? or do any of you guys have another suggestion?
You can send data from one fragment to another. The best way to do this is by going through the parent activity. Something like this:
public class MyActivity extends FragmentActivity implements MyFragmentListener {
MyFragment1 frag1;
MyFragment2 frag2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(0);
FragmentManager fm = getSupportFragmentManager();
frag1 = (MyFragment1) fm.findFragmentByTag("frag1");
frag1.setListener(this);
frag2 = (MyFragment2) fm.findFragmentByTag("frag2");
}
// Call this function from frag1 when you want to send the data to frag2
public void addToFrag2(ListItem item) {
frag2.addToList(item);
}
}
// Define whatever methods the fragments want to use to pass data back and forth
public interface MyFragmentListener {
void addToFrag2(ListItem item);
}
Related
I'm currently trying to make a create account fragment and a choose profile pic fragment.
Fragment A/create account:
This houses Edittextfields for name, password, E-mail address.
There is also an Image view which represents the profile pic.
This Image view has a button on the side, which I want to use to switch over to Fragment B.
Fragment B/Choose Profile Pic:
Fragment is just an Image view and a couple of Image Buttons.
My Problem
Let's say the user has typed in all information on Fragment A and now wants to choose a profile pic, how do I save all the data temporary which is entered in Fragment A.
The second question is then, when the user clicks the Accept button on Fragment B, how do I sent the chosen Pic to Fragment A. So that I can switch over to Fragment A and restore the previously saved information and receive the drawable Image which the user has selected, to display it in the Image view.
Have a look at the new Android Architecture Components. Especially ViewModel.
https://developer.android.com/topic/libraries/architecture/viewmodel.html#sharing
There is a section on sharing data between fragments.
It's very common that two or more fragments in an activity need to
communicate with each other. Imagine a common case of master-detail
fragments, where you have a fragment in which the user selects an item
from a list and another fragment that displays the contents of the
selected item. This case is never trivial as both fragments need to
define some interface description, and the owner activity must bind
the two together. In addition, both fragments must handle the scenario
where the other fragment is not yet created or visible.
This common pain point can be addressed by using ViewModel objects.
These fragments can share a ViewModel using their activity scope to
handle this communication, as illustrated by the following sample
code:
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.
});
}
}
Making Activity as an intermediate can enable your fragment communication.
Refer Communicating with Other Fragments for "fragment-activity-fragment" communication. If you want to persist the data refer SharedPreference of android.
Why you want to create 2 Fragments ?
You can achieve same thing with different views. Let's say you can create one Linear/Relative(Layout Group) Layout with all the controls of 1st Fragment and create another layout(Layout Group) with 2nd Fragment controls. And then using animation show and hide layouts so you can have both the things in same fragment or activity and user won't even notice that thing.
This way you don't have to save data temporary and you will have to implement all the things in single file.
Situation:
I have an activity with a FrameLayout in which I change fragments.
I use:
getSupportFragmentManager().beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack("name")
.commit)
All works fine the problem is when I go back in the stack the previous fragment is reloaded and all the data is lost.
Possible solution:
restore fragment state - I want to avoid this because most of the data is retrieved from the server and it takes a lot of time
use .add(R.id.content, fragment) instead of .add(R.id.content, fragment) but in this case my fragments must have a solid background otherwise they overlay each other. The problem is that I can't set a solid background because of some design constraints.
Question:
How can i use '.add(R.id.content,fragment)' and somehow hide the fragment below it so it won't overlay and I can go back to the previous fragment in the state I left it.
First I would say that there's no need to add the fragment to the backstack if you don't want the user to go back to a previous fragment.
To answer the other question, the FragmentManager has a "hide" method that you can use to keep a fragment in the FragmentManager, but hide it from the user. Then use "show" to reveal it again.
final Fragment oldFragment = methodToGetFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.hide(oldFragment)
.addToBackStack("name")
.commit)
Like stated in the first sentence, the Fragment is going to be popped and the old fragment will be shown when the user presses "back". If you don't want that to happen, then simply remove addToBackStack().
for save data
you can use Activity when replacing fragments, activity is live .
public class MotherActivity extends ActionBarActivity {
private Data data = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adv);
Fragment oldFragment = methodToGetFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.hide(oldFragment)
.addToBackStack("name")
.commit)
}
public void setData(Data data){
....
}
public void getData(){
....}
}
public class FirstFragment extends Fragment {
private AdvActivity act;
......
public void onAttach(Activity activity) {
super.onAttach(activity);
// get data from internet
Data data=getData();
// and save data in mother activity
activity.setData(data);
}
second fragment:
public class SecondFragment extends Fragment {
private AdvActivity act;
private Data data;
......
public void onAttach(Activity activity) {
super.onAttach(activity);
// get data from mother activity
data=activity.getData();
}
I have an activity A with 3 fragments. Each fragments replaces each other, hence at a given time only 1 is visible.
HomeFragment has 2 textviews wrapped inside 2 cardviews. Each cardview represents a text value which comes from Fragment1 and Fragment2. When I click on say Card1,I get to the Fragment1.
Fragment1 has some cardviews, when I selects any of them I navigate back to HomeFragment and update the cardview text based on my selection in Fragment1.Here is the switch statement, depending upon what card user selects I put that in a bundle and pass it to HomeFragment.
switch (v.getId()) {
case R.id.card_view0:
Fragment1Bundle.putString("Test", "Testing");
bundle.putBundle("Fragment1Bundle", Fragment1Bundle);
fragmentTransaction.setCustomAnimations(R.anim.slideup, R.anim.slidedown, R.anim.slideup, R.anim.slidedown);
fragmentTransaction.replace(R.id.content_frame, fragment);
fragment.setArguments(bundle);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
break;
Fragment2 has same behavior as Fragment 1.
switch (v.getId()) {
case R.id.card_view0:
Fragment2Bundle.putString("Test2", "Tetsing");
bundle.putBundle("Fragment2Bundle", Fragment2Bundle);
fragmentTransaction.setCustomAnimations(R.anim.slideup, R.anim.slidedown, R.anim.slideup, R.anim.slidedown);
fragmentTransaction.replace(R.id.content_frame, fragment);
fragment.setArguments(bundle);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
break;
My challenge is that I am using bundles to pass data between fragments, My home fragment gets updated with the data it from fragment1 but when I go to fragment 2 and after making the selection come back to Home fragment, my fragment1 data is set to default. This is what I am doing in Home Fragments onCreateView()
try {
bundle1 = getArguments().getBundle("Fragment1Bundle");
bundle2 = getArguments().getBundle("Fragment2Bundle");
tv.setText(bundle1.getString("Test") == null ? null : bundle1.getString("Test"));
tv2.setText(bundle2.getString("Test2") == null ? nul : bundle2.getString("Test2"));
} catch (NullPointerException e) {
Log.d(TAG, e.printStackTrace());
}
I know that I am creating a new Homefragment in my fragment transaction in both fragment1 and fragment2, How can I keep just 1 instance of Home fragment around.
Another design recommended by Google is to use the main Activity and 2 fragments (in your case Fragment1 and Fragment2). I can see your problem of passing data bundle to HomeFragment. This suggested design uses MainActivity which is declared static (may be required for scoping issue). And it uses an interface to be established between Activity and a Fragment. I think the interface is easier than passing bundle back to the HomeFragment.
A Google webpage is # Communicating with Other Fragments. This is not just my opinion. A good SO link, I think, is How to pass data between fragments.
Code snippet from the webpage...
An example of Fragment to Activity communication:
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
...
An example of Activity to Fragment communication:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
}
}
Note:
OnHeadlineSelectedListener is the interface created by the Fragment.
The created method onArticleSelected has a parameter position, which comes from the ListView in ListFragment (in the sample).
You can still set data bundles and send data between Activity and Fragment. However I have not sent back data from Fragment to Activity. I normally use Fragment to handle much of UI updates.
how to pass values from activity to already open fragment and update array-list help me please. when I using interface the array-list size is zero what I do? do not us bundle method.
public class Main2Activity extends AppCompatActivity{
String desc = "data";
OnDataPassedListener onDataPassedListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
String passedArg = getIntent().getExtras().getString("id");
Log.d("data",passedArg);
Scription scription = new Scription();
onDataPassedListener = (OnDataPassedListener)scription;
onDataPassedListener.onDataPassed(passedArg,desc);
}
public interface OnDataPassedListener {
void onDataPassed(String text,String name);
}
}
public class Test extends Fragment implements
Main2Activity.OnDataPassedListener{
.
.
.
.
#Override
public void onDataPassed(String text,String name) {
monthlylists.get(Integer.valueOf(text)).setFood_type(name);
}
I have two static fragments in same activity, in "fragmentA" i have a customized list, when an item is clicked must to appear a detail in "fragmentB", detail appear only when i change screen orientation, no automatically. I use this code in main activity for refresh but application restart(detail appear).
finish();
startActivity(getIntent());
Someone knows a better way to make appear detail automatically in "fragmentB" when i clicked some item from "fragmentA", always using two static fragments in same activity.
Don't use static references to hold a Fragment, it's a really bad practice.
Don't store the Context in a static reference. Or you could will leak memory.
Instead, implement an Interface:
//FragmentActivityTest
public class FragmentActivityTest extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentB fragmentB = new FragmentB();
FragmentA fragmentA = new FragmentA();
fragmentA.setFragmentBHandler(fragmentB);
//Perform transactions etc
}
}
//FragmentA
public class FragmentA extends Fragment {
private FragmentBHandler _handler;
public void setFragmentBHandler(FragmentBHandler handler) {
_handler = handler;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
((ListView) getView().findViewById(R.id.list_view)).setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
_handler.updateDetail();
}
});
}
}
//FragmentB
public class FragmentB extends Fragment implements FragmentBHandler {
#Override
public void updateDetail() {
//do your work
}
}
You should use an event bus like greenrobot or otto. FragmentB subscribe to an event, and FragmentA post that event. When you click on an item, you'll send an event, and the subscriber will execute your action (show details).
Without showing code, I can only guess your current implementation.
The proper way to communicate between fragments is
Pass data to the parent activity from Fragment A on item click,
Activity passes this data to fragment B by finding the fragment in fragment manager and call a method in fragment B,
That method in fragment B should determine if it should populate the detail.
How can I communicate a listview of a ListFragment after an event of a Fragment inside another Fragment?
In the ListFragment (fragment A) I have a method to refresh the ListView. But also, I need to refresh it after a click of a Button inside a Fragment, wich is child of another Fragment (fragment b)
Its like Fragment A (listFragment) | Fragment B (detailview)
(fragment C - child fragment of B)
How can I do it?
You can access another Fragment by its tag:
// find your fragment
YourFragment f = (YourFragment) getSupportFragmentManager().findFragmentByTag("yourFragTag");
// update the list view
f.updateListView();
The tag of your Fragment is set when it is attached to a container layout:
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.frameBuy, YourFragment.newInstance(), "yourFragTag").commit();
So when you click your Button, find the Fragment you want to refresh by its tag, and then call your refresh method.
IF you are using a ViewPager, this is how to get the Fragments tag:
/**
* Gets the fragment tag of a fragment at a specific position in the viewpager.
*
* #param pos the pos
* #return the fragment tag
*/
public String getFragmentTag(int pos){
return "android:switcher:"+R.id.yourViewPagerId+":"+pos;
}
You can do it with a few simple steps:
Create a listener interface for component to listen to the button click event from FragmentC. For example:
public interface FragmentCButtonListener {
public void onButtonClicked();
}
Add a method in FragmentC to allow listener registration. FragmentC will keep track of the listener, and call the listener callback as soon as the button is clicked. For example:
public class FragmentC extends Fragment {
FragmentCButtonListener myListener;
public void registerListener (FragmentCButtonListener listener) {
myListener = listener;
}
}
FragmentA should implement FragmentCButtonListener interface, register itself as a listener to FragmentC, and refresh the list view when it receives the callback from FragmentC. For example:
public class FragmentC extends Fragment implements FragementCButtonListener {
FragmentC fragmentC;
public void onCreate() {
fragment = new FragmentC();
fragment.registerListener (this);
}
public void onButtonClicked() {
//refresh the list view
}
}
Please note, I assume the FragmentA has a reference to FragmentC in the sample. If not, just make sure the container class of all fragments registers itself as the listener of FragmentC. The container class can as FragmentA to update listview once it receives callback from FragmentC.
follow these steps
We have two fragments called AddFragmentand ListFragment, and upon adding an item on first fragment you want the updated list be shown on list fragment (what sort of sorcery is this!!!).
Step 1 create the listener interface on class level of AddFragment with a method that is going to be implemented by the other guy (ListFragment ) and create Interface type variable
public class AddFragment extends Fragment{
//listener varriable
//listener
public interface OnCategoryAddedListener{
public void refreshList();
}
private static OnCategoryAddedListener meAddListener;
}
Step 2 create register method on class level of the same AddFragment class and set listenter variable
public class AddFragment extends Fragment{
public void registerListener(OnCategoryAddedListener listener)
{
meAddListener = listener;
}
}
Step 3 upon any event cud be button click or yelling at ur application(that is considered rude event in android :-) ) check for listener object meAddListener variable and call the interface,
in a Shakespeare’s nutshell it means “for thou who implement ye interface and brought the method within ur class shelter, I shall give u my utmost privilege and blessing to …. ”
Step 4 On ListFragment implement the AddFragment’s interface,no turning back just go implement its method. Within that method u just call abracadabra to repopulate ur list or any sort of updatable android view object… and ur done
public class ListFragment extends Fragment implements AddFragment.OnCattegoryAddedListener{
//refer to AddFragment
AddFragment addFragment;
//once the fragment is within the memory scope u instantiate AddFragment
//and register listener with AddFragment context which inherently implement OnCategoryAddedListener
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
categoryAddFragment = new CategoryAddFragment();
categoryAddFragment.registerListener(this);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
fillList();
}
public void fillList() {
ArrayAdapter<String> catArrayAdapter = new ArrayAdapter<>(context,android.R.layout.simple_list_item_1,getItems());
setListAdapter(catArrayAdapter);
}
//le interface method u can count on to refresh ur list content
public void refreshList(){
fillList();
}
check this out for a little more
enjoy the java magic