Load data in a time-sensitive way for a Broadcast Receiver - android

I am listening to a broadcast through a BroadcastReceiver. The nature of my requirement isneeding me to load some sizable data from SQLite DB in a very time sensitive manner. I need the data fast. The ideal way for me to have the data pre-loaded and prepared before BroadcastReceiver.onReceive hits.
What's an ideal way to do this?

Not including static code, you cannot do anything in a BroadcastReceiver before the onReceive call. The only thing you could do is override the default (no-argument) constructor, but that won't help you either since you do not have a valid Context yet with which to access and open your database (the Context is passed in as an argument to onReceive).
If the work you want to do is too long to be done in a BroadcastReceiver, then your receiver needs to start a Service and have the work be done there instead. If you don't want the Service to stay alive, you can use an IntentService, which will manage its own lifecycle and stop itself after it finishes whatever work is done in onHandleIntent.
BroadcastReceiver:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent.setClassName(context, MyService.class);
context.startService(intent);
}
}
Service:
public class MyService extends IntentService {
private static final String TAG = "MyService";
// default constructor is required for all application components
public MyService() {
super(TAG);
}
#Override
public void onHandleIntent() {
// do your work here
}
}

This is the approach I have taken:
Problem was delay in data. I created another table with most minimal set of columns from each source tables that are important for processing when BroadcastReceiver starts (or in turn starts a Service).
This new table is designed to keep the cartesian product of the join between all the tables I need, down to the granularity of the column which I am using to search (where clause). This table is recreated through a Service that manages a Thread. This thread processes all data and "digests" it so that its in the most easy form of processing by the app. It saves the digested data to the table. I didn't use IntentService because there's no way to stop a running worker thread.
All I'm doing now is to query the DB when Service starts and get the absolute row that I want from the SQLite DB and work on it. Since it is already simplified in terms of how app can easily start processing it, there's no other overhead on processing time. We just get down to the business as soon as I have the result.
This isn't still the most perfect way I imagined my final approach to be, but given the current speed of SQLite database access, it works fine.

Related

When to extend Service and run in background

I am bit confused what is the right place to use Service (for background task).
This is my scenario:
I have a class that extends Broadcast receiver. It receives WiFi state changes. Depending on the state change, I call another class. This is a pure Java class, not extending any class.
This class is instantiated by passing the Context (received with the broadcast receiver).
I need to pass the Context because, among other things, I access SharedPreferences, display a notification, etc. But this not a foreground activity.
Is this the correct way? Or should my class extend Service and work as a background task?
Is it wrong to pass the Context to initiate a class?
For example,
public class WifiStateBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
...
WifiChangeReceptionClass wifiChanged = new WifiChangeReceptionClass(context);
wifiChanged.showNotification();
...
}
What is wrong with this approach?
Try any of this:
public class WifiChangeReceptionClass{
public static void showNotification(Context context){
//showYourNotification
}
}
Or
Create an Application class that has a static method to get it's context, like so.
public class MyApplication extends Application {
...
public static MyApplication get(){
return this;
}
...
}
Then in your class, just call:
public class WifiChangeReceptionClass{
public static void showNotification(){
Context context = MyApplication.get();
//showYourNotification
}
}
Or
Just use dagger for your dependency injections.
Check docs here
It is wrong because context reference will be available as long as you are in onReceive() method. Once call back onReceive() method gets completed context will no longer be available.
It is absolutely fine as long as you are using the context within the lifecycle of broadcast receiver (you may pass it to any class). Since broadcast receiver and service, both run on UI thread, using service would not make much difference.
If you want to perform some network operation or long running operation, then you can instantiate a intent service from receiver.
Registering for broadcast receiver to get Wifi state changes might not from Android 7 its has disabled the CONNECTIVITY_CHANGED.
Apps targeting Android 7.0 (API level 24) and higher do not receive CONNECTIVITY_ACTION broadcasts if they declare the broadcast receiver in their manifest. Apps will still receive CONNECTIVITY_ACTION broadcasts if they register their BroadcastReceiver with Context.registerReceiver() and that context is still valid.
This includes connectivity change. The better option is to use JobScheduler. Refer this link
As mentioned in the response, onReceive() of BroadcastReceiver is executed on main thread. Based on android documentation for broadcast receiver
As a general rule, broadcast receivers are allowed to run for up to 10 seconds before they system will consider them non-responsive and ANR the app. Since these usually execute on the app's main thread, they are already bound by the ~5 second time limit of various operations that can happen there (not to mention just avoiding UI jank), so the receive limit is generally not of concern. However, once you use goAsync, though able to be off the main thread, the broadcast execution limit still applies, and that includes the time spent between calling this method and ultimately PendingResult.finish().
If your WifiChangeReceptionClass is doing some extensive work, then refrain from running directly in onRecevie(). Instead start Service (you have to spawn a new thread thread) or IntentService

