For a Xamarin Forms application how should I decide what goes in the App constructor or the OnStart()? - xamarin

Here's the code that I have:
public App()
{
InitializeComponent();
DB.CreateTables();
DB.GetSettings();
DB.PopulateTables();
SetResourceColors();
SetResourceDimensions();
MainPage = new MainPage();
activity = Helpers.Activity.Create();
VersionTracking.Track();
DeviceDisplay.MainDisplayInfoChanged += OnMainDisplayInfoChanged;
}
protected override void OnStart()
{
}
Can someone explain to me. Is there any difference between me placing the code such as I have in the constructor or in the OnStart() method? What's the normal way to do this?

I have been working with Xamarin.Forms for a long time now and this is how I and my fellow developers use the OnStart Method.
If you check the Microsoft documents it says the following about it :
OnStart - Called when the application starts.
So, first of all, you should know that there is no specific use of the OnStart method, to be very honest there is no major difference in between using the constructor or this lifecycle method because both get called on XF framework startup, first the constructor then the OnStart method.
Now let's come to the differences.
As Jason pointed out, the OnStart method is a lifecycle method and hence has a return type unlike the constructor, so you can even call an asynchronous piece of code in the OnStart method but you cannot do the same in the constructor as constructors cannot be asynchronous.
Which means if you have the below method:
public async Task<bool> IsSomeThingWorkingAsync(//SomeParams)
{
// Code
}
Now, this method cannot be asynchronously called from the constructor since constructors are forcefully synchronous and have no return types. But if you try doing that from the on start method it's quite easy and it will work. In this case, you use the OnStart method. Something like below:
protected override async void OnStart()
{
bool WasWorkSuccess=await IsSomeThingWorkingAsync();
//do something with the boolean
}
A constructor is intended to be used for wiring. In the constructor, you want to avoid doing actual work. You basically prepare the class to be used. Methods are intended to do actual work.
Note: There are no performance gains whatsoever by choosing one over the other - it's really a matter of preference and standard.

Please go through the details here
You can write the initialisation codes in App() constructor. But you need to be very careful abut registering events.
Reason is,
For example in Android, If the app is launched and it is in task list and if you try to launch the app again by clicking on app icon. The constructor of App() will call again. This will register the event multiple times and will create issues.
So for events I will suggest you to use overriden methods for registering events.
Again as Jason pointed it out, It is your personal preference where to write your code.

Related

Xamarin Async Constructor

For my application I need to fetch some data asynchronously and do some initialization for each page. Unfortunately, a constructor does not allow me to make asynchronous calls. I followed this article and put all of my code into the OnAppearing method. However, since then I ran into multiple issues since each platform handles the event a little bit differently. For example, I have pages where you can take pictures, on iOS the OnAppearing is called again every time after the camera is closed while Android doesn't. It doesn't seem like a reliable method for my needs, which is also described here:
Calls to the OnDisappearing and OnAppearing overrides cannot be treated as guaranteed indications of page navigation. For example, on iOS, the OnDisappearing override is called on the active page when the application terminates.
I am searching for a method/way where I can perform my own initialization. The constructor would be perfect for that but I cannot perform anything asynchronously in there. Please do not provide me with any work arounds, I am searching for a solution that is the "recommended" way or maybe someone with a lot of experience can tell me what they are doing. (I also don't want to .Wait() or .Result as it will lock my app)
You can use Stephen Cleary's excellent NotifyTaskCompletion class.
You can read more how it works and what to do/don't in these cases in Microsoft's excellent Async Programming : Patterns for Asynchronous MVVM Applications: Data Binding. The highlights of this topics are:
Let’s walk through the core method
NotifyTaskCompletion.WatchTaskAsync. This method takes a task
representing the asynchronous operation, and (asynchronously) waits
for it to complete. Note that the await does not use
ConfigureAwait(false); I want to return to the UI context before
raising the PropertyChanged notifications. This method violates a
common coding guideline here: It has an empty general catch clause. In
this case, though, that’s exactly what I want. I don’t want to
propagate exceptions directly back to the main UI loop; I want to
capture any exceptions and set properties so that the error handling
is done via data binding. When the task completes, the type raises
PropertyChanged notifications for all the appropriate properties.
A sample usage of it:
public class MainViewModel
{
public MainViewModel()
{
UrlByteCount = new NotifyTaskCompletion<int>(
MyStaticService.CountBytesInUrlAsync("http://www.example.com"));
}
public NotifyTaskCompletion<int> UrlByteCount { get; private set; }
}
Here, the demo is about binding the returned asynchronous value to some bindable property, but of course you can you is without any return value (for simple data loading).
This may be too simple to say, but you CAN run asynchronous tasks in the constructor. Just wrap it in an anonymous Task.
public MyConstructor() {
Task.Run(async () => {
<Your code>
}
}
Be careful when doing this though as you can get into resource conflict issues if you accidentally open the page twice.
Another thing I like to do is use an _isInit flag, which indicates a first time use, and then never again.

MvvmCross ViewModel Start method async behavior clarification

In my ViewModel I load data in (overrided) Start method, like so:
public override async void Start()
{
base.Start();
await ProcessItems();
// or the following (no difference for Start method behavior)
await ProcessItems().ConfigureAwait(false);
}
However, it doesn't look like the await/async logic actually works with the method (I tested it with Android only, though).
"Doesn't work" means that right after calling my awaitable ProcessItems all the rest of ViewModel pipeline is called (like Initialize, ViewCreated, ViewAppearing etc.) before the awaitable method actually finished work.
Which brings up some further issues as the rest of methods expect the data initialization already finished.
So, what should I take into consideration here and how handle this situation.
Thanks!
The calling code can't await Start because it is returning void. Any exceptions being thrown in there are being swallowed. If the method returned Task or Task<T> then this would work as you expect. You pretty much never want to use async void except in an event handler. There is an MSDN article going further into detail as to why async void should be avoided.
This problem is fixed in MvvmCross 5 and later where you would do this same kind of initialization in Task Initialize method in place of this void Start method.
Since MvvmCross 5.0 there is a new lifecycle. https://www.mvvmcross.com/documentation/fundamentals/viewmodel-lifecycle#initialize
Please use Initialize for your stuff instead of Start.
Initialize: All heavy work should be run here. This method returns a Task, which means you can mark it as async and use await safely. If this method fails, the Navigate call that you are probably awaiting will fail, so you might want to catch that exception.
public async Task Initialize()
{
await base.Initialize();
await ProcessItems();
}

Is it bad practice to mark void-returning view lifecycle methods like ViewDidLoad/OnCreate async?

Most of the articles on async/await best practices suggest that async void methods should be avoided unless the method is an event handler.
What are the best practices for handling situations where you need to call an async method during initialization of a view?
I've seen code that marks lifecycle methods such as ViewDidLoad, ViewWillAppear, OnCreate, OnResume etc as async void so that a method can be await-ed in the method body - but my gut reaction to this is that it is dangerous if the method is an override from the framework - since the consumer might not be aware of the context in which the method is being used internally.
An alternate approach could be to assign the result of the async method to a Task. Then await that Task before any dependent code runs:
Foo.cs:
async Task SomeMethodForInit()
{
//some code here for Init
}
Android Fragment:
Task _initTask;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
_initTask = fooInstance.SomeMethodForInit();
}
...
//call this before doing anything dependent on that task
await _initTask;
Is this the right approach?
I like this post on async/await best practices. The biggest problem imho is from exceptions not getting handled properly when encountering async void.
To answer your question: Is there a specific reason why you have to use await or maybe can you choose a different approach to solving your problem? If you can, great, if not, the "downside" should be negligible.

Use one instance of AsyncTask throughout Activity

I have a number of AsyncTask set up as individual classes. I reuse them throughout my app. I wonder, in places where the same AsyncTask may be needed more than one is it possible to use one instance of that custom AsyncTask class multiple times? This is really a cosmetic problem since it bothers me having redundant sections of code, especially when an AsyncTask uses a callback to communicate with it's starting activity.
I've tried to do it this way -
MyTask task = new MyTask(new someCallBackListener){
#Override
public void taskDone(boolean youDone){
}
});
And then in my activity just calling
task.execute(params);
This seems to work the first time, but I cannot execute it more than once. Do I really just need to initialize a new task each time I want to use it?
An asynctask can be executed only once as per the android documentation here(section Threading rules)which says
The task can be executed only once (an exception will be thrown if a
second execution is attempted.)
So its not possible to reuse an AsyncTask instance. Further this SO link would help you!
While you can't use twice the same instance I think you could reuse the callback implementation by creating the instance this way
new MyTask(this).execute(params);
and implementing the callback in the Activity or the Fragment like this
public class SomeActivity extends Activity implements MyTask.someCallBackListener {
//All the Activity code
public void taskDone(boolean youDone) {
}
}
This way, you can create multiple instances of your AsyncTask without those redundant sections of code that bother you.

Zend controller's predispatch method

I was reading this to understand zend's MVC Request Lifecycle.
But i can't think of any cases in zend where i would use a controller's predispatch method , isn't the init method enough for the code that i want executed before controller's actions .
What should exactly should be in a controller's predispatch and not init .
Can you give an example ?
See Zend_Controller_Action - Object Initialization and the following section Pre and Post Dispatch Hooks. They both go into some detail on the two, and the Action Controller itself.
init() is more for setting up the controller object and doing initialization that will be available to all of your actions. Since init() runs prior to preDispatch(), anything you set up in init() will be available for preDispatch() to use. While it is possible to forward or redirect from init(), it is best practice to do it from preDispatch() because it runs prior to dispatching the controller action.
From the manual:
Note: Usage of init() vs. preDispatch() What is the difference between them (init and preDispatch), and what actions would you take
in each?
The init() method is primarily intended for extending the
constructor. Typically, your constructor should simply set object
state, and not perform much logic. This might include initializing
resources used in the controller (such as models, configuration
objects, etc.), or assigning values retrieved from the front
controller, bootstrap, or a registry.
The preDispatch() method can also be used to set object or
environmental (e.g., view, action helper, etc.) state, but its primary
purpose is to make decisions about whether or not the requested action
should be dispatched. If not, you should then _forward() to
another action, or throw an exception.
Note: _forward() actually will not work correctly when executed from init(), which is a formalization of the intentions
of the two methods.
to extend drew010's answer here is an example of how I use preDispatch() and int():
public function preDispatch() {
$this->_helper->layout->setLayout('admin');
}
/**
*initiaize the flashmessenger and assign the _session property
*/
public function init() {
if ($this->_helper->FlashMessenger->hasMessages()) {
$this->view->messages = $this->_helper->FlashMessenger->getMessages();
}
//set the session namespace to property for easier access
$this->_session = new Zend_Session_Namespace('location');
}
I use preDispatch() to set the layout for every action as it not the default layout and in init() I initialize my flash messenger and setup the session namespace for this controller and initialize the session as a property.
Here's one popular gotcha where you can waste loads of resources using init() instead of preDispatch(): if you do access control using controller plugin's preDispatch() method then call sequence will be: YourController::init(), YourAccessPlugin::preDispatch(), YourController::preDispatch(), YourController::whateverAction. This means that if you do any heavy lifting in init() then unauthorized users can trigger it. Say for e.g. you start a new session namespace in init() then mindless search bots can cause your session database to be littered with empty sessions. So stick to very basic simple stuff in init, avoid touching or modifying any resources, avoid database access.

Resources