Pause IntentService based on connectivity (Queue Intents) - android

After consulting Stackoverflow a lot I found this solution:
https://stackoverflow.com/a/11401196/2440358
Now I'm already using an IntentService which is handling the communication with the server and I've implemented a BroadcastReceiver which is looking for the current connectivity state.
IntentService:
public class CommunicationService extends IntentService {
public CommunicationService() {
super(CommunicationService.class.getName());
}
#Override
protected void onHandleIntent(Intent intent) {
String kind = intent.getExtras().getString("kind");
if ("LocationUpdate".equals(kind)) {
// send current Location to the server
}
}
BroadcastReceiver:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
checkConnectionState(context);
}
public static boolean checkConnectionState(final Context context) {
final ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager
.getActiveNetworkInfo();
Intent intent = new Intent(context, CommunicationService.class);
intent.putExtra("kind", "");
if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
// start service
context.startService(intent);
return true;
} else {
// stop service
context.stopService(intent);
return false;
}
}
}
That's all working like a charm, but I don't know how to bring those two together like mentioned in the link above. I really would like to use that mentioned automatic queueing of the IntentService without.
Is there an easy way to make use of the IntentServices queueing and make it queue everything until the connectivity comes back?
Thanks in advance for your help :)
Edit: Now I solved it in a kinda dirty hack. The Application itself has a queue now, where the intents are added to in case they go wrong (internet connection loss during execution) or when there is no internet connection at all. The intents from that queue will be started again in the broadcastreceivers onReceive() when internet connection is available. I hope it helps someone ;)

Related

BroadcastReceiver Not Working When App is removed from recent app list

I have a Class "ConnectivityChangeReceiver" Class which extends BroadCastReceiver:
public class ConnectivityChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intentPostTelemetry = new Intent(context.getApplicationContext(), PostTelemetryData.class);
intentPostTelemetry.putExtra("isNetworkConnected", isConnected(context));
context.startService(intentPostTelemetry);
}
public boolean isConnected(Context context) {
ConnectivityManager connectivityManager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE));
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
return networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected();
}
}
This ConnectivityChangeReceiver class calls PostTemetryData
public class PostTelemetryData extends IntentService {
public PostTelemetryData() {
super("PostTelemetryData");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
boolean isNetworkConnected = extras.getBoolean("isNetworkConnected");
if (isNetworkConnected == true) {
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("TelemetryInfo", 0);
String telemetryDetailsInfo = sharedPreferences.getString("TelemetryDetailsInfo", null);
if (telemetryDetailsInfo != null && !telemetryDetailsInfo.isEmpty()) {
saveTelemetryData(telemetryDetailsInfo);
}
}
// your code
}}
And in manifest i add following codes:
<receiver android:name=".ConnectivityChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".PostTelemetryData"/>
This Broad Cast Receiver starts when connectivity changed.
Everything is working fine when the app is running.But When the app is closed and removed from the recent app list Then The Broadcast Receiver is not working So i can not save Data. So please help me out from this situation.
Thanks in advance.
The problem could be that your device is going to sleep after onReceive() is done, hence your IntentService is not getting to do its thing.
Try using this - https://github.com/commonsguy/cwac-wakeful
More simply, we acquire WakeLock in the onReceive() method of BroadcastReceiver, then start the service and release the wakelock in the onHandleIntent() method of IntentService.
Let me know if this works.
You really cannot do what you are trying to do. There is no way to keep your application running forever, and you can only catch ACTION_BATTERY_* where your app is running.

Broadcastreceiver components are not allowed to bind to services in android