Service-Activity Communication data processing while sleep

Project statement:
i have a simple counter app which has 6 things i am counting. on my wearable, i have a radiobutton group which selects which of those things i want to count. it then displays the current count for the item on the watch and then i can either add or subtract 1 from it from the watch. The watch is only an interface and interaction device. it does no processing. All processing of information and storing of information is done on the mobile. so the watch merely sends messages and displays information.
How it works:
the wear sends messages to the mobile via Wearable.MessageApi.sendMessage() and the phone responds with Wearable.DataApi.putDataItem(). The watch is sending multiple forms of informaiton like add/subtract/countRequest in addition to which item it is references. the mobile only responds with the item count requested and the watch only need change the display if it is a different value than what is showing.
This is a general messenger understanding question. I have
public class MyListenerService extends WearableListenerService{
#Override
public void onMessageReceived(MessageEvent me){
showToast();
}
}
The listener works. Now i want to do something useful with the listener because it is actually sending data i need. But i am having trouble communicating between Service and Activity because of my limited experience. I have read up on messaging and broadcast receivers. and am looking for ideas on how to implement to get my result or a better understanding.
From what i am gathering from trying to code, a service cannot directly interact with my interface, so i need to communicate with my activity in some way. 2 ways i have read is messaging(handlers) and broadcastreceivers.
each of these methods will do the function, however have their drawbacks which is where i am looking for better understanding or help.
for the Handler: even though i can create a static handler class and run code within the handler class, because it is static i cannot call non static objects which means if i try and do this it fails.
Service:
public class MyListenerService extends WearableListenerService{
#Override
public void onMessageReceived(MessageEvent me){
Activity.mHandler.sendEmptyMessage(MyConstants.COMMAND);
}
}
Activity:
public static Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
doThis(msg.what);
}
};
private void doThis(int command){
processCommand();
updateUserInterface();
}
Is there a way i can implement the above Handler, because when i process message if i just simply do a toast, it works, so i can receive the message. I just cant call a non-static object from a static. so i am assuming i cannot update an interface object either if i just threw the code of doThis() inside the Handler since i am just using it as a go between. When i was using LiveListeners and the onMessageReceived() was within my Activity, rather than a separate service, i just called doThis() directly and it worked great.
for the BroadcastReceiver:
There is a lot of code to show so instead i will just explain my issue for it and you may be able to answer from that. apparently you have to register/unregister on onResume()/onPause(). That would prevent me from being able to process information when the phone goes to sleep. the whole point of running a service is so i can do stuff when the phone is asleep or the activity is not in the foreground.
Before i was doing "LiveListeners" and it worked fine, so long as activity was in the foreground and phone was not sleeping. only way to have it work while sleeping is to engage a service to work in the background.
So my question is, what is best way to handle this situation so that i can process the information that the wearable is sending to the mobile while the mobile is asleep. or is there another method to send data i did not find?
If you extend WearableListenerService, you are creating a special Service which runs as part of your app's process. You can use this to communicate with another Service in your app which does all the processing, or use broadcasts (as you noted.) In either case, the Service is running in the context of your process and on the main thread - so if you need to do any heavy processing you'll need to offload it to a background thread.
Since your WearableListenerService is declared in the manifest and its lifecycle managed by Android Wear (by default), it's going to be simplest to either create a secondary Service or use a BroadcastReceiver to do your processing. Just note that "processing" must be lightweight if in a BR. If you use a BR, look into using LocalBroadcastManager as it is more efficient than sending the broadcast via the usual Context.sendBroadcast(). It's roughly the equivalent of sending a message to your app, it just happens to be in Intent form.
I certainly do not want to oversimplify greatly, but I like the easy way. Having intent I just awaken mobile or wearable from Sleep, and then the other threads also perforce awaken and process data.
#Override
protected void onHandleIntent(Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
String tmp = " ";
PowerManager.WakeLock wakeLock = null;
// wakeLock.acquire();
if (intent.getAction() != null) {
tmp=intent.getAction();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), TAG);
wakeLock.setReferenceCounted(true);
if(! wakeLock.isHeld()) {
wakeLock.acquire();
}
Code snippet from https://github.com/NickZt/E52/blob/master/wear/src/main/java/ua/zt/mezon/e52/core/MySpcIntentService.java

Android - starting IntentService frequently

