Can bad stuff happen when calling a class from an Activity? - android

I am calling a class from my Activity. The class I am calling doesn't extend a Service or a Activity. It is just a worker class that I am using to process a BufferedReader object. I am concerned that if the app loses focus during the processing of the BufferedReader I could be left with messy data. So what happens when my Activity calls a class to perform database entries and the Activity loses focus. I am thinking of making my worker class a Service so that I will have access to the OnPause and OnResume methods. Not sure what I should be doing. Does anyone else have any clues about this.

You have to leverage the Android Activity Lifecycle.
class MyActivity extends Activity {
private MyWorkerClass myWorkerClass;
void onCreate() {
myWorkerClass = new MyWorkerClass();
myWorkerClass.startLoading();
}
void onPause() {
// You know the activity is going into the background
// so act appropriately in your worker class
myWorkerClass.stopLoading();
}
}
The issues you describe above are very generic, so explaining any specific implementation wouldn't help.
If you wanted your worker class to complete the work even if your Activity goes into onPause then yes you would want to do the work in another Thread and possibly in a Service. You can still have your worker class though for nice OO & adhering to the SRP.

You can create an IntentService if its a simple one-time task, or extend Service class if this is a continuous task. Also, have a look at AsyncTaskLoader.
If app process is being terminated, you need to make sure you don't leave the IO medium in a inconsistent state, or with corrupt data. So, use transactions in case of databases, write to a temporary file and replace at end in case of file IO, use confirmation requests in case of remote IO.

Related

Does fragment onStop run on UI thread

