I have a Recyclerview in MainActivity where data are from an API. I want to open a DetailsActivity after clicking an item.
Now in MVP pattern, how should I pass the data object from MainActivity to DetailsActivity? I used Interactor in Mainactivity to handle data part.
I think you should use callback in your adapter and pass data from your adapter to
your first activity then pass data from first activity to second activity with Parcelable.
You can follow this for use Parcelable.
[https://developer.android.com/reference/android/os/Parcelable
Under an assumption DetailsActivity is supposed to show "details" that have id, you may pass the id through a Bundle to DetailsActivity and fetch "details" by the id.
If the assumption is wrong, then you might make the "details" Parcelable and pass them through a Bundle to the DetailsActivity.
By using either of the approaches it is guaranteed that the data passed through a Bundle will "survive" a process death in case your app process is killed by the system in background. I.e., when navigating back to the app the Bundle will be "redelivered" to DetailsActivity.
I can directly pass the data to the DetailActivity through Intent, but how is the MVP approach here?
In MVP, a view (V) is usually platform specific, so it's fine for it (in Android) to operate with Bundle.
That means I can directly send data to DetailActivity?
Yes, it might be as follows. Presenter (P) of DetailsActivity gets an id passed via Intent and "asks" Interactor to get the details data from Repository (or some other abstraction you use).
Related
I am trying to create a recycler view with data from another activity. I need to transfer data from one activity to the recycler view activity without it opening the recycler view activity. Because only when I press another button do I want to go to the next activity.
I have tried using intent, however startActivity(intent) always opens the other activity. I also tried using Share preferences to save the data and retrieve it in the other activity. However, Base64.DEFAULT was not working for me.
public void sendData(Bitmap images, String image_class) {
Intent send = new Intent(getApplicationContext(), Scanned_List_Activity.class);
send.putExtra("image_class",image_class);
send.putExtra("image", images);
startActivity(send);
}
If I understand your question right, you should do it differently.
Activity represents a View or better to say a Controller in the MVC architecture. Data you gained in the RecyclerReceiver comes from a model, activity just passes it to a view. That's why the right way is to have this data in the model layer rather than pass it over an Intent as a Parcelable object.
Nowadays we have a ViewModel class which is a layer between a model and your view. If you use DI tool like dagger you can keep a single instance of your ViewModel between this two activities - when you prepare your dataset on the first activity, the second activity will get it next time when it would be opened.
In short you should put this dataset either in the separate table and request from 2nd activity or to put on the ViewModel which single instance is shared between this two activities.
I have an application that needs to collect some data before doing it's main job.
So, the first fragment collects data, the second fragment collects data and then the third fragment uses the data.
The problem is: data in the first fragment is uncorrelated to the data I collect in the second fragment.
How can I pass the data from the first fragment to the third? Should I incrementally pass all the data I collect in the next fragment arguments, or should I store them elsewhere? I'd really like to know what the best practice is.
explicative image
I won't use a database, since I don't need to permanently store the data.
Thank you!
As for any best practices, the best answer is "it depends".
If your app is really small and simple then it's okay to pass data from one screen to another in the arguments bundle.
A more complex approach is to store data somewhere outside of these Fragment lifecycles.
It's a general rule you can implement as you want. A couple of examples below:
Data can be stored on Application class level. Application class runs for all application lifecycle. Every fragment can get Application instance from its activity like activity?.getApplication().
Data can be stored on Activity level if all fragments run in a single activity. Activity can be obtained from Fragment using activity or requireActivity().
Data can be stored on a parent fragment level if all fragments run in this parent fragment. It can be obtained from child fragments using parentFragment.
All these approaches suppose you to cast some "parent" thing to specific interface or implementation. For example, if your fragments run in the MainActivity which is stores some val data: Data as its property, then you should use it something like this: (requireActivity() as MainActivity).data
Clarification on a couple of popular answers:
The Shared ViewModel is just a special case of activity-level approach as ViewModel instance is stored in Activity scope.
The SharedPrefrences like any "database" approach is a special case of application-level approach as SharedPreferences is stored on application-level (in the file storage) no matter where you create its instance. (And SharedPreferences persists data across application starts, so it's not your option)
In addition to mentioned "Shared ViewModel" technique, Androidx introduced new "Fragment result Api" starting with "Fragment" library v1.3.0-alph04 (currently in beta) which could be used for communication between pair of Fragments or Activity-Fragment.
A Fragment/Activity set a listener in FragmentManager by specifying a key and other Fragment/Activity send data (in form of a Bundle) to the listener with that key. If there's no listener for the key, FragmentManager keeps newest data until a listener gets registered.
Pay attention that listener and result must be set on same FragmentManager instance.
I my opinion, its good for signals (events), not for sharing data. A situation I found it useful, was sending "onWindowFocusChanged" from Activity to Fragment. In case of sharing data, Shared ViewModel is better.
Most MVP Architecture Tutorials online seem to have some clickable view (Button) to process user interaction: view asks the presenter what to do, presenter retrieves some data from the model, presenter then gives it back to the view for it to be shown to the user.
But what about transferring to another Activity? Do we do the processing during onCreate? What about getting the extras on the Intent? - Should it be placed on the Activity?
As of MVP you are processing data in your presenter and pass it back to your view. Where you use this data to display.
As you have your data in your view it means you already have data(Model) reference in you view(activity) so you can transfer it to another view(activity) with in view.
As in most of case your one activity reference to only one presenter so ho would you take data from another presenter without having reference of it.
If you want to start another activity you must have context reference to start. So it should be the best option to start activity and pass those data in extra from activity it self.
I have three components whose data I have to synchronise.
Activity - This activity get data from Content Provider and has a ViewPager. It passes this data (Fragment.getInstance(data...)) to the second component which is a Fragment
Fragment - This fragment has a RecyclerView and onClick() of a particular item, data is passed through intent to the third component which is an Activity.
Activity - Here the data which is received is modified.
What would be the best way to sync this modification across all the three components?
Do not hold references to the same POJOs (Plain old java object) between different activities and fragments. Use shared preferences or a SQL db instead.
Activities and fragments are supposed to be stateless. So I am going to tell you how to transfer data between activities and fragments rather than how to synchronize data.
Let's take them case by case:
'1 to 2': You probably already have all the fragments in the activity. So just call fragment.sendData(...) to send data to the fragment. Caveat: In case you are using a FragmentStateAdapter you will have to do this (reference):
if (adapter.getCount() > 0) {
fragment = (MyFragment) adapter.instantiateItem(
null, viewPager.getCurrentItem());
// A NullPointerException is thrown if the item isn't initialized as yet
// So be careful.
}
'2 to 1': Create a fragment callback interface (say FragmentCallback) that the activity1 must implement i.e. override Fragment.onAttach(Activity activty), check if activity instanceof FragmentCallback and throw an exception if it isn't. (This is automatically generated by android studio when you create a new fragment)
'1 to 3': Start the activity by passing an Intent with the data.
'2 to 3': Start the activity by passing an Intent with the data. In case you need some data from activity1, don't use this method. Use '2 to 1' followed by '1 to 3' instead.
'3 to 1': The correct way to do it is to start a new activity1 with Intent data or send it to the original activity1 using startActivtyForResult and handle the result in activity1. You can use android:launchMode="singleTop" (ref) if needed. If you have to send it the original activity (in a way that cannot be satisfied by startActivtyForResult), it's definitely a code smell. Use shared preferences or something and check it in Activity1.onResume and/or Activity1.onCreate.
'3 to 2': Use '3 to 1', followed by '1 to 2'.
I adopted to the event bus library which simplified the communications. Check it out at EventBus
I'm very new to Android programming (and Java for that matter) coming from an iOS background.
What I am trying to do, is pass a pointer to a Fragment from one Activity to another.
Basically, I have a starting activity called BeginActivity that handles a couple of Fragments for login and register screens. Once logged in, I load up the main activity of the app called TabsFragmentActivity using this code:
public void loggedIn() {
Intent intent = new Intent(this, TabsFragmentActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
this.startActivity(intent);
finish();
}
I'm using FLAG_ACTIVITY_CLEAR_TOP as I dont want the user to go back without actually logging out first.
Now the problem:
In BeginActivity I have a pointer to a fragment that holds the users data. I am using it like a singleton, that the first few view fragments can access from BeginActivity.
I need to pass this same object to the new TabsFragmentActivity before I call finish() on it.
How do I do this?
I know I can use putExtra() but I believe that is just for strings etc.. and not other Fragments.
Is there a way in the newly created TabsFragmentActivity that I can reference the BeginActivity to 'grab' the pointer?
Thanks
First of all, you should be sure about Fragments and Activity life cycle.
Fragments are designed to be reusable UI complex components. They look like activity, but you can reuse. So,you can have as many activities you need containing the same fragments, but not the same instances of these fragments.
If you just want to pass you user data for another activity you must use Bundle and putExtra(). Depending of the user data type can be necessary implements Serializable or Parcelable Interfaces, as #gheese said.
If you want to use the same UI appearence of your fragment on two or more activities, besides use Bundle and putExtra. Each activity that you want this behavior must contains a field whose is a Fragment and in the moment of starting this fragment you can use getActivity().getIntent().getExtra to get the user information and populate your fragment.
Basically you need to be able to pass your class via the intent, look at Serializable / Parcelable interfaces
This question has the answer you require
How to pass an object from one activity to another on Android