I have RecyclerView on LightsFragment, and I want to sort it from the MainActivity which contain this fragment.
Here is what I have now:
Thats the function that sorting my adapter:
Collections.sort(lights);
lightsAdapter.updateData(lights);
LightsFragment - handling the adapter that should be sorted.
public class LightsFragment extends Fragment implements LightsPresenter, View.OnClickListener {
private RecyclerView RVLights;
private ArrayList<Light> lights = new ArrayList<>();
private Light light;
private LightsAdapter lightsAdapter;
private LightsView presenter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_lights, container, false);
presenter = new LightsView(lights, light, this);
RVLights = view.findViewById(R.id.RVLights);
presenter.loadData();
return view;
}
#Override
public void setAdapter() {
lightsAdapter = new LightsAdapter(getActivity(), lights);
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), 3);
RVLights.setLayoutManager(layoutManager);
RVLights.setAdapter(lightsAdapter);
}
}
MainActivity - handling 3 buttons, one of the buttons should sort adapter.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Greetings mGreetings = new Greetings();
private TextView mTVgreetings;
private Button BTNmLights, BTNmGarage, BTNmSortBy;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
mTVgreetings = findViewById(R.id.TVgreetings);
initFunctions();
}
public void showLightsFragment() {
getSupportFragmentManager().beginTransaction().add(R.id.main_fragment_container, new LightsFragment())
.commit();
}
public void initFunctions() {
showLightsFragment();
showGreetings();
}
public void showGreetings() {
mTVgreetings.setText(mGreetings.getGreetings());
}
public void initView() {
BTNmLights = findViewById(R.id.BTNlights);
BTNmGarage = findViewById(R.id.BTNgarage);
BTNmSortBy = findViewById(R.id.BTNsort);
BTNmLights.setOnClickListener(this);
BTNmGarage.setOnClickListener(this);
BTNmSortBy.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.BTNlights:
//TODO open lights fragment...
break;
case R.id.BTNgarage:
//TODO open garage fragment...
break;
case R.id.BTNsort:
//TODO make drop down with sort light and garage.
break;
}
}
}
I want that when i pressing on sort button on main activity,
the adapter from LightsFragment will be sorted.
I already have a function that sorting adapter.
Just don't know how to access the adapter from the Main activity.
Store the Fragment instance in Activity and access it any time.
private LightsFragment lightsFragment= new LightsFragment();
public void showLightsFragment() {
getSupportFragmentManager()
.beginTransaction().add(R.id.main_fragment_container, this.lightFragment)
.commit();
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.BTNlights:
//TODO open lights fragment...
break;
case R.id.BTNgarage:
//TODO open garage fragment...
break;
case R.id.BTNsort:
this.lightFragment.sortLights()
//TODO make drop down with sort light and garage.
break;
}
}
and in your LightFragment you should have a method to find the RecylerView and get it's adapter to update the list and notifyDataSetChanged
First, create a getter method for your LightsAdapter in Fragment.
After, get the fragment in the mainActivity with the help of
Fragment yourFragment=getSupportFragmentManager().findFragmentById(R.id.main_fragment_container);
Later, check if the fragment is your fragment or not:
if(yourFragment instanceOf LightsFragment)
{
yourFragment.getAdapter();
}
You can do that using interface.
create an interface like
public interface UpdateFrag {
void sortAdapter(int sortType);
}
In your Activity do the following
UpdateFrag updatFrag ;// add this line
public void showLightsFragment() {
Fragment lightsFragment = new LightsFragment();
updatFrag = lightsFragment; // here you initialize updatFrag
fragment.getSupportFragmentManager().beginTransaction().add(R.id.main_fragment_container, lightsFragment)
.commit();
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.BTNlights:
break;
case R.id.BTNgarage:
//TODO open garage fragment...
break;
case R.id.BTNsort:
// here you should call sortAdapter method.
updatFrag.sortAdapter(1) // suppose 1 for light and 2 for garage
break;
}
}
Now in your LightsFragment implement the interface.
public class LightsFragment extends Fragment implements LightsPresenter, View.OnClickListener, UpdateFrag {
// ....
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// ....
}
#Override
public void setAdapter() {
// ....
}
#Override
public void sortAdapter(int sortType) {
if (sortType == 1){
// here you can sort your adapter according to light
}else{
// here you can sort your adapter according to garage
}
}
}
Related
I have activity that contain fragment.
This fragment have a lottie animation with lottie_loop="false",
that means, once the animation finish first loop , the animation will be and.
I want to listen for this event(animation end) in activity that contain this fragment, but some this wrong with my code, and I have white screen.
I created interface for listen to even , and this is my code:
Fragment with lottie animation:
public class EntryFragmentAnimation extends Fragment {
private View view;
private LottieAnimationView mLavTwoHearts;
private boolean isAnimationEnd = false;
private OnAnimationEndListener iOnAnimationEndListener;
public interface OnAnimationEndListener {
void onAnimationEnd(boolean isAnimationEnd);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_entry_animation, container, false);
initView(view);
initAnimation();
return view;
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
iOnAnimationEndListener = (OnAnimationEndListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement OnAnimationEndListener");
}
}
private void initView(View view) {
mLavTwoHearts = view.findViewById(R.id.lavTwoHearts);
}
private void initAnimation() {
mLavTwoHearts.playAnimation();
mLavTwoHearts.addAnimatorListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isAnimationEnd = true;
iOnAnimationEndListener.onAnimationEnd(isAnimationEnd);
}
});
}
}
And an activity
public class LoginActivity extends AppCompatActivity implements EntryFragmentAnimation.OnAnimationEndListener {
private boolean isAnimationEnd = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
setEntryScreen();
listenToAnimationEnd();
}
private void setEntryScreen(){
getSupportFragmentManager()
.beginTransaction()
.add(R.id.container_login_fl, new EntryFragmentAnimation())
.commit();
}
private void listenToAnimationEnd(){
while (!isAnimationEnd){
Log.d(TAG, "listenToAnimationEnd: Animation playing");
}
Log.d(TAG, "listenToAnimationEnd: animation end");
}
#Override
public void onAnimationEnd(boolean isAnimationEnd) {
this.isAnimationEnd = isAnimationEnd;
}
}
While running the app , only white screen appear and in logcat running endless log with Animation playing
Instead of a listener I would suggest you to better use a ViewModel. You only need to create ViewModel class and create its instance in fragment but using the activity scope so that it will be available for all the fragment contained within the activity including activity itself.
In your fragment create a Shared ViewModel instance like below:
activity?.let {
sharedViewModel = ViewModelProviders.of(it).get(SharedViewModel::class.java)
}
Once the animation ends update the the ViewModel
sharedViewModel?.onAnimationFinished()
Note: Inside you ViewModel class, have any live data member which is being obeserved by your Activity and then just update the variable within the function.
In the activity we just need to create instance of our ViewModel and observe the required data like this
val sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)
sharedViewModel.animationEndEvent.observe(this, Observer {
it?.let {
// do some thing
}
})
So I have my MainActivity.java, I also have a FragmentA.java and a FragmentB.java.
In my MainActivity I have a BottomNavigation which allows me to switch between the two fragments.
MainActivity.java
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
Fragment selectedFragment = null;
switch (menuItem.getItemId()) {
case R.id.nav_a:
selectedFragment = new FragmentA();
break;
case R.id.nav_b:
selectedFragment = new FragmentB();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
Inside FragmentA I have a RecyclerView with an adapter of course and on each CardView there is a button, when i click that button i want to pass the corresponding object to the RecyclerView in FragmentB.
FragmentA.java
adapter.setOnItemClickListener(new RewardItemAdapter.OnItemClickListener() {
#Override
public void onItemClick(int position) {
//When I click the item, pass theItem to FragmentB
CustomObject theItem = items.get(position);
}
});
FragmentB.java
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_b, container, false);
itemsList = new ArrayList<>();
itemsList.add(new CustomObject(R.drawable.picture, "Text", "More text.", 200));
//I'm guessing I want to add the CustomObject that I clicked to the list here so that I can display it in the RecyclerView
recyclerView = v.findViewById(R.id.fragmentBRecyclerView);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getContext());
adapter = new FragmentBItemAdapter(itemsList);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
return v;
}
The only issue is I have no idea how to, I tried using Interfaces but I couldn't implement it properly, I'm not sure if it's because I am instantiating a new instance of the fragments.
You could achieve this by two ways:
1) Through Interface Contract between the Fragment and Activity
class FragmentA: Fragment() {
interface SomeInterfaceName {
fun setSelectedItem(item: SomeItem)
}
}
class FragmentA: Fragment() {
interface AnotherInterfaceName {
fun getSelectedItem(): SomeItem
}
}
class ContainerActivity: Activity(), AnotherInterfaceName, SomeInterfaceName {
var someItem: SomeItem? = null
fun setSelectedItem(item: SomeItem) {
someItem = item
// inflate your FragmentB
}
fun getSelectedItem(): SomeItem {
return someItem;
}
}
But the best solution in my opinion is to use a shared ViewModel for this case.
You can read about this he here under "Share data between fragments" section.
Doing the job by interface is correct, But you have to bind it to the Fragment in the onAttached lifeCycle method.
Define an Interface. OnFragmentInteractionListener.java
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(String args);
}
Then Implement your activity with the interface.
public class MainActivity extends ActionBarActivity implements OnFragmentInteractionListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
onFragmentInteraction(String args){
**// Made the Change Here**
// Send Local Broadcast Receiver
Intent intent = new Intent("UPDATE_LIST");
intent.putExtra("TYPE", 0);
// Change the args to get position or the relevant param
intent.putExtra("POSITION", selectedPosition);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
In the FragmentA.java,
public class FragmentA extends Fragment {
OnFragmentInteractionListener mCallback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnFragmentInteractionListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
...
adapter.setOnItemClickListener(new RewardItemAdapter.OnItemClickListener()
{
#Override
public void onItemClick(int position) {
//When I click the item, pass theItem to FragmentB
CustomObject theItem = items.get(position);
// Send the selected Item Name to Main Activity through args
mCallback.onFragmentInteraction(theItem.getName);
}
});
}
On your FragmentB.java class add Local Broadcast Receiver
public class FragmentBt extends Fragment{
public static Fragment newInstance(){
...
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.layout, container, false);
return v;
}
...
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
// Register Local Broadcast Receiver
LocalBroadcastManager.getInstance(getContext()).registerReceiver(mMessageReceiver, new IntentFilter("UPDATE_LIST"));
}
#Override
public void onDestroy() {
super.onDestroy();
// Destroy the Local Broadcast Receiver
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mMessageReceiver);
}
// Create Broadcast Receiver instance
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.hasExtra("POSITION")){
mAdapter.notifyItemChanged(intent.getIntExtra("POSITION", 0));
// Update Adapter as the requirement
}
}
};
}
Hope this will help.
Cheers!!
Is it possible to pass a data from fragment to fragment by swipe?
There are many articles teaching us how to pass the data from fragment to fragment, but most of the article or questions had implemented OnClickListener in their first fragment, which used to pass value to another fragment.
But my case is pass the data from two fragments without any button click and finally save them in different tables by clicking button in the last fragment. What can I do to achieve this??
The flow is Information >> WorkForce >>WorkDetailsTable and save them to different table by one button click.
I have tried to work it out but I get NULL value in SQLite. I think I have miss out a lot but have no idea. PLEASE help me...I've been stuck at here for more than two days...Thanks
Tab.java
public class Tab extends ActionBarActivity implements ActionBar.TabListener {
ViewPager Tab;
TabPagerAdapter TabAdapter;
ActionBar actionBar;
public static String name = null;
public static String subContractors = null;
// will be used for data communication
public static Force force_bean;;
public static Info info_bean;
public static Force getForce(){
return force_bean;
}
public static void setForce(Force force){
force_bean=force;
}
public static Info getInfo(){
return info_bean;
}
public static void setInfo(Info info){
info_bean=info;
}
final Activity mActivity = (Activity) this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab1);
info_bean = new Info();
force_bean = new Force();
TabAdapter = new TabPagerAdapter(getSupportFragmentManager());
Tab = (ViewPager) findViewById(R.id.pager);
Tab.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
actionBar.setSelectedNavigationItem(position);
}
});
Tab.setAdapter(TabAdapter);
actionBar = ((AppCompatActivity) mActivity).getSupportActionBar();
//Enable Tabs on Action Bar
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
//Add New Tabs
actionBar.addTab(actionBar.newTab().setText("Information").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Work Force").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Work Details").setTabListener(this));
}
#Override
public void onTabSelected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
#Override
public void onTabUnselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
}
}
TabPagerAdapter.java
public class TabPagerAdapter extends FragmentStatePagerAdapter {
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return Information.newInstance("name");
case 1:
return WorkForce.newInstance("SubCon");
case 2:
return WorkDetailsTable.newInstance();
}
return null ;
}
#Override
public int getCount() {
return 3; //No of Tabs you can give your number of tabs
}
Informmation.java
public class Information extends Fragment implements View.OnClickListener {
private Spinner spinner, spinner2, spinner3;
private static String a;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View info = inflater.inflate(R.layout.information, container, false);
dialog = new DateDialog();
spinner = (Spinner)info.findViewById(R.id.spinner);
addItemsOnSpinner();
a= spinner.getSelectedItem().toString();
return info;
}
public static Information newInstance(String a)
{
Information fragment=new Information();
Bundle bundle=new Bundle();
bundle.putString("a",a);
fragment.setArguments(bundle);
return fragment;
}
public void addItemsOnSpinner() {
List<String> list = new ArrayList<String>();
list.add("1 ");
list.add("2");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_spinner_dropdown_item, list);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
WorkForce.java
public class WorkForce extends Fragment {
private static EditText txt1;
private static String subCon;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View work = inflater.inflate(R.layout.workforce, container, false);
txt1 = (EditText) work.findViewById(R.id.editText);
subCon = txt1.getText().toString();
return work;
}
public static WorkForce newInstance(String subCon) {
WorkForce f = new WorkForce();
Bundle bundle = new Bundle();
bundle.putString("subCon", subCon);
f.setArguments(bundle);
return f;
}
}
WorkDetails.java
private com.example.project.project.API.InfoAPI ts;
private com.example.project.project.API.WorkDetailsAPI WD;
private com.example.project.project.API.WorkForceAPI WF;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View workDetails = inflater.inflate(R.layout.tableworkdetails, container, false);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
spinnerTra = (Spinner) workDetails.findViewById(R.id.spinner6);
addItemsOnSpinner();
Button btn1 = (Button)workDetails.findViewById(R.id.button2);
WD = new com.example.project.project.API.WorkDetailsAPI(getActivity());
ts = new com.example.project.project.API.InfoAPI(getActivity());
WF = new com.example.project.project.API.WorkForceAPI(getActivity());
a1 = spinnerTra.getSelectedItem().toString();
Bundle bundle = new Bundle();
final String name = bundle.getString("a");
final String subContractors = bundle.getString("subCon");
btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
add(name, subContractors);
}
});
return workDetails;
}
public void add(String name,String subContractors)
{
Toast.makeText(getActivity(),+name+subContractors, Toast.LENGTH_SHORT).show();
ts.insertTimeSheet(name);
WF.insertWorkForce(subContractors);
}
Note: My case is pass the data from two fragments without any button click and finally save them in different tables by clicking button in the last fragment.
If I understand your problem correctly, you are essentially implementing something a little bit like a "Wizard" where each step passes information to the next step as you swipe between the tabs or select them.
So in reality your problem is how to get the information out of a fragment when it is deselected and into a fragment when selected.
At the simplest level I would suggest your activity holds the "master" copy of all of the information and passes it into/takes it from each fragment in your tab pager adapter.
You would need some kind of "Domain" object to hold all the information you need to collect. Each tab would only update the bits of information it cares about..
public class WorkData {
string information;
string subCon;
... etc..
}
You add an instance of this to hold the master copy to your "tab" activity:
public class Tab extends ActionBarActivity implements ActionBar.TabListener {
...
WorkData workData = new WorkData();
...
I would then suggest a simple interface that each of your "tab" fragments implement; something like:
public interface DataUpdate {
void setData(WorkData data);
WorkData getData();
}
Each of your tab fragments would implement this interface, updating the WorkData as required..
public class WorkForce extends Fragment implements DataUpdate {
...
private WorkData workData; // this fragment's "copy" of the data
...
#Override
public WorkData getData() {
this.workData.subCon = this.subCon; // Assuming subcon has been updated.. else use txt1.getText();
return this.workData;
}
#Override
public void setData(WorkData workData) {
this.workData = workData;
// Update this page's views with the workData...
// This assumes the fragment has already been created and txt1 is set to a view
txt1.setText(workData.subCon);
this.subCon = workData.subCon; // Actually could just use subCon in workData, but be aware that workData actually points to the Activity's copy (kinda makes getdata redundant.. but I like symmetry and couldn't be bothered making lots of copies of the object).
}
Then you just need to add the code to pass the data backwards and forwards.. in your "Tab" activity which looks like...
#Override
public void onTabSelected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Pass the master workdata to the selected fragment
dataUpdate.setData(this.workData);
}
#Override
public void onTabUnselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Update the master workdata from the unselected fragment
this.workData = dataUpdate.getData();
}
#Override
public void onTabReselected(ActionBar.Tab tab, android.support.v4.app.FragmentTransaction ft) {
// This might be pointless, but we'll do it anyway..
int position = tab.getPosition();
DataUpdate dataUpdate = (DataUpdate) TabAdapter.getItem(position);
// Pass the master workdata to the selected fragment
dataUpdate.setData(this.workData);
}
An important thing to notice here is that your TabPagerAdapter will create a new fragment every time you call getItem().. that will mean that we will never get any updates because each time we try to get the fragment it returns a new, empty fragment. We need to change this so that the fragments are still created when first asked for, but only created once so that we don't keep throwing away our work.
public class TabPagerAdapter extends FragmentStatePagerAdapter {
private static final int NUMBER_OF_TABS = 3;
private Fragment[] tabList = new Fragment[NUMBER_OF_TABS];
public TabPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
if (tabList[i] != null) {
// Return a tab we created earlier..
return tabList[i];
} else {
switch (i) {
case 0:
tabList[0] = Information.newInstance("name");
return tabList[0];
case 1:
tabList[1] = WorkForce.newInstance("SubCon");
return tabList[1];
case 2:
tabList[2] = WorkDetailsTable.newInstance();
return tabList[2];
}
}
return null ;
}
#Override
public int getCount() {
return NUMBER_OF_TABS;
}
Hope this helps. Good luck :-)
Although C James provides good tips to solve your problems, I would like to introduce another way without using implementing of interfaces. Please check below link out. If you use an event bus library such a http://square.github.io/otto/, you can easily pass data you want to share among fragments and even activities. Additionally, you can reduce a lot of code line since it only requires Sender(PUBLISHING), Receiver(Subscriber) while implementation of interfaces requires additional lines of code.
Here is a tutorial of Otto libarary.
http://www.vogella.com/tutorials/JavaLibrary-EventBusOtto/article.html
Hope it helps :)
I would more go the Observer Pattern way.
Each Fragments changes an POJO with is rendered in your Fragments in some way. You simply have to Observe the pojo in your Fragments. Changing Fragments will notify interested observers without knowing them.
I believe that's a much cleaner way to implement this.
Fragment A -> PojoInstance.setXY("foo");
Fragment A -> informs the Observers which e.b Informs Fragment B:
Fragment B will see the change tru the Observer.
Because ViewPagers or other Components will cache Fragments thats a way to get information in already created Fragments, even when their are not seen.
You could also try to use an EventBus where you pass the POJO around.
To transfer data from one fragment to another fragment when swipe is performed ,firstly you should get the view of the each fragment.here is the sample code that can help you out a bit.
write this code in Activity:
mviewpager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
mviewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
adapter = ((SOFragmentPagerAdapter) mviewpager.getAdapter());
//getting the view of fragments at positions
if(position==0)
{
View v = null;
Fragment1=(Fragment1)adapter.getFragment(position);
v=fragment1.getMyView();//this is how you get the view
ListView lv=(ListView)v.findViewById(R.id.lv_services);
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(SOListItemSelectedActivity.this,android.R.layout.simple_list_item_1,soRequestFragment.al_list_of_services);
lv.setAdapter(arrayAdapter);
}
if(position==1)
{
}
}
#Override
public void onPageSelected(int position) {
if(position==0)
{
View v = null;
soRequestFragment=(SORequestFragment)adapter.getFragment(position);
v=soRequestFragment.getMyView();
}
if(position==1)
{
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
mviewpager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
and create a FragmentPagerAdapter as:
public class SOFragmentPagerAdapter extends FragmentPagerAdapter {
HashMap<Integer,Fragment> mPageReferenceMap;
int mNumOfTabs;
public SOFragmentPagerAdapter(FragmentManager fm,int mNumOfTabs) {
super(fm);
this.mNumOfTabs=mNumOfTabs;
mPageReferenceMap=new HashMap<Integer,Fragment>();
}
#Override
public Fragment getItem(int position) {
switch (position)
{
case 0:
Fragment1 fragment1=new tFragment1();
mPageReferenceMap.put(position,fragment1);
return fragment1;
case 1:
Fragment2 fragment2=new Fragment2();
mPageReferenceMap.put(position,fragment2);
return fragment2;
default:
return null;
}
}
public Fragment getFragment(int key) {
return mPageReferenceMap.get(key);
}
#Override
public int getCount() {
return 2;
}}
In Fragments add the getmyview() which will return the view of that fragment as:
public void getmyview()
{
return myview;//myview is fragment view which you will return in oncreateview method
}
Note: Viewpager execute onpagescroll first and get the position 0,1 and when you scroll ,views at position 1,2 will execute and page selected 0 will execute.
For tabselections: Tabunselected,Tabselected Tab reselected is the sequence of execution.
so write accordingly in the respective positions of fragments.
Hope this helps you.
I am trying to communicate between an activity and the fragment that sits on top of it, I want new data (image/text - retrieved from the db) to be passed into the frag every time an onclick occurs (onclick is in the activity). I made a simple interface to test (let me know if this is not suitable for images or if it is too slow or inefficient), and I am trying to have it included in my fragment so when an onclick occurs the fragment changes the image and the text.
Here is the simple interface code:
public interface FragmentCommunicator {
public void passDataToFragment(String someValue);
}
Here is the activity code:
public class RandomActivity extends FragmentActivity implements ActivityCommunicator {
//viewpager adapter
private PageAdapter mAdapter;
private ViewPager viewPager;
//interface through which communication is made to fragment
public FragmentCommunicator fragmentCommunicator;
//Buttons for yes, no, skip
Button btnYesRandom, btnNoRandom, btnSkipRandom;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_random);
//set buttons
btnYesRandom = (Button) findViewById(R.id.btnYesRandom);
// Initializing pager
viewPager = (ViewPager) findViewById(R.id.random_pager);
//calling bundle to attach data to fragment
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
RandomFragment randFrag = new RandomFragment();
randFrag.setArguments(bundle);
//Setting up fragment
FragmentManager fm = getFragmentManager();
mAdapter = new PageAdapter(getSupportFragmentManager(), new UserUpVotesFragment(), randFrag, new UserDownVotesFragment());
viewPager.setAdapter(mAdapter);
// Here you would declare which page to visit on creation
viewPager.setCurrentItem(1);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
public void onPageSelected(int position) {
// Check if this is the page you want.
if(position !=1) {
//swiping to the right
if(position == 0) {
Log.e("Swiping", "SWIPING TO THE Right BUT RESET ERR");
getIntent().removeExtra("edttext");
}
//swiping to the left
if(position == 2) {
Log.e("Swiping", "SWIPING TO THE left BUT RESET ERR");
}
// RandomFragment randomFrag = (RandomFragment) getFragmentManager().findFragmentById(R.id.fra);
viewPager.setCurrentItem(1);
}
}
});
btnYesRandom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
if(fragmentCommunicator != null)
fragmentCommunicator.passDataToFragment("Hi from FragmentActivity");
}
});
}
Code for Fragment:
public class RandomFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//call data from activity bundle
String strtext = getArguments().getString("edttext");
View rootView = inflater.inflate(R.layout.fragment_random, container, false);
RelativeLayout random_frag_layout = (RelativeLayout) rootView.findViewById(R.id.random_frag_layout);
activityButton = (ImageView) rootView.findViewById(R.id.imagehere);
//setRetainInstance(true);
texthere = (TextView) rootView.findViewById(R.id.texthere);
texthere.setText(strtext);
return rootView;
}
//FragmentCommunicator interface implementation
public void passDataToFragment(String someValue){
activityAssignedValue = someValue;
Log.e("ACTIVITY", activityAssignedValue);
}
}
If you have only one fragment, then you can access it directly and send any data just via method: make your fragment a field and call your passDataToFragment() on it from activity.
To access an activity from fragment, call ((RandomActivity)getActivity()).activityMethod()
What is ActivityCommunicator?
If you wish to go down this route have your RandomActivity class implement the FragmentCommunicator interface, which should either be declared as an inner-public interface in the RandomFragment class say, or publicly (or package local) in its own file.
I have a FragmentActivity with two Fragments. The two Fragments depend on a shared object. The object is loaded by an AsyncTask. So the problem here is that when the activity creates and shows up the fragments, the object is not loaded yet. Is there any method that pauses the Fragment creation or something like this?
The scenario is like this:
FragmentActivity
public class MainActivity extends FragmentActivity {
private Object sharedObject;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new FooAsyncTask(...).execute();
}
...
public void onAsyncTaskCompleted(result) {
sharedObject = result;
}
// Pager adapter -------------------------------------------------------
private class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return FooFragment.newInstance(sharedObject);
case 1:
return BarFragment.newInstance(sharedObject);
default:
throw new IllegalStateException();
}
}
#Override
public String getPageTitle(int position) {
switch(position) {
case 0:
return "Foo";
case 1:
return "Bar";
default:
throw new IllegalStateException();
}
}
#Override
public int getCount() {
return 2;
}
}
}
FooFragment
public class FooFragment extends Fragment {
public FooFragment newInstance(Object sharedObject) {
FooFragment f = new FooFragment();
f.setObject(sharedObject);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
// Here I use the object to show data
}
}
BarFragment
public class BarFragment extends Fragment {
public BarFragment newInstance(Object sharedObject) {
BarFragment f = new BarFragment();
f.setObject(sharedObject);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
// Here I use the object to show data
}
}
Final thoughts
So, as you can see, I need the same data for the two fragments, and this data needs to be loaded in an AsyncTask. The ideal behavior for me would be:
Load MainActivity
Show ProgressDialog and load the data in the background
Dismiss ProgressDialog
Show Fragments and use the data
You do this wrong. You should NOT pause anything. Instead, when parent activity load what is needed it should tell the fragments about that. In fact I'd make it differently - by using listeners - so my fragment would need to register on creation and the object that loads my data would then broadcast message back once loading task it done.