I am new to Xamarin Android. I am looking to create a multi-step registration form i.e. wizard process.
I am seeking for some best practises on a approach that can save each step state in order to build up a model and then submit the model (Builder design pattern).
I am not sure how to save a state when going to another view. From research, would i pass a view model as part of the intent by calling PutExtra to pass data ?
I am not sure what is the good way doing this. I am using MVVMCross for building up the viewmodel. I hope the community can assist me on the right direction please
In MvvmCross you don't pass data between views, but all navigation is done between ViewModels. Extensive documentation about this can be found at: https://www.mvvmcross.com/documentation/fundamentals/navigation
An example is:
public class MyViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public MyViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public override void Prepare()
{
//Do anything before navigating to the view
}
public async Task SomeMethod()
{
await _navigationService.Navigate<NextViewModel, MyObject>(new MyObject());
}
}
public class NextViewModel : MvxViewModel<MyObject>
{
public override void Prepare(MyObject parameter)
{
//Do anything before navigating to the view
//Save the parameter to a property if you want to use it later
}
public override async Task Initialize()
{
//Do heavy work and data loading here
}
}
Related
I'm using Retrofit with RxJava2 to obtain some data from a Rest API. I want to use a SwipeRefreshLayout to update the view and I'm using a ViewModel to handle the API call, so I want to implement a method in there to refresh the data programmatically.
I want to obtain something like this https://stackoverflow.com/a/34276564/6787552 but instead of having a periodic trigger, I want to do that programmatically when the user pull to refresh.
That's the ViewModel:
public class DashboardViewModel extends ViewModel {
public final Single<Dashboard> dashboard;
public DashboardViewModel() {
dashboard = Api.getDashboard();
refresh();
}
public void refresh() {
// Refresh data
}
}
And in the DashboardFragment:
#Override
public View onCreateView(...) {
...
viewModel.dashboard
.observeOn(AndroidSchedulers.mainThread())
.subscribe(dashboard -> {
binding.setDashboard(dashboard);
binding.swipeRefreshLayout.setRefreshing(false);
});
binding.swipeRefreshLayout.setOnRefreshListener(() -> viewModel.refresh());
...
}
Thank you in advance!
EDIT:
That's what I ended up doing:
public class DashboardViewModel extends ViewModel {
private final BehaviorSubject<Dashboard> dashboard;
public DashboardViewModel() {
dashboard = BehaviorSubject.createDefault(Api.getDashboard());
}
public void refresh() {
// I use a Object because null values are not supported
dashboard.onNext(Api.getDashboard());
}
public Observable<Dashboard> getDashboard(){
return dashboard;
}
}
And then in the DashboardFragment just subscribe to viewModel.getDashbaord()
I'm not 100% sure that I understood what you want to do but if I got the question right, you can do something like this:
put a subject inside the model (probably a BehaviorSubject?)
expose it as an observable to the
view and subscribe to it (instead of subscribing to the single)
in the model, when you
receive a new call to refresh() from the ui, do something like
subject.onNext(Api.getDashboard())
in this way, each call to refresh will cause the emission of a new dashboard, and that will be properly bound by the subscription in the view.
I have used LiveData and ViewModel example
but i dont understand use of this feature because i can change value directly without use this feature even this is growing number of line in code by using observing code and same as in ViewModel by creating MutableLiveData.
below ViewModel Code
public class FirstViewModel extends ViewModel {
// Create a LiveData with a String
public MutableLiveData<String> mCurrentName;
public MutableLiveData<String> getCurrentName() {
if (mCurrentName == null) {
mCurrentName = new MutableLiveData<String>();
}
return mCurrentName;
}
}
Using in Activity
public class MainActivity extends AppCompatActivity {
private FirstViewModel mModel;
ActivityMainBinding mBinding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding=DataBindingUtil.setContentView(this,R.layout.activity_main);
// Get the ViewModel.
mModel= ViewModelProviders.of(this).get(FirstViewModel.class);
// Create the observer which updates the UI.
final Observer<String> nameObserver = new Observer<String>() {
#Override
public void onChanged(#Nullable final String newName) {
// Update the UI, in this case, a TextView.
mBinding.mNameTextView.setText(newName);
}
};
// Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
mModel.getCurrentName().observe(this, nameObserver);
mBinding.btnSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String anotherName = mBinding.etField.getText().toString();
mModel.getCurrentName().setValue(anotherName);
}
});
}
}
The ViewModel and LiveData android architecture components together help to create lifecycle aware applications.
ViewModel:
ViewModel classes are often used to significantly segregate the view logic (present in Activity classes) from the business logic which is contained in the ViewModel classes. This segregation is a good architecture design and becomes very important while maintaining large projects.
LiveData:
LiveData helps in implementing the Observer Observable pattern in a lifecycle aware manner.
In your case, it may seem trivial since you are only setting value for a TextView. However consider common scenarios like hitting an api to retrieve data, etc. In such cases, the ViewModel is responsible for providing the data to be displayed in the Activity, which when done with the help of LiveData can help avoid crashes by ensuring lifecycle awareness easily.
You can read about live data from here. It is like Observer that looks for changing of data and notify observers that observable object has changed
In simple words its make your life eazy as a programmer when we go into the details like activity/fragment lifecycle handling, displaying updated data and more importantly separating the presentation layer from business logic and to create a more well structured application. please find more details from here
I am using the visitor pattern to abstract payment processing away from the UI code in android. I have some doubts on what i should pass into the visitor constructor inorder for the view to get a call back once its done processing the payment.
Let me show you what i have so far:
i am dealing with 2 payment systems, thus two payment strategies (brainTree and Stripe):
public class BrainTreePaymentStrategy implements IVisitable {
#Override
public void makePayment() {
}
#Override
public void accept(Visitor v) {
}
}
public class StripePaymentStrategy implements IVisitable {
#Override
public void makePayment() {
}
#Override
public void accept(IVisitor v) {
}
}
public interface IVisitable {
void makePayment();
void accept(IVisitor v);
}
public interface IVisitor {
//list out all the classes the visitor can visit now
void visit(StripePaymentStrategy stripePaymentStrategy);
void visit(BrainTreePaymentStrategy brainTreePaymentStrategy);
}
//now critical, lets create a real concrete visitor that can actually do the work:
public class PaymentStrategyVistor implements IVisitor {
#Override
public void visit(StripePaymentStrategy stripePaymentStrategy) {
//process the braintree payment here, but how to give call back to UI ?
}
#Override
public void visit(BrainTreePaymentStrategy brainTreePaymentStrategy) {
//process the braintree payment here, but how to give call back to UI ?
}
}
i am using uncle bob's clean architecuture so my network calls are through usecases and also im using mvp for my presentation layer so i have access to presenter and usecase if needed.
So again my question is regarding PaymentStrategyVistor class, what do you think if i passed in the presenter as a constructor parameter. i for example , could then call presenter.doBrainTreePayment("someToken"); i could do that in the visitors visit(BrainTreePaymentStrategy brainTreePaymentStrategy) method. is this how you all would do it ?
Your suggestion (passing the presenter to the constructor of each visitor) seems to be totally fine.
Looking from clean architecture perspective this all is fine as long as u do not violate the dependency rule. so if ur strategy and visitors live in the "interface adapter layer" u can easily pass the presenter. on the other hand if ur strategy/visitor belong to the "use cases layer" than passing the presenter would violate the dependency rule and u should not do it.
For a more detailed discussion on presenters in clean architecture see my blog post: https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/
Would it be an anti-pattern if from a Presenter layer I open an Activity?
If so, should I manage the navigation of the app from the View Layer?
Yes it's an anti-mvp-pattern. Based on passive view in MVP, you lost your testability, because you don't have to deal with the android framework in your presenter.
So it's better to manage the navigation of the app from the View Layer.
class MyPresenter {
MyPresenter.View view;
void backButtonClicked() {
view.navigateToHomeScreen();
}
public interface View {
void navigateToHomeScreen();
}
}
class MyActivity extends Activity implements MyPresenter.View {
#Override
void navigateToHomeScreen() {
startActivity(...)
}
#OnClick(R.id.my_button)
void onClick() {
presenter.backButtonClicked();
}
}
Also another advantage of this way is that it will be easy to replace activity with a fragment or a view.
Edit 1:
Morgwai said this way will break separation of concern and single responsibility, but you cannot have single responsibility every where. Sometime you need to violate it. Here is an example from Google for MVP:
TaskDetailPresenter calls ShowEditTask which is responsible to open a new Activity inside TaskDetailFragment.
But also you can use CommandPattern which is a better approach
interface NavigationCommand {
void navigate();
}
So, Presenter will use it when it needs.
As I wrote in my comment to the accepted answer, I think that managing navigation from the view layer is a clear breaking of separation of concerns rule: views should contain ONLY methods to update current UI screen.
The problem originates from the android platform design as Activity and Fragment classes contain both methods to operate on UI screen and to send intent objects that start other activities like startActivity.
A clean way to solve this would be to create some Navigator interface that would contain methods related to navigation, make activities implement it and inject it into presenters as well. This way at least from the presenters' standpoint navigation and UI manipulation would be separated. It may however look odd from activities' standpoint: now they would often implement both interfaces (Navigator and View) and pass their reference 2 times to the presenter. If because of this reason you decide to manage navigation from your view layer then at least keep methods for navigating separate from those for manipulating UI: never perform navigation and UI manipulation in the same method.
In my opinion it would be better if you open an activity from the View Layer. I prefer that Presenter knows about Activity as little as possible.
If there is some condition of what activity should be started, you can use something like this:
public class Presenter {
private ViewsPresentation mViewsPresentation;
public void someButtonClicked() {
if (/*some condition*/) {
mViewsPresentation.startFirstActivity();
} else {
mViewsPresentation.startSecondActivity();
}
}
public interface ViewsPresentation {
void startFirstActivity();
void startSecondActivity();
}
}
I have made this solution (in Kotlin):
I created an Interface called ViewNavigator
interface ViewNavigator {
fun navigateTo(target: Class<*>)
}
Then I made the View Interface Implement it
interface View : ViewNavigator {
//...
}
Then the Actual View (the activity) can override the navigateTo function
override fun navigateTo(target: Class<*>) {
startActivity(Intent(this, target))
}
So, whenever I want to navigate to any activity, I can simply write that in the presenter class. For example:
override fun onAnimationFinished() {
view.navigateTo(HomeActivity::class.java)
}
I just switched over from iPhone to Android and am looking for something similar to where in the iPhone SDK, when a class finishes a certain task, it calls delegate methods in objects set as it's delegates.
I don't need too many details. I went through the docs and didn't find anything (the closest I got was "broadcast intents" which seem more like iOS notifications).
Even if someone can point me to the correct documentation, it would be great.
Thanks!
Never mind... found the answer here :)
http://www.javaworld.com/javaworld/javatips/jw-javatip10.html
Pasting from the article so as to preserve it:
Developers conversant in the event-driven programming model of MS-Windows and the X Window System are accustomed to passing function pointers that are invoked (that is, "called back") when something happens. Java's object-oriented model does not currently support method pointers, and thus seems to preclude using this comfortable mechanism. But all is not lost!
Java's support of interfaces provides a mechanism by which we can get the equivalent of callbacks. The trick is to define a simple interface that declares the method we wish to be invoked.
For example, suppose we want to be notified when an event happens. We can define an interface:
public interface InterestingEvent
{
// This is just a regular method so it can return something or
// take arguments if you like.
public void interestingEvent ();
}
This gives us a grip on any objects of classes that implement the interface. So, we need not concern ourselves with any other extraneous type information. This is much nicer than hacking trampoline C functions that use the data field of widgets to hold an object pointer when using C++ code with Motif.
The class that will signal the event needs to expect objects that implement the InterestingEvent interface and then invoke the interestingEvent() method as appropriate.
public class EventNotifier
{
private InterestingEvent ie;
private boolean somethingHappened;
public EventNotifier (InterestingEvent event)
{
// Save the event object for later use.
ie = event;
// Nothing to report yet.
somethingHappened = false;
}
//...
public void doWork ()
{
// Check the predicate, which is set elsewhere.
if (somethingHappened)
{
// Signal the even by invoking the interface's method.
ie.interestingEvent ();
}
//...
}
// ...
}
In that example, I used the somethingHappened predicate to track whether or not the event should be triggered. In many instances, the very fact that the method was called is enough to warrant signaling the interestingEvent().
The code that wishes to receive the event notification must implement the InterestingEvent interface and just pass a reference to itself to the event notifier.
public class CallMe implements InterestingEvent
{
private EventNotifier en;
public CallMe ()
{
// Create the event notifier and pass ourself to it.
en = new EventNotifier (this);
}
// Define the actual handler for the event.
public void interestingEvent ()
{
// Wow! Something really interesting must have occurred!
// Do something...
}
//...
}
That's all there is to it. I hope use this simple Java idiom will make your transition to Java a bit less jittery.
The pendant for kotlin.
Define your interface: In my example I scan a credit card with an external library.
interface ScanIOInterface {
fun onScannedCreditCard(creditCard: CreditCard)
}
Create a class where you can register your Activity / Fragment.
class ScanIOScanner {
var scannerInterface: ScanIOInterface? = null
fun startScanningCreditCard() {
val creditCard = Library.whichScanCreditCard() //returns CreditCard model
scannerInterface?.onScannedCreditCard(creditCard)
}
}
Implement the interface in your Activity / Fragment.
class YourClassActivity extends AppCompatActivity, ScanIOInterface {
//called when credit card was scanned
override fun onScannedCreditCard(creditCard: CreditCard) {
//do stuff with the credit card information
}
//call scanIOScanner to register your interface
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val scanIOScanner = ScanIOScanner()
scanIOScanner.scannerInterface = this
}
}
CreditCard is a model and could be define however you like. In my case it includes brand, digits, expiry date ...
After that you can call scanIOScanner.startScanningCreditCard() wherever you like.
The main content of this video tutorial is to show how to use interfaces to delegate methods / data exchange between different Fragments and activities, but it is great example to learn how delegate pattern can be implemented in Java for Android.
Java callback is not the same thing like ios delegate, in ios you can use a callback almost the same way like in Android. In Android there is startActivityForResult that can help you to implement the tasks for what ios delegate is used.
I believe ListAdapter is a example of delegation pattern in Android.
Kotlin's official Delegation pattern:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
See: https://kotlinlang.org/docs/delegation.html