Here is what I am doing:
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
ConnectivityManager conn = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = conn.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null
&& activeNetwork.isConnectedOrConnecting();
if (isConnected == true) {
// initChatHub();
Intent serviceIntent = new Intent(context, ChatService.class);
Toast.makeText(context, "Connected", 1000).show();
serviceIntent.putExtras(intent);
context.startService(serviceIntent);
context.bindService(serviceIntent, mServiceConnection,
Context.BIND_AUTO_CREATE);
} else {
Toast.makeText(context, "Disconnected", 1000).show();
}
}
when network state change then application becomes crash when i data-connection off then there is no Error coming when data connection On then app becomes crash and this Exception coming please suggest me how to fix it.
See here Context.bindService :
Note: this method can not be called from a BroadcastReceiver
component....
So, use BroadcastReceiver.peekService which return IBinder from running Service:
Intent serviceIntent = new Intent(context, ChatService.class);
context.startService(serviceIntent);
if (isConnected == true) {
IBinder binder = peekService(context, new Intent(context, ChatService.class));
Toast.makeText(context, "Connected", 1000).show();
if (binder != null){
mChatService = ((LocalBinder) binder).getService();
//.... other code here
}
}
The reason Android return this exception is Receiver lifecycle. It may be very short. If receiver binds service, receiver may not exist until result return. see here Receiver lifecycle.
The solution is starting another middle service. Let middle service to bind target service. This middle service can be existed until result return. And receiver can be killed in anytime.
There is another hack solution to skip Android NotAllowException. This exception check Context. If this Context comes from Receiver, then Android return Exception. Change your code
context.bindService(serviceIntent, mServiceConnection,
Context.BIND_AUTO_CREATE);
to
context.getApplicationContext.bindService(serviceIntent, mServiceConnection,
Context.BIND_AUTO_CREATE);
This hack solution won't keep receiver's life. If you think the result from binding service is not important. You can use this hack solution to skip NotAllowException.
You cannot call bindService from BroadcastReceiver. The alternate is :
Create an Application class (by extending Application class)
Create a function for starting and binding of service into you Application class
In broadcast receiver get instance of your application class and call function for starting service.
Sample Code:
public class MyApplication extends Application{
public void startService(){
Intent serviceIntent = new Intent(context, ChatService.class);
Toast.makeText(context, "Connected", 1000).show();
serviceIntent.putExtras(intent);
context.startService(serviceIntent);
context.bindService(serviceIntent, mServiceConnection,
Context.BIND_AUTO_CREATE);
}
}
// inside onReceive function
public void onReceive(Context context, Intent intent) {
ConnectivityManager conn = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = conn.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null
&& activeNetwork.isConnectedOrConnecting();
if (isConnected == true) {
MyApplication app=(MyApplication)context.getApplicationContext();
app.initChatService();
} else {
Toast.makeText(context, "Disconnected", 1000).show();
}
}
Service.bindService() can not be called from a BroadcastReceiver component. I use Application Context,it is OK
I met same problem, when I was trying to access MQTT client from BroadcastReceiver like this:
public class BroadcastHelper extends BroadcastReceiver implements MqttCallbackExtended {
#Override
public void onReceive(Context context, Intent intent) {
MqttAndroidClient CLIENT;
mqtt_helper = new MQTThelper( context ); <--- problem was here
CLIENT = mqtt_helper.getMqttCLIENT();
CLIENT.setCallback( this );
mqtt_helper.MqttConnect();
}
//... all other functions omitted
}
Then I received NotAllowException and Broadcastreceiver components are not allowed to bind to services error.
So to solve this I had to pass context to the class where MQTT CLIENT is created and handled like this context.getApplicationContext() instead of context only.
full line:
mqtt_helper = new MQTThelper( context.getApplicationContext() );

Start service when internet is active in android

How to start a service when internet is enabled?
I need to start the service when the internet is active state. I have application that communicate with the web application when internet is present,even offline the mobile need a communication,it will known by server at the time of internet comes active.
The answer is in your question. Just create a BroadcastReceiver to listen network state, when internet is okay, start server as usual.
public class NetworkBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager mgr = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = mgr.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isConnected()){
isNetworkConnected = true;
//do your work here
}
}
}}

Android: Stop/Start service depending on WiFi state?

