Screen rotation during long-term operation

Introduction


When developing almost any application with a user interface, a programmer sooner or later encounters a situation when you need to perform a long-term operation. During a long-term operation, usually the user is shown a "Please wait ..." window or something like that.

The Android platform, and probably many other platforms, do not allow long-term operations in the UI stream. Performing a long-term operation in a UI thread, you simply hang the program.

Android offers AsyncTask for this kind of task . AsyncTask allows you to perform a long-term operation and interact with the UI thread.

Problem


It would seem nothing complicated, create an AsyncTask, pass the pointer to the current Activity to the created AsyncTask, and you're done, the background process is running, updating the UI, everyone is happy.

Everything works fine until the screen orientation (Portrait → Landscape, Landscape → Portrait) or the application is sent to the background. Typically, with this approach, after changing the screen orientation, the application crashes.

Why does application crash


Because when you change the orientation of the eran, Android recreates the Activity, as a result, the Activity to which you passed the link to AsyncTask is already destroyed and your AsyncTask is trying to interact with the destroyed object.

Solutions


Everyone solves the problem in different ways, I will not describe all the proposed methods of solution, you can find them on Google either in various blogs or on StackOverflow.

Each approach requires the implementation of certain tweaks, additional tests, debugging, writing additional code or limiting the capabilities of the user interface.
Faced with this problem, I was very annoyed that for such a trivial task there is no ready-made box solution (in any case, I did not find it).

Can i try


Please do not judge strictly and do not consider it self-PR, I just want to write how I solve this problem and share the solution with others.

I wrote some kind of framework (I think that the framework is too loud for my solution, but due to the peculiarities of use it is still a kind of framework) and posted it on Github.

The source code is open, the Apache 2.0 license , I emphasize once again that I do not sell anything, do not impose and do not beg. The framework is called Asmyk .

How does it work


When an Activity is activated (onResume event), the Activity is marked in the application context. Next, the background task addresses the UI of the Activity task from the context.

Yes, nothing complicated, but when implementing this scheme, a novice programmer can be a little complicated and will have to spend a couple of days to implement a quality solution.

How to implement


Download the AAR file and connect to the project .

If you do not extend the Application class with your implementation, specify the attribute in the AndroidManifest.xml file in the application tag:

android:name="net.mabramyan.asmyk.core.AsmykApplicationContext"

Example:


...

If you extend the Application class with your implementation, you must inherit your implementation from the AsmykApplicationContext class.

Activities with which you will work from the background should be inherited from AsmykCompatActivitiy.
Note: You can inherit at least all of your Activities from AsmykCompatActivitiy.

Example


UI "Please Wait ..."


Create an Activity inherited from AsmykPleaseWaitActivity or from AsmykBasicPleaseWaitActivity.

What you need to implement for AsmykPleaseWaitActivity


The method describes the actions that the Activity should perform when updating the status of the operation. The progressObj object will be passed from AsmykPleaseWaitTask:

void onProgress(final Object progressObj)

The method describes the actions that the Activity should perform when the operation fails. The errorObj object will be passed from AsmykPleaseWaitTask.

void onFail(final Object errorObj) 

The method describes the actions that the Activity should perform when the operation is successful. The successObj object will be passed from AsmykPleaseWaitTask.

void onSuccess(final Object successObj)

What you need to implement for AsmykBasicPleaseWaitActivity


The method describes the actions that the Activity should perform when the operation is successful. The successObj object will be passed from AsmykPleaseWaitTask:

void onSuccess(final Object successObj)

The onFail and onProgress methods are already implemented. As arguments, take String with a description of the error or with a description of the new state of the background task, respectively.

Background task


Next, create a background task implementing the AsmykPleaseWaitTask class. You will have to implement just one method describing your background task:

void doInBackground(final AsmykApplicationContext ctx)

In the process of executing the task, you can call the method void fireProgress(AsmykApplicationContext ctx, final Object progressObj)- this method will subsequently call onProgress in your AsmykPleaseWaitActivity. Upon completion of the task, call fireSuccess or fireFailed, depending on the result of the operation.

Launch


An example of calling a background task:


pleaseWaitTask.start((AsmykApplicationContext) MainActivity.this.getApplicationContext());
Intent intent = new Intent(MainActivity.this, PleaseWaitActivity.class);
startActivity(intent);

Attention: AsmykPleaseWaitTask will actually start the task only after the Activity inherited from AsmykPleaseWaitActivity is shown.

This is done so that the background task does not finish before the Activity is displayed.

You can see an example of a simple application here .

Appeal to commenters


Thank you for reading and taking the time to comment.
I am for criticism if it is constructive.
In order for the post to be useful for other readers, let's do this:
If you think any code constructs are not correct, describe why.
If you offer a method that is more convenient or more correct than the one described above, apply your solution to the task (this is the main task that the framework solves above):
1) We have already received a piece of data from the user for registration, the user clicks “Continue”
2) Perform the registration step 1. N different requests are sent sequentially. Here I want to show the user what the program is doing right now. In this case, rotation of the screen, etc. must not interrupt the registration process.
From my point of view, there can be many such tasks in a real application.

PS I suppose if we apply real examples, the post will be as useful as possible.

That's all! Thanks for attention.

Also popular now: