I am building an app which requires a connection to an MQTT server. Everything works fine, but I want to make it fail proof. More specifically, I need that when the service is unable to connect to the MQTT server, the application closes as it can't do anything. I tried to broadcast an intent to the activity, but the broadcast doesn't reach it after catching the exception. (I ommited some code for easier understanding)
Service's onHandleIntent()
try{
mqttClient.connect();
} catch (MqttException e) {
Intent msgint = new Intent();
msgint.setAction(constantStrings.SH_CONN_ERROR);
sendBroadcast(msgint);
Log.d("MqttLog","ERROR-MqttException " + e.getMessage());
}
The Activity I need to finish (SelectionGrid.class)
#Override
protected void onCreate(Bundle savedInstanceState) {
[...]
IntentFilter filter = new IntentFilter();
filter.addAction(constantStrings.SH_CONNERROR);
registerReceiver(SH_Communication, filter);
}
BroadcastReceiver SH_Communication = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(constantStrings.SH_CONN_ERROR)){
new AlertDialog.Builder(getApplicationContext())
.setTitle("Error")
.setMessage("No conection")
.setCancelable(false)
.setPositiveButton("Close app", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
SelectionGrid.this.finish();
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
}
};
I do get the Log entry when catching the exception, but the broadcast never gets to the activity.
Is there any better way to do this?
I was able to solve it. It turned out that I was calling the wrong activity which looks a lot like the one I really needed. The code that I showed in the question is correct.
Related
I can’t catch up - how to send Toast from Executors.newSingleThreadExecutor () in the run () method? In the debug I set a breakpoint, everything is fine, we go into the method, but the message does not appear in the emulator? And yet, in the same method, I send the intent to the receiver, the intent is sent, but the receiver does not receive it.
ExecutorService service:
public void start() {
service = Executors.newSingleThreadExecutor();
service.submit(new Runnable() {
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent intent = new Intent(ACTION_FOR_FRAGMENT);
sendBroadcast(intent);
service.shutdown();
}
});
}
I solved this problem, you can close the question. The essence of the problem was that I did not correctly implement the service methods.
I created a Broadcast Receiver (BR) in a service that will react to incoming SMS with specific number and body. I only need it to receive for a few seconds/minutes after user action, that's why I didn't registered it in manifest or activity (user may close it). BR has two parts, automatic (which works fine) and manual which should launch MainActivity and start a Dialog. I know that Dialog can't be started from BR and thats why I created a Listener, but my problem is that it is always null after service starts. It has value in onCreate of my MainActivity, but when service starts it changes to null, and I understand why (serivce re-initalize the Listener listener). I even tryed to put initialised listener value to SharedPrefs and restore it after, but when I try to store it with json it only stores null again. So how do I make my listener != null??? These are the relevant parts of my code:
MainActivity
onCreate {
SMSService smsReceiver = new SMSService();
smsReceiver.setListener(new SMSService.Listener() { //here listener from service is != null
#Override
public void onTextReceived(String s) {
dialogS(s); // totaly different dialog
}
});
...
mDialogBuilder = new AlertDialog.Builder(this);
...
.setPositiveButton(new OnClick...
Intent servisIntent = new Intent(MainActivity.this, SMSService.class);
startService(servisIntent);
...
}
SMSService
private Listener listener; // and here it get null which is the problem
public int onStartCommand(Intent intent, int flags, int startId) {
...
SMSReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MainActivity.class);
context.startActivity(i);
if (listener != null) {
listener.onTextReceived("4333");
}
}
void setListener(Listener listener) {
this.listener = listener; }
interface Listener {
void onTextReceived(String text);
}
Btw I also tried to put smsReceiver.setListener block of code in my Dialog .setPossitive onClickListener after calling startService hoping it would initiate after service but nothing
Installing a listener mechanism with setter method in service is bad practice. You can use ResultReceiver to receive callback results from service. It is Parcelable, so it can be passed in an intent before service started
I have an alarm application.
Flow looks like this :
WakefulBroadcastReceiver(Acquires wakelock) --->> Intent service -->> startActivity
public class AlarmService extends IntentService {
protected void onHandleIntent(Intent intent) {
Intent activityIntent = new Intent(this, TriggeredActivity.class);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(activityIntent);
Basically WakefulBroadcaseReceiver starts an intent service using startWakefulService(). Inside intent service's onHandleIntent(), only work I am doing is further starting a new activity using startActivity(). That new activity is where I am using mediaPlayer in a loop, which sounds the alarm. That activity has a dismiss button, which waits for user click to stop the media player & activity finishes.
Now the problem I am facing is that after calling startactivity() inside intent service, I can not wait for TriggeredActivity to finish(no equivalent to startActivityForResult in Service) and then complete wakeful intent. Related link
startActivity(activityIntent);
WakefulBCastReceiver.completeWakefulIntent(intent); /* can't do here */
So I am not explicitly releasing wakelock here.
My question is will the wakelock be released automatically(link-to-death), when the process that is holding it is killed.
If yes, then in my particular scenario, I need not call WakefulBCastReceiver.completeWakefulIntent().
Yes, you need to use completeWakefulIntent.
You need to put your TriggeredActivity intent into EXTRAs.
#Override
public void onReceive(Context context, Intent intent) {
Intent intentService = new Intent(context, NotificationsIntentService.class);
// Inserting data inside the Intent
intentService.putExtra(NotificationsIntentService.EXTRA_NOTIF, new Intent(context, TriggeredActivity.class));
startWakefulService(context, intentService);
}
NotificationsIntentService.class
public class NotificationsIntentService extends IntentService {
private static final String TAG = "DebugNotifIntent";
public static final String EXTRA_NOTIF = "extra_notif";
public NotificationsIntentService(){
super(NotificationsIntentService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: ");
Intent extraIntent = intent.getParcelableExtra(EXTRA_NOTIF);
extraIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(extraIntent);
NotificationWakefulBroadcastReceiver.completeWakefulIntent(intent);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
}
I have managed to find a solution for my problem. I am now using a Messenger for message based cross process communication between intent service & triggered activity.
I am passing a handler - alarmServiceHandler, from intent service to activity through a messenger.
Handler alarmServiceHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
if(msg.arg1 == 1) {
completedTriggeredActivity = true;
}
}
};
Inside onHandleIntent(), I am passing handler through Messenger object in intent's extra data.
Messenger alarmServiceMessenger = new Messenger(alarmServiceHandler);
Intent activityIntent = new Intent(this, TriggeredActivity.class);
activityIntent.putExtra("AlarmServiceMessenger", alarmServiceMessenger);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(activityIntent);
while(!completedTriggeredActivity){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
WakefulBCastReceiver.completeWakefulIntent(intent);
In TriggeredActivity, I am retrieving messenger in Dismiss button's OnClickListener, just before calling finish() on the activity. And sending back a message to AlarmService with arg = 1, implying end of processing in triggered activity.
buttonDismiss.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Messenger alarmServiceMessenger = getIntent().getParcelableExtra("AlarmServiceMessenger");
Message alarmServiceMessage = Message.obtain();
alarmServiceMessage.arg1 = 1;
try {
alarmServiceMessenger.send(alarmServiceMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
finish();
}
After starting triggered activity, I am putting AlarmService in sleep mode till boolean variable completedTriggeredActivity has not been set to true in handleMessage(). Once true, it means triggered activity has finished & now I can proceed with releasing wake lock.
I would be glad to receive comments about my approach & any suggestions towards a better solution to my problem, than the one I have deviced.
In my App, there is a condition which check every day and if it gets true then I want my App get close in between the run like a crash and stack also gets clear .
I have try and tested many solutions but didn't find the one that works the way i wanted .
My BroadcastReceiver:
public void onReceive(Context context, Intent intent) {
PreferenceForApp prefs = new PreferenceForApp(context);
Bundle bundle = intent.getExtras();
if (bundle!=null){
if(bundle.containsKey("exception")) {
// String e = bundle.getString("exception")
if(bundle.get("exception").toString().equalsIgnoreCase("http request failed with error_msg No Match Found")) {
prefs.setIsDeviceValidated(false);
prefs.setIsLogIn(false);
Log.i("Time", "Exception Occur");
Intent CSPIntent=new Intent(context,CSPLoginActivity.class);
CSPIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
CSPIntent.putExtra("close_activity", true);
Log.i("Time", "IntentExit");
context.startActivity(CSPIntent);
}
}
}
}
}
And code to finish in an Activity I am calling from broadcastReceiver:
if (getIntent().getBooleanExtra("close_activity",false)) {
Log.i("Time", "ExitCSPLogin");
this.finish();
}
This code is not closing App in between the run.
You need to register BroadcastReceiver in your activity and send broadcast to BroadcastReceiver when you want to close application.
In your Activity try this:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.package.ACTION_CLOSE");;
BroadcastReceiver Receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
registerReceiver(Receiver, intentFilter);
in onDestroy() method of you Activity unregister BroadcastReceiver:
#Override
protected void onDestroy() {
unregisterReceiver(Receiver);
super.onDestroy();
}
Now when you want close application send broadcast to BroadcastReceiver:
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.package.ACTION_CLOSE");
sendBroadcast(broadcastIntent);
Hope this helps!
you have to check below condition in your app's mainActivity's onCreate method every time when user enter in your app. or in onResume if you want to to close your app immediately
if (!prefs.getIsDeviceValidated()) {
Log.i("Time", "ExitCSPLogin");
this.finish();
}
i assume you have more then one activity in your app, so insted of check above flag in every activity we 'll put it in main activity. allow user to use your app until he/she come at mainActivity
Note: create Broadcast Receiver for your App(add in manifest), not for specific activity
I have an app in which I'm trying to detect WHEN the Internet connection appears and when it disappears.
At the moment, when it appears, I'm starting a new thread (different from the UI) which connects my app to a remote server.
For that I'm hardly trying to implement a broadcast receiver which LISTENS for connectivity, but I'm having problems in understanding the concept.
In my onCreate() I have somethig like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
cThread.start();
}
When there is connection to the Internet I'm sending data through the socket, when there is not I'm storing the data in a database. And when the Internet appears I'm restarting my thread to reconnect and send the old data (which hasn't been sent because of network crashing) and the new one.
Let's say I would implement something like this:
DoRefreshBroadcastReceiver refreshBroadcastReceiver;
...
onResume() {
// register the refreshing complete broadcast receiver
IntentFilter intentFilter = new IntentFilter(DO_REFRESH);
refreshBroadcastReceiver = new doRefreshBroadcastReceiver();
registerReceiver(refreshBroadcastReceiver, intentFilter);
}
public class DoRefreshBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// call method to run fetch code...
}
}
Does this mean that when the Internet connection is detected my onReceive() gets called? And I could start my thread there?
What is the concept of using an intent? Because I really don't get it. How to use it, and what its purpose?
THE IDEA: I don't really know how to use this intent in this case or how to use it in my app!
Would this thing detect the connection to the Internet even when I'm not in this activity?
EDIT:
Here is how my onReceive looks like:
onCreate()
{
cThread = new Thread(new ClientThread(syncToken));
// cThread.start();
connIntentFilter = new IntentFilter(
"android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
public void onReceive(Context context, Intent intent)
{
mNetworkInfo = (NetworkInfo) intent
.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if (mNetworkInfo != null && mNetworkInfo.isConnected())
{
/*
* if(mNetworkInfo.getType()==ConnectivityManager.TYPE_WIFI);
*
*
* else
*/
cThread.start();
}
else {
System.out.println("There is no internet connection!");
try {
cThread.stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
mNetworkInfo != null && mNetworkInfo.isConnected()
Does this mean it's connected or should I verify for a certain type of connection on the emulator?
*I think that I should start my thread directly in onReceive(). As soon as my app starts it detects the Internet connection and BroadcastReceiver gets fired, doesn't it?
Try something like this...
public class MyActivity extends Activity {
private MyConnectivityListener connListener = null;
private IntentFiler connIntentFilter = null;
private Boolean connIntentFilterIsRegistered = false;
#Override
protected void onCreate(...) {
...
connIntentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
connListener = new MyConnectivityListener();
}
#Override
protected void onResume() {
...
if (!connIntentFilterIsRegistered) {
registerReceiver(connListener, connIntentFilter);
connIntentFilterIsRegistered = true;
}
}
#Override
protected void onPause() {
...
if (connIntentFilterIsRegistered) {
unregisterReceiver(connListener);
connIntentFilterIsRegistered = false;
}
}
protected class MyConnectivityListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// The NetworkInfo for the affected network is sent
// as an extra; it should be consulted to see what
// kind of connectivity event occurred.
}
}
}
A BroadcastReceiver is effectively a 'listener' which listens for events either sent by the system or, in some cases, by your own application components.
In this case, the system broadcasts android.net.conn.CONNECTIVITY_CHANGE whenever there is a connection change (connected/disconnected). By registering your BroadcastReceiver to 'listen' for that event, you can get the extra included in the Intent from your BroadcastReceiver's onReceive(...) method and do whatever you need to do accordingly. The extra is a `NetworkInfo object which will contain information about the particular network and whether it is connected or not.