In the android application that I'm designing, my service only needs to be running when the device is connected to the router (via WiFi obviously).
I'm really new to android, and what I've got so far has taken me forever to Achieve, so I'm really hoping for some pointers.
My service is set to start up when the phone starts up. Also when the Activity is launched it checks whether the service is running - and if not it starts it.
I'm just wondering what code I can put into my service to make it turn off if the WiFi state is lost - and what code I need to make the service start once a WiFi connection becomes active?
Thanks! :)
You can create a BroadcastReceiver that handles wifi connection changes.
To be more precise, you will want to create a class - say NetWatcher:
public class NetWatcher extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//here, check that the network connection is available. If yes, start your service. If not, stop your service.
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null) {
if (info.isConnected()) {
//start service
Intent intent = new Intent(context, MyService.class);
context.startService(intent);
}
else {
//stop service
Intent intent = new Intent(context, MyService.class);
context.stopService(intent);
}
}
}
}
(changing MyService to the name of your service).
Also, in your AndroidManifest, you need to add the following lines:
<receiver android:name="com.example.android.NetWatcher">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
(changing com.example.android to the name of your package).
As #Phil stated, you should extend BroadcastReceiver, and in onReceive method start or stop the service. Something like:
class ConnectionChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
//start service
} else {
//stop service
}
}
}
You can make this a private class of your activity, and register receiver on activity create, and unregister it on activity destroy.
More useful information is provided here: Determining and Monitoring the Connectivity Status
To start/stop your service when supplicant Wifi state is ok/nok:
register a BroadcastReceiver to recieve WIFI state change broadcasted intents
inside your BroadCastReceiver check the intent validity then start your service
So register your broadcast receiver to receive WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.
Add permission android.permission.CHANGE_WIFI_STATE or android.permission.ACCESS_NETWORK_STATE. I'm not sure if it is necessary or not.
Then a sample broadcast receiver code could be:
public class MyWifiStatereceiver extends BroadcastReceiver {
//Other stuff here
#Override
public void onReceive(Context context, Intent intent) {
Intent srvIntent = new Intent();
srvIntent.setClass(MyService.class);
boolean bWifiStateOk = false;
if (WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION.equals(intent.getAction()) {
//check intents and service to know if all is ok then set bWifiStateOk accordingly
bWifiStateOk = ...
} else {
return ; // do nothing ... we're not in good intent context doh !
}
if (bWifiStateOk) {
context.startService(srvIntent);
} else {
context.stopService(srvIntent);
}
}
}

android communicate between activity and broadcast receiver

I have an activity which displays some data fetched from the server. If no connection is available, activity displays some cached data; if connection is available, activity fetches data and displays it. It all works as expected.
Now, I would like to make my activity reload the data as soon as the connection occurs. I am using a simple Receiver that extends the BroadcastReceiver:
public class ConnectionChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null) {
//what to do here?
}
}
}
Broadcast receiver is declared in my manifest file as follows:
<receiver android:name=".ConnectionChangeReceiver"
android:label="NetworkConnection">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
In my activity, I register the receiver:
ConnectionChangeReceiver receiver = new ConnectionChangeReceiver();
this.registerReceiver(receiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
Now, I am confused as what to do next. When onReceive method is executed, how to make my activity aware of that? I know I could start a new activity, but that's not really what I want. Should I declare ConnectionChangeReceiver as a private class of my activity? Or is there any other solution?
I think building the receiver as a private subclass of your activity is the way to go here. This way you can control events and data from your activity. Then you can just create one instance of it and register the receiver from code as you did above.
Note that you don't have to register your receiver in both the manifest and code. One of these is enugh - the manifest is basically a "static" registration while doing it in code allows dynamic registration at runtime. Also when you register in the manifest, a new instance of your receiver will automatically be created from the system, executed and terminated. Doing the reg in code allows to point to one specific instance.
Interface Approach!
You can communicate via an interface as well. This approach works even
if your BroadcastReceiver is in a seperate file. You will not even
have to access UI elements of Activity in the Broadcast.
Its pretty Straightforward. Just follow these 3 simple steps.
1) Create an interface
public interface MyListerner{
public void performSomething(String arg);
}
2) Initialize the Listener in ConnectionChangeReceiver
public class ConnectionChangeReceiver extends BroadcastReceiver {
private MyListerner listener;
#Override
public void onReceive(Context context, Intent intent) {
listener = (MyListerner )context; // initialse
ConnectivityManager connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null) {
listener.performSomething("Some data"); // Call listener method
}
}
}
3) Implement the interface and Override the method in your Activity
public class YourActivity implements MyListerner{
// Activity relate stuff onCreate() etc
public void updateUI(String result){
// Your code to update UI
}
#Override
public void performSomething(String arg){
updateUI(arg);
}
}
Relevant Links:
You can read in detail Why using an interface is a preferred approach in this case

Categories

Resources