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() );
Related
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.
Can anybody tell me a way to create an in-application BroadcastReceiver? I have created BroadcastReceiver which Toasts a message. It works even when the application is in background state, I want it to work only when application is in foreground.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.registerReceiver(this.mConnReceiver, new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
}
private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
String reason = intent
.getStringExtra(ConnectivityManager.EXTRA_REASON);
boolean isFailover = intent.getBooleanExtra(
ConnectivityManager.EXTRA_IS_FAILOVER, false);
NetworkInfo currentNetworkInfo = (NetworkInfo) intent
.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
NetworkInfo otherNetworkInfo = (NetworkInfo) intent
.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
if (currentNetworkInfo.isConnected()) {
System.out.println("Connected");
Toast.makeText(getApplicationContext(), "Connected",
Toast.LENGTH_LONG).show();
} else {
System.out.println("Not Connected");
Toast.makeText(getApplicationContext(), "Not Connected",
Toast.LENGTH_LONG).show();
}
}
};
}
So here is my code which is checking network state and generating a BroadcastReceiver. I haven't added anything in manifest.
There are a number of ways to do this. The first 2 I can think of are like this:
If your <receiver> is declared in the manifest with an <intent-filter>, you can enable it and disable it from your application so that it is only enabled when the app is in the foreground. To do this, initially set the receiver disabled by adding android:enabled="false" to the manifest entry for <receiver>.
Now, when your app is running, in onResume() you want to enable the receiver. Use PackageManager.setComponentEnabledSetting() to do this. When your activity goes to the background, in onPause() you can disable the receiver again.
Dynamically register and unregister the receiver. For this you don't need to declare the receiver in the manifest. In your application, create an instance of your BroadcastReceiver and in onResume() call registerReceiver() with the appropriate intent filter. When the app goes to the background, in onPause() call unregisterReceiver() to remove it. The receiver will only receive calls to onReceive() while the app is in the foreground.
see Context.registerReceiver() and Context.unregisterReceiver()
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 ;)
I'm trying to implement a Broadcast Receiver who should receive Intent from a Service which is running in the background, however it is not working.
In my main Activity I just bind the service and start it via onClick on a Button.
In my SpeechRecognizer Service class I create a new BroadcastReceiver (see code below).
public void onCreate() {
Log.d(TAG, "onCreate");
if (SpeechRecognizer.isRecognitionAvailable(this)){ //check if a SpeechRecognizer is available
this.sr = SpeechRecognizer.createSpeechRecognizer(this);
this.sr.setRecognitionListener(new listener());
commandsReceiver = new CommandsReceiver();
ConnectivityManager cm =(ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
testfilter = new IntentFilter();
registerReceiver(commandsReceiver,testfilter);
} else {
Toast.makeText(this,"Please install a SpeechRecognizer on your system.", Toast.LENGTH_LONG).show(); //alert if speech-recognizer is not installed on the device
Log.d(TAG, "no SpeechRecognizer available");
this.onDestroy();
}
}
In my onResult I do it like this:
Intent intent = new Intent();
intent.setAction(CommandsReceiver.TEST);
sendBroadcast(intent);
In my CommandsReceiver I just got a simple String and a Log message:
public class CommandsReceiver extends BroadcastReceiver {
public static final String TEST = "de.speech.TEST_INTENT";
#Override
public void onReceive(Context context, Intent intent) {
Log.d("BroadCastReceiver", "Intent received"+intent);
}
}
However I'm not getting the Log.d() message.
I hope you can help me out.
Seems you are creating an IntentFilter without any Action as
testfilter = new IntentFilter();
instead of,
testfilter = new IntentFilter(CommandsReceiver.TEST);
so, register your BroadCast using,
testfilter = new IntentFilter(CommandsReceiver.TEST);
registerReceiver(commandsReceiver,testfilter);
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);
}
}
}