In my application, a single instance of a class acts like a state machine. Many activities wants to receive updates on the state of this object. The state of this object itself is updated from data from a broadcast of some primitive information.
I have implemented it this way.
I registered a broadcast receiver in the manifest file which receives the primitive information and then starts an IntentService just passing the received information.
#Override
public void onReceive(Context context, Intent intent) {
Intent update_service = new Intent(context, StateMachineUpdateService.class);
update_service.putExtra(PRIMITIVE, intent.getDoubleExtra(PRIMITIVE, 0));
context.startService(update_service);
}
The StateMachineUpdateService keeps an instance and updates it:
#Override
protected void onHandleIntent(Intent intent) {
statemachine.update(intent.getDoubleExtra(PRIMITIVE, 0));
Intent broadcast = new Intent(STATE_MACHINE_UPDATE);
broadcast.putExtra(STATE_MACHINE_STATE, statemachine.get_state());
this.sendBroadcast(broadcast);
}
}
I am wondering if there is an more elegant way to achieve this. I am wondering if starting an IntentService (which in turn will start a separate thread) is something I should try to avoid. The primitive broadcast is sent about 10 times in a second.
Side-question:
let us say statemachine.update takes so much time that the next broadcast has arrived, I would like to ignore those broadcasts. What is the best way to do this?
If you have a singleton object that requires serialized access to its members, one way to go is to use a HandlerThread and schedule incoming work on it from your receiver or wherever else work may originate. The HandlerThread will process everything (runnable or message) in the order it was received (just like the Android main thread).
If you want to skip incoming items of work, you can record the receive time of the work and compare it to the actual time it's being executed, and skip it if the some threshold has been exceeded.
Starting IntentService takes 1-15 ms on my 1 GHz phone. As it is created on UI Thread 10 calls can take even 100 ms which is too much (user will experience lag). You should consider using Hanlder with WorkerThread. You can check how IntentService use this solution and implement it in your case.

Uploading Image and displaying outcome on UI: AsyncTask or Service?

My Android application has to:
upload an image to the server
make 3 ( quick ) calls to a REST web service using the uploaded image image
get output from webservice
display output on ui.
I'm confused about whether I should use a Service or AsyncTask.
I think I should use an AsyncTask because the tasks need to be done in the background and the outcome needs to be displayed on the UI once the process is complete. The doInBackground() and postExecute() methods seem perfect for this sort of thing.
However, I've read from the Android Documentation and several StackOverflow answers that using Services is more appropriate. The problem is that I want to display the output on the UI as soon as the task is complete. If the user quits the app, then I want the upload to stop.
I'm confused: Is AsyncTask really the better choice?
You should create an IntentService. Send an intent to the service to start it. Send back an intent with the result using a LocalBroadcastManager (from the support library). The IntentService stops itself when it completes, unlike regular Services.
If the user rotates the device while the AsyncTask is executing the result will be lost since the AsyncTask thread is associated with the activity that was destroyed by the rotation. You can find an example here on StackOverflow of how to circumvent this problem, but it's much more code and more complex than writing an IntentService. Since the IntentService is on its own thread, it doesn't get lost when the activity is destroyed.
public class MyIntentService extends IntentService {
public static final String SERVICE_NAME ="whatever";
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
//Get input from the intent, do your http stuff here,
// create a new intent to send back
LocalBroadcastManager.getInstance(this).sendBroadcast(intentToSendBack);
}
}
Check out the IntentService docs: Intent Service is about 1/3 down the page
Use a LocalBroadcastManager in your activity to listen for the returning intents. You just hook it up in the OnResume event handler and unhook it in the OnPause handler. So after your original activity is destroyed on the rotation, the new one will start listening. The magic of LocalBroadcastManager queues up the intent for that small period of time between the destruction of the first activity and the creation of the second.
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(MyIntentService.SERVICE_NAME);
LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, filter);
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
}
private BroadcastReceiver onNotice = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Do your UI stuff here....
}
}
There is more detail on LocalBroadcastManager in the docs. There are some other good side effects of LocalBroadcastManager. Intents sent this way do not leave the application scope, so other apps can't snoop on data you pass around, and your activity processes the result without being forced into the foreground.
Don't forget to register the service in your AndroidManifest.xml.
IF you are doing network related stuff in your app you need to use an AsyncTask no matter what you do because you will get a NetowrkOnMainThreadException. you are not allowed to do anything network related on the UI thread. Since a service runs on the UI thread you will still need an AsyncTask in the service.
So if it were me I would not worry about the service if you need to update the UI when its done

Android : Do Application Login in background on boot-up

