As a background, I am using MVP mosby for my android application.
Currently I have this UI design requirement, where from almost everywhere across the app. (4 different activity/fragment/recycler adapter). If the user taps on an item, I should present a dialog (same everywhere) and the dialog itself needs to make API calls, and need to handle any error that comes back.
I wrote this the present dialog logic inside a helper class.
#EBean
public class DialogService {
Dialog d;
public void presentUniversalDialog(Context context, Data data) {
d = new Dialog(context);
.. set view
.. change some text view based on data
.. make some api calls
}
private void makeAPiCall() {
.. some API calls here. On Return, update the dialog d if not null
}
}
So then in my other activities, I just need to inject this service and I can easily show the dialog by calling
#EActivity
public class MyRandomActivity extends Activity {
#Bean
DialogService dialogService;
#Click(R.id.my_random_button)
void onButtonClick() {
dialogService.presentUniversalDialog(this, data);
}
}
Now, the good news is that all the random activities should not be bothered by this dialog as long as it is launched. So I don't need to pass random event listeners around.
But how do I structure my dialogService code to deal with async events?
For example, the "data" field might contain only an id so I need to make API calls to populate the whole data. And once user clicks on OK. I need to send a request to confirm.
For now, I worked around by basically keeping track of the API calls via some member fields inside the DialogService. But as code gets large, this will quickly fill up and starts to be super confusing.
What is a recommended way of writing this "universal dialog"? Should I perhaps only use service per dialog? Or are there some other ways?
Treat dialog as View (in MVP) and give it its own presenter as gateway to your business logic (to make http request). So just treat Dialog not different than you would treat a Activity or Fragment in MVP.
Also worthwhile checking DialogFragment
Related
I am using MVVM pattern with repository for network call.
When i click button in my view it triggers save/ fetch data method in my viewmodel which then make call to repository wherein i am doing my network operation using Retrofit.
Now i would like to dismiss my progress bar with proper message (like saved, error etc. from my repository (onResponse or onFailure) that i started inside view.
public void onClick(View v) {
ProgressDialog dialog = new ProgressDialog(getActivity());
dialog.setMessage("saving...");
dialog.show();
cuttingUnitViewModel.saveProjectUnit();
}
Is it ok to do what i am doing or is there better alternative?
All i want to say that I want to return NETWORK STATE and DATA both from repository , how to do that?
Main issue which I think in your case is that you initiate a call and get its response but your activity doesn't get to know any of these changes. Without this you might have to create some custom util classes or some other workaround which in my opinion would be a really bad practice.
My suggestion is that you create a MutableLiveData object for your response in your activity's ViewModel, then pass this object to your repository so that when your retrofit completes your call you can post the result on your livedata object.
And in your activity you should be observing this livedata for changes. So, when you get the result and post the new value, then in activity livedata observer's onChanged() you can get the result and even make your progress bar disappear.
Sorry, if this was too hard to understand. Here is a nice little tutorial you can refer to. I suppose that would make things easier with an example. Good luck!
No, it is not proper to do View activities like dismissing ProgressBar in the Repository as this class is only meant to deal with Data from different sources and this creates tight coupling. A proper design would be to set callback functions back to the class where the View is present from the Repository class through the intermediate layers like ViewModel until it reaches the View layer and then dismiss the ProgressBar there.
I have been tasked with remaking an entire app basically at work. Essentially the app is just a feed that contains multiple types of cards (think facebook with update cards, photo cards, OG content cards) etc. I moved all of the network handling into a single class. You call the method that contains the request you want, passing in relative parameters and a Listener. The network call is made and then the Listener is passed the response.
Currently I have a Fragment class that populates a recyclerview with my custom adapter. The Fragment class interacts with my network class by making pagination requests on an endpoint. Should I have an adapter listener that communicates with my fragment when for example, the like icon on a particular viewHolder card is clicked? Should I then have the fragment make and manage that network call? The issue I have to account for here is if a network response fails, I need to unset UI elements (like the color of a like icon) to notify the user that their request could not be completed at this time. Unsetting these elements are properties of the view holder at that position in the recycler view. It seems wrong to pass all of this view holder information back to the fragment just to have the fragment be the only class that interacts with my network class. Is there anything inherently wrong with having my adapter handle network requests as well.
For example, Set an onClickListener on my view holder element, when clicked update the UI and make the call, then respond back to the adapter. If successful leave everything be, if failure, then unset the UI. This pattern makes sense to me and decouples individual view logic from the fragment. Is this fine to do? A lot of google searching has lead me to believe otherwise. This is my first business application and I want to make sure I follow the best patterns possible.
My fragment for the record looks something like this
onCreate() {
networkListener = new NetworkResponseListener() {
//Process success response based on response code
onSuccess(JSONObject response, responseCode)
onError(Error e, responseCode) // Handle Errors
}
}
//After scroll listener indicates I need to fetch again
NetworkHelper.makeFeedFetch(networkListener, LastId, GET_FEED_REQUEST_CODE);
So essentially I would do the same type of Network interaction in my adapter class for actions like, viewHolder like icon clicked and so on. Is that acceptable?
If you really want to make sure you follow the best patterns, you shouldn't make NetworkCalls from your fragment. Fragments or Activities should be just viewed objects that show the data that is served to them by other classes like Presenters(if you follow MVP) or ViewModels(MVVM). These classes also do not make direct network calls.
Generally, we use the Repository pattern which gets data from the remote(web services, remote DBs etc.) or local sources(a local DB).
Your network class is a candidate for a repository source. Then for each action
that is necessary for our business logic, we generate a use case, and if this use case needs the repository we inject our repository to our use case. Then we inject this use case to our Presenter or ViewModel. This much of indirection may seem like overkill but it gives easily extensible and testable code. Recycler view is also a view so you shouldn't make network calls
inside of recycler view too.
Although not an exact solution, your
Set an onClickListener on my view holder element, when clicked update the UI and make the call, then respond back to the adapter
is better IMO.
I'm contributing to my first large project and am struggling with a design decision. I have two fragments that populate a ListView and set a custom ArrayAdapter. Let's say the list items are emails, and the two Fragments are MessageListFragment and SearchMessagesFragment. The ArrayAdapter uses a ViewHolder pattern to inflate each message and attach an onClickListener to the "star" icon.
Now, regardless of which fragment I am in, I want the onClickListener to do the same basic thing: change the status of the email on the server to "starred," and determine if the email needs its position moved in the list (i.e. left alone if there are no filters, moved the to top/bottom if the emails are sorted by starred messages, or removed from the current list if the filter is only non-starred messages).
How can I create this behavior in a reusable manner so that I do not have to repeat this code in both fragments?
If I understood you need to perform an action triggered by one of the Fragments or both or further ones you should create an Interface ie:
interface MyCustomAction {
void triggerAction(boolean isTriggered);
}
Assign it to the Fragments and implementing it in the Activity responsible of Fragments
Declare Action in the Fragment:
private MyCustomAction myCustomAction;
Expose method to be assigned by Activity in the Fragment:
public void assignAction(MyCustomAction myCustomAction) {
this.myCustomAction = myCustomAction;
}
In the Fragment, when an onClickListner() is called, do that:
myCustomAction.triggerAction(true); //or False or what you want...
...and in the Activity:
myFragment.assignAction(new MyCustomAction() {
#Override
public void triggerAction(boolean isTriggered) {
//Doing something can be triggered by any Fragments using the same Interface
});
One way would be to create a separate class, which implements View.OnClickListener , and then pass an instance of that class to the setOnClickListener(...) method.
Im not entirely sure I fully understand you, are you saying that you have two onClickListeners and you want them to do the same thing without repeated code? If so, you can simply put the repetitious code in a subroutine and call it from both listeners. However if you mean that you have one onClickListener and you want it to listen for two different actions, then you can change those actions so that they act on the same listener. I am not sure what language you are using so I could not tell you how to do this but it should be fairly simple.
I am a newbie to android. My question is not about how to do something, but more on the idea I have in mind is optimized or not.
I am creating a Chat App. The biggest issue I was facing was storing Non persistent data, coz whenever the activity closed, all data was lost. The biggest problem was when user moved from Chat Screen (Chat Activity) to Peoples List (Peoples Activity) all data was lost again, and if user reinitited chat, he couldnt see the history.
As a workaround, I am creating a few data classes, and a service. The service stores data in the classes, whenever it receives an update from activity or the server. After that on each new activity I will just pass around this object from one activity to another and service.
I would like some recommendations in this, Is this a good way to go around? Thanks for your precious time.
If I've understood properly, you need a way to store data of variables or the content of one data structure or whatever and don't lose this data when your app change across severals activities, right? You need save state across several Activities.
First solution: in Java, one solution for this problem could be to use "static" variables. You can do it but using Android, we can use a more elegant solution.
Second and recommended solution: Associate the state with the Application Context (easy)
You should create your own subclass of android.app.Application. It will work like a singleton.
One subclass of Application inherit the properties of Application and you can access to this class wherever you want using the command "Context.getApplicationContext()". Normally you will use this class to have everthing that need a global access. Example:
class YourName_App extends Application {
private ArrayList<String> chatConversation;
public String getChatConversation(){
return this.chatConversation;
}
public void setChatConversation(ArrayList<String> chat){
this.chatConversation = chat;
}
}
And now your Chat Activity:
class Chat extends Activity {
ArrayList<String> conversation;
#Override
public void onCreate(Bundle b)
{
...
YourName_App appState = ((YourName_App) getApplicationContext());
conversation = appState.getChatConversation();
...
}
}
It is done! This is the best way to do it.
Sorry for my poor english.
I am working on an Application that require some interaction between two activities, and I am not sure of what is the best way to achieve it:
One of the Activities is a "Logbook" (Just a ListView that displays a bunch of events).
The other Activity allows the user to create the events, that will be sent (and displayed in the Logbook).
How do I notify my Logbook Activity when a new Event is ready to be added?
Also, where should I add the event to the database? From the Logbook Activity, when I add it to the ListView, or from the NewEvents Activity, as soon as it's ready?
Thanks!
Ok, I found how to do it, using a BroadcastReceiver:
In my Logbook activity, I just set up a new custom receiver onCreate():
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logbook);
registerReceiver(new EventReceiver(this), new IntentFilter("SEND_NEW_EVENT"));
Now, I can make the calls in my newEventActivity:
public void sendToLogbook(int eventId){
Intent i = new Intent("SEND_NEW_EVENT");
i.putExtra("newEvent", this.newEvents[eventId]);
sendBroadcast(i);
}
Of course, I had to create my CustomReceiver Class, and override the onReceive() method to do what I want:
public class EventReceiver extends BroadcastReceiver {
private ActivityLogbook activity;
public EventReceiver(ActivityLogbook activity) {
this.activity = activity;
}
public void onReceive(Context context, Intent i) {
this.activity.addToReport((Event)i.getParcelableExtra("newEvent"));
}
}
It works great so far, but if you do have comments/concerns about this, please tell me!
Thank you!
If I recall cporrectly the Notepad project which is included in the android sdk and is also part of the tutorials online is a good examaple which should satisfy your needs.
To borrow from MV-* (Model-View-something or other) patterns, separate your idea of the Model (in this case, your Event objects) and what is displaying them (the View, or in your case an Activity) and it'll become more clear.
If you have your events somewhere global where all activities can interact with them, then you can work with the model and display the model from wherever and however you choose.
One simple suggestion is have a class (EventController or something like that) that allows you to interact with the Events collection, and make it available through a derived Application class. I can explain further if that doesn't make sense. I have a pattern I use in my Android apps whereby all Activity classes have access to a custom global Application instance, so my model is a model and can be accessed by whatever Activities I want to have access.
This is merely one approach, and as always, there are many that may suit your needs.
One possibility would be:
The ListActivity gets all the data each time it is resumed and updates the ListView accordingly
The NewEventActivity does all the job of storing the Event and simply finishes
You can improve it a bit more:
The ListActivity gets all the data when it starts
The ListActivity starts the NewEventActivity expecting a OK/CANCELLED result
The NewEventActivity does all the job of storing the Event and returns a result saying OK or CANCELLED
Depending on the result it gets from the NewEventActivity, ListActivity reloads its data or not