I have some fragments loaded in a ViewPager, where each "page" is loaded from a row in a cursor. Each fragment shows an image (JPEG) on the device. When the user dismisses the fragment (i.e swipe/page change, hits back/up, or just closes the app entirely) I want to invoke a method which opens the JPEG file for writing and does an update of its metadata. The actual work is eventually handled by the Apache Commons Imaging library.
I've implemented this by invoking my saveToFile() method from each fragment's life cycle onStop() handler. Does this mean the entire file operation ends up running on the UI thread? Should I definitely set up an AsyncTask for this?
Say the file write for some reason suddenly (for some jpeg) should take a long time, eg 2 minutes. What would then happen? Would the UI just wait (freeze) at this page/fragment before resuming? Or would the process (write to file) carry on "in the background" somehow? Or would the process just be killed, stopped short mid-process?
The way I have this wired up currently (onStop invoking saveToFile(), which calls up the imaging library and then updates the file) seems to work as it should. Even if I end the app, I still see my Toast text popping up, saying "Writing to file..." Seemingly, the process is never disturbed, and I can't say I'm experiencing any UI lag.
onStop() handler. Does this mean the entire file operation ends up
running on the UI thread? Should I definitely set up an AsyncTask for
this?
YES
An AsyncTask has several parts: a doInBackground method that does, in fact, run on a separate thread and the onPostExecute method that runs on the UI thread.
You can also use some sort of observer pattern such as EventBus to run async and post results to the UI.
Say the file write for some reason suddenly (for some jpeg) should
take a long time, eg 2 minutes. What would then happen? Would the UI
just wait (freeze)
The application will crash because Android will forcefully close it due to ANR (Application Not Responding).
Refer to the official documentation for details on this: https://developer.android.com/training/articles/perf-anr.html
Android applications normally run entirely on a single thread by
default the "UI thread" or "main thread"). This means anything your
application is doing in the UI thread that takes a long time to
complete can trigger the ANR dialog because your application is not
giving itself a chance to handle the input event or intent broadcasts.
Therefore, any method that runs in the UI thread should do as little
work as possible on that thread. In particular, activities should do
as little as possible to set up in key life-cycle methods such as
onCreate() and onResume(). Potentially long running operations such as
network or database operations, or computationally expensive
calculations such as resizing bitmaps should be done in a worker
thread (or in the case of databases operations, via an asynchronous
request).
The most effective way to create a worker thread for longer operations
is with the AsyncTask class.
Here is what I recommend though. Use the above mentioned, EventBus and create a BaseActivity which will automatically save the data for you onClose() by firing an event that runs Async. You then extend that base activity in all the places where you need autosave capabilities.
Here's what I mean with an example that uses EventBus.
public abstract class BaseActivity extends Activity{
#Override
protected void onResume(){
if(!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
super.onResume();
}
#Override
protected void onDestroy() {
if(EventBus.getDefault().isRegistered(this))
EventBus.getDefault().unregister(this);
super.onDestroy();
}
#Override
protected void onStop() {
super.onStop();
//We fire event and pass the current parent class that inherited this base.
EventBus.getDefault().post(new EventBusProcessMySaveData(this.getClass()));
}
}
//Your model class to use with EventBus
public final class EventBusProcessMySaveData{
private final Class className;
public EventBusProcessMySaveData(final Class className){
this.className = className;
}
public Class getClassName(){
return this.className;
}
}
public class MyMainActivity extends BaseActivity{
//Do you standard setup here onCreate() and such...
//Handle Event for Saving Operation, async.
//This will fire everytime theres an onClose() IN ANY activity that
//extends BaseActivity, but will only process if the class names match.
#Subscribe(threadMode = ThreadMode.ASYNC)
public void methodNameDoesNotReallyMatterHere(final EventBusProcessMySaveData model){
//We make sure this is the intended receiving end by comparing current class name
//with received class name.
if(model.getClassName().equals(this.getClass())){
//Do whatever you need to do that's CPUintensive here.
}
}
}

What is the expected behavior of SQLite CRUD operations after a configuration change or if the activity that started those operations is destroyed?

I'm refactoring an app I made some time ago. Back then I was taking my first steps into Android and the easy way to go was to avoid orientation changes, for almost all my CRUD operations I used the AsyncTask class, didn't implement a Content Provider or used Fragments.
Now I have made some changes:
I use Fragments to encapsulate functionality
All accesses to my database are done through a Content Provider
I use CursorLoaders to retrieve my data taking advantage of the content observation and automatic background loading the LoaderFramework brings.
The only problem I have now is that I'm not quite sure how to handle the rest of the CRUD operations (Create,Update, and Delete).
I've found that I can use the AsyncQueryHandler class, but there's not enough information online.
One thing I like the Loader Framework, is that is aware of the Activity or Fragment lifecycle, but what about the AsyncQueryHandler?
What happens to the operations that were started with startDelete, startInsert, startUpdate when the Activity/Fragment undergoes a configuration change? Or when I press the back button? Or worse yet, if the activity is destroyed?
What is the expected behavior of this kind of operations in such cases? Should they be cancelled or should they continue to do their work?
All the operations I've mentioned above are not that complex. For real complex operations I've used Services or IntentServices, but since I don't consider a good idea to run SQLite operations on the main thread I want to use a better solution, but first I need to know how that solution should react to the Activity/Fragment lifecycle events.
Any comments or suggestions would me greatly appreciated.
Thanks.
If you use AsyncQueryHandler you have to take into consideration that this abstract wrapper is created and executes provider operations on the thread that it was started on. If you call this from UI thread the callbacks will be sent to the UI thread. If you call this from another working thread, the callbacks will be sent to that working thread.
This is not bound to the lifecycle of the fragment or the activity, ContentProviders don't have an lifecycle.
The AsyncQueryHandler at an basic level, creates an Message object which is added to the MessageQueue of an single background thread. No matter from which activity/fragment you use the AsyncQueryHandler all the Message objects will end up on the same MessageQueue.
Once the background thread processes an request it will send the response back to the instance of the AsyncQueryHandler from which the request was initially made.
My recommendation is to use the Loaders from Android. These are directly tied to the lifecycle of the activity/fragment. You can have multiple Loaders in a LoaderManager(one LoaderManager per activity/fragment) which allows to do more complex operations. Your activity/fragment will automatically be notified when the content has changed(very useful when you want to combine it with your custom methods for CRUD operations or if you need to use long running services). Another very important feature they have is that they will always reconnect to the last Loader, thus you will avoid re-querying your content.
I recommend you search for some tutorials for implementing Loaders in Android. You can start with these:
Loaders - part 1
Loaders - part 2
Loaders - part 3
Loaders - part 4
Answer for your last comments:
I suggest to use the EventBus library (https://github.com/greenrobot/EventBus) to make the communication between your AsyncTasks/Thread and your other components.
You can start by creating an abstract AsyncTask/Thread and on top of that to make your specific command.
For example:
public abstract class AbstractThread extends Thread {
#Override
public void run() {
super.run();
command();
}
abstract void command();
}
In the abstract class you could make some DB initialization, verification or anything else that might make sense for your application.
public class InserTask extends AbstractThread{
#Override
void command() {
//TODO: Add logic for the insert task
}
}
public class UpdateTask extends AbstractThread{
#Override
void command() {
//TODO: Add logic for the update task
}
}
In these specific classes, just add your logic of the CRUD operation.
To have control over these threads, like when they should be stopped, paused, resumed you could create and ThreadPool manager which controls your threads. You can read more how to achieve this here: Thread Pool

accessing UI elements of activities from another class

Ok first of all android is really confusing. The scenario is I have about two runnable classes which are created from a Login View and if logged in it will create another view which will have other data and even more activities can be created from there
Now I can pass the the Login view context when creating a thread for the runnable class and edit out UI elements in them like this:
((Activity)someContext).runOnUiThread(new Runnable(){
public void run()
{
TextView txtErr = (TextView) ((Activity)someContext).findViewById(R.id.errMsg);
txtErr.setText("Some message");
}
});
But the issue is there will be more activities that will be created and the runnable class is created at the time of logging in, and I can't keep passing contexts.
Is there a better way for accessing the UI elements of different activities from different threads?
P.S: the threads which will be accessing the UI elements doesn't extend Activity and are running in a separate thread.
EDIT
I think I need to make my question more clear... I am developing a client app for a messenger... The process goes this way... User clicks on login button which creates a thread in a separate class named ClientThread for handling socket connection and keeping the connection alive till the user logs out or connection drops. The ClientThread class loops till the socket is connected and whenever some data is received the data is passed to another thread in a class named ProcessDataThread which do the parsing of data and will update the UI accordingly.
Now in a response from server if the user is logged in I want to create an activity from that class and keep a context to that activity in ProcessDataThread as I will be updating UI on further responses from server. And if login fails ProcessDataThread will display a message on the main activity saying login failed, now I was able to achieve the later by passing the context from the MainActivity to the two threads when clicked on Login like this:
global_constants.clientObject = new ClientThread(this);
global_constants.clientThread = new Thread(global_constants.clientObject);
global_constants.clientThread.start();
And then from ClientThread to ProcessDataThread
global_constants.updateConversationHandler.post(new ProcessDataThread(SharedBuff, cntxt));
But how will I create more activities from a non-activity class and do all update them or find a UI element etc...
Not sure if I understand you, but it sounds like you are trying to control the view of an activity from outside of the Activity. This sounds hacky to me. I'd let each Activity manage its own UI.
A good way of doing decoupled communication between objects is the observer pattern, aka an "event bus" or "event dispatcher" system. An example of how to do this on Android is here: http://www.therealjoshua.com/2012/03/event-dispatching-sending-messages/
Basically, the code that's generating the error should dispatch a message. The Activity can listen for this message, and then update its own UI as needed.
EDIT
Thanks for the clarification. I think the observer pattern can still help here. Basically, your data processing threads shouldn't know anything about the UI. Just have them post an event for the error, optionally with additional info on the error. If you want, your event dispatcher class could even make the actual event calls on the UI thread itself using a Runnable like you showed, so that the listener can always assume that they are being called on the UI thread, if this is important for your design. This way you don't have to pass the context to the thread at all (at least not for purposes of updating the UI) - let the worker thread just be responsible for the work, and the activity can be responsible for its own UI.
Another option you could use is an android Handler (see http://developer.android.com/reference/android/os/Handler.html)
In this case, the work is still done in another thread, but the Activity receives a handleMessage callback from the thread at the appropriate time. I haven't used this myself but from the documentation it looks like it can get the job done for what you need.
In either case IMO, the responsibility for updating the UI should lie with the Activity, not the worker thread.

Controlling a spawned Thread from multiple activities in Android

I have an application that runs a background thread which periodically performs a task. The UI thread moves through several different activities.
The tutorial I used can be found at this blog, the gist of it is the following:
Create a class that extends Thread
public final class JSONThread extends Thread {
Define a method in this class that adds a task to the MessageQueue, prompting executing when able.
public synchronized void enqueueJSON(final JSON.JSON task) {
However, after creating the initial object in my main activity, navigating to another activity obviously loses the Object bound to my Thread. I am no longer able to call methods on that Object (hence unable to add to queue).
I am unsure if this is caused by a wrong decision in architecture on my part or by overseeing the obvious solution. Any ideas? Note that I am trying to avoid AsyncTask for this purpose, since a pool of five threads for a simple task seems a little too much.
You need to store a Thread object as member of some other object with lifetime longer than Activity.
Two ideas for you:
a) It could be a member of Application (http://developer.android.com/reference/android/app/Application.html)
You may have problems with this, if you don't have a Service running. There is no guarantee that your application won't be killed (as example if any system dialog will pop up on top of your activities)
b) It could be a member of Service
(http://developer.android.com/reference/android/app/Service.html)
You should be using a service, not a thread. A service will remain in the background so long as there is an activity bound to it, and it won't be reset when an activity exits.

When to use a service in Android

I have a class that fetches data in response to button presses in the main activity. Unfortunately, I keep running into problems because this class is not an Activity or a Service. For example, without a Context I cannot translate a resource id into a string:
getString(R.string.example_string); // Doesn't work
Should I make this class into a Service and have the main Activity stop the class when it is closed? Should I pass the Context from the Activity into this class like this?
MyClass c = new MyClass(this);
Or is there some better way to handle this problem?
This issue also comes up when I try to send a Toast from this class.
Update: Erich and Janusz pointed me in the direction of the AsyncTask class which works perfectly, except that it creates a new thread and never kills that thread. This means that ever time the user presses a button, another thread is added and the old ones just sit there.
If you have a background action whose lifecycle is decoupled from your activity, I would use a Service. In that case, the Service will have its own Context, so you won't need to pass it in. If, however, you need to perform a background action in response to a UI event (and optionally post the results back into the UI thread), I would recommend you use an AsyncTask.
I agree with Erich, if you only have a something small like posting a change to a web backend or loading something from the phone memory to show it on screen use a Async Task. If the task will exit very "quick" (some seconds) you can make an anonymous class inside your activity. This will enable you to use a implicit reference to the outer activity inside the task and you can get your context from there.
If the task is running for a longer time you can pass down the context. If you are passing down the context try to not pass this from the activity use this.getApplicationContext() this will minimize the number of references to your activity and enable the garbage collector to clean up properly.

Categories

Resources