I have a VOIP Application, I need to login the application in background on device bootup.
Currently the init to my application is done on UI Active(onCreate()).
I have the following things in my mind, can anyone help and clear my doubts.
The service design is must to achieve this task??
Which Service Remote(AIDL) or Local Service and why?
How does the UI and Service interaction happens?
After UI is active who gets the Call- Backs? UI or Service?
Should i make Service as my Controller i.e Service to UI data Pass Vice-versa?
Sample App: Skype.
So there are many ways to achieve what you want, it is a matter of what fits your style and design better. Hopefully you will find this information useful.
For the application to login in the background on startup there are a few option. The first thing you will need is a BroadcastReceiver which is defined as a receiver in the manifest. Have the BroadcastReceiver catch the ACTION_BOOT_COMPLETED intent. From here you can launch your Service. This leads to #2.
If all you are doing are RESTful calls then really an IntentService would be ideal. The difference between an IntentService and a Service is simple: An IntentService runs off of the main thread, executes it's 'code' and dies. A Service, however runs on the main thread (this is an important fact) and is long running so it has to be told to stopSelf(). To take matters further, a Service is also less likely to be killed compared to an Activity (application components are killed to make room in memory for newly launched apps), ie. it takes higher precedence. The service can also be declared a foreground service which requires a notification but give even higher precedence. I think in your case a Service would be perfect.
Once your UI (Activity) is opened the best way to connect to the Service would be the Binder. This will allow multiple interfaces to the Service from different applications / components if need be. AIDL is pretty cool stuff but from my experience much harder to manage since all parameters must be primitive or Parcables. AIDL is also slower an less efficient because it is really a form of IPC. When a Service is started with an intent the onStartCommand() method is called. If the service is started by an application trying to bind to it then the onBind() method is called. But you can start the Service with and Intent and then bind to it. If you prefer the RESTful approach where you just have quick calls for data you can use an IntentService with a ResultReceiver. This is a great article written about Google I/O examples and just overall well implemented if you are interested in the IntentService and ResultReceiver.
This is up to you. Using the Binder or AIDL your Activity can call the Service methods just like object method where the 'callback' would just be the method return. If you use a ResultReceiver the Activity interfacing the Receiver would be the callback. You could also just pass Intents back and forth but this could get messy. Again for your case the Binder approach would be good as well as a Receiver.
Think of the Service as a model in the MVVM system - use it as a helper to get data from, not as something that controls the logic of the application.
Sorry if this seems messy there are so many ways to achieve what you are looking for. Its just a matter of what fits your situation best what you 'feel' is better. Not to mention the Android SDK is pretty large. I tried to hit on all the topics that could help you out. Good luck!
Try a service with a boot reciever. Here is an example I found after a quick google search. Then make sure to store in the login info somewhere for when the app starts. Not sure what callbacks you might have, so really hard to answer that part. I would say that if the callbacks should affect the UI then let the activity take them over when it starts up. If you need a UI when only the service is running, probably best to throw up a notification and have it call the appropriate activity with the callback data.
you can authanticate user login by background services
package com.javaorigin.android.sample.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class MyService extends Service {
String tag="TestService";
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
Log.i(tag, "Service created...");
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.i(tag, "Service started...");
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed...", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
public class SampleAction extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView view = new TextView(this);
view.setText("Service Test");
Intent i = new Intent();
i.setClassName( "com.javaorigin.android.sample.service",
"com.javaorigin.android.sample.service.MyService" );
bindService( i, null, Context.BIND_AUTO_CREATE);
this.startService(i);
setContentView(view);
}
}
If you login is takes so long use [AccountManager][1] and do it only once.
The idea behind the AccountManager a token or whatever credentials you need to use in your Service.
In your particular case I think the best way of communicating your Activity with the Service is binding to it.
Best source of knowledge about basic Service usage is SDK. Long story short AIDL is used for IPC communications and as long as you run the service in the same process you don't need it. I suppose you have two options:
If the only thing you need is just login, you can start a service on boot up, login and then i.e. send a sticky broadcast with bundled login data which will be then received in application. See this question for a good set of ways to start a service on boot up.
#Override
public void onCreate() {
Data data = performLogin();
Intent i = new Intent(ACTION_VOIP_LOGIN);
i.putExtra(EXTRA_LOGIN_DATA, data);
mContext.sendStickyBroadcast(i);
}
...
private final class LoginReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// You may use a Bundle instead
Data data = intent.getParcelableExtra();
processLoginData(data)
}
}
protected void onCreate(Bundle savedInstanceState) {
...
IntentFilter filter = new IntentFilter(ACTION_VOIP_LOGIN);
mContext.registerReceiver(new LoginReceiver(), filter);
}
In second case you might want to move all your logic to the service. Here you'll extend the Binder class. See this SDK article for details.

Categories

Resources