Activity seems to finish directly on 2nd resume - android

Let's pretend I have the activities MyActivityA and MyActivityB.
MyActivityA starts MyActivityB
MyActivityB starts an repeating AlarmManager who triggers an IntentService which is informing MyActivityB with a ResultReceiver when something happens.
something happened, MyActivityB opens an AlertDialog, the PositiveButton leads to MyActivityA
(IntentService makes GET-Requests, something is an expected GET-Response)
The first time it's working. But when I then repeat step one and two, the AlertDialog does not appear and the app crashes with BadTokenException: Unable to add window -- token ... is not valid; is your activity running?
A check at step three showed, that isFinishing() is true the second time. That explains the error. But why is the activity finishing right after getting resumed?
I try to give you the relevant part of the code:
MyActivityA:
public class MyActivityA extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_a);
}
public void sendButtonPressed(View view) {
Intent intent = new Intent(MyActivityA.this, MyActivityB.class);
startActivity(intent);
}
}
MyActivityB:
public class MyActivityB extends AppCompatActivity implements CheckIPResultReceiver.Receiver{
private CheckIPResultReceiver mReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_b);
mReceiver = new CheckIPResultReceiver(new Handler());
mReceiver.setReceiver(this);
}
#Override
protected void onResume() {
super.onResume();
//starting repeated IntentService via AlarmManager
String targetURL = "www.google.de";
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
alarmIntent.putExtra("targetURL", targetURL);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager alarmManager=(AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 10000, pendingIntent);
}
public void onReceiveResult(int resultCode, Bundle resultData) {
//getting events from the service
switch (resultCode) {
case SendPostRequest_Service.STATUS_ALERT:
//stopping AlarmManager
Intent alarmIntent = new Intent(MyActivityB.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MyActivityB.this, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
//debug-check
if(isFinishing()){
// on the 2nd time --> TRUE!
Log.v(TAG, "Act. seems to finish?!");
}
else {
// only on the 1st time true
Log.v(TAG, "Act. seems ok");
new AlertDialog.Builder(MyActivityB.this)
.setTitle("Alert triggered!")
.setMessage("...")
.setCancelable(false)
.setPositiveButton("Restart", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(MyActivityB.this, MyActivityA.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
break;
}
}
}
Do you have any suggestions? I don't find any reason why MyActivityB goes into finishing...

Related

Alarm Manager does not work as expected when scheduling task

I'm currently working with Android Alarm Manager and found a working example. But it does not work properly in my situation. Let me explain. Basically my goal is to execute a method from the MainActivity each 5 mins. For this purpose I use Alarm Manager to schedule that task.
Basically this is the working stuff:
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.sendBroadcast(new Intent("SERVICE_TEMPORARY_STOPPED"));
}
}
MainActivity.java
public class MainActivity extends Activity{
private PendingIntent pendingIntent;
private AlarmManager manager;
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "I'm running", Toast.LENGTH_SHORT).show();
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
registerReceiver(broadcastReceiver, new IntentFilter("SERVICE_TEMPORARY_STOPPED"));
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startAlarm();
}
});
}
public void startAlarm() {
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int interval = 300000;
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Log.d(TAG, "Alarm Set");
}
}
Everything is good. "I'm running" Toast is executed every 300000 ms (5 mins). The AlarmReceiver class send a broadcast to my main Activity with the message "SERVICE_TEMPORARY_STOPPED". I already registered that message in my MainActivity via registerReceiver(broadcastReceiver, new IntentFilter("SERVICE_TEMPORARY_STOPPED"));. But, when I add another method, let's say stopAlarm() in the broadcastReceiver, which is going to stop the alarm after 5 mins, the time interval (5 mins) is not applied anymore. In something like 10 secs, it calls the Broadcast Receiver and stop the alarm. And this is the issue. Take a look at the stop() method and how I call it on the broadcastReceiver:
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "I'm running", Toast.LENGTH_SHORT).show();
stopAlarm();
}
};
public void stopAlarm() {
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
manager.cancel(pendingIntent);
Log.d(TAG, "Alarm Cancelled");
}
Any clue?
AlarmManager.setRepeating doesn't work properly on different android versions.
Try setExact. It won't repeat but you can achieve repeating functionality as mentioned below:
Updated AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.sendBroadcast(new Intent("SERVICE_TEMPORARY_STOPPED"));
long repeatCount = PreferenceManager.getDefaultSharedPreferences(context).getLong("REPEAT_COUNT", 0L);
repeatCount++;
PreferenceManager.getDefaultSharedPreferences (context).edit().putLong("REPEAT_COUNT", repeatCount).apply()
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
manager.setExact(AlarmManager.RTC_WAKEUP, (repeatCount *System.currentTimeMillis()),pendingIntent);
}
}
Here we maintain a repeatCount & variable (preference based) and increment it in your AlarmReceiver & schedule alarm again by calculating nextAlarmTime using repeatCount * System.currentTimeMillis();

Broadcasting with AlarmManager to call activity

I want to call a method in another activity with the use of Alarm manager
I use a broadcasting to call alarm manager
I want just call a activityAlarm without ui (just alarm method)
I dont want open ui,
What should I do?
public class ReciveData extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
Intent myIntent = new Intent(G.context, ActivityAlarm.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(G.context, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
G.alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 2000, 3000, pendingIntent);
}
}
and this :
public class ActivityAlarm extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
alarm();
}
public void alarm() {
Log.i("LOGALARM", "Hello");
}
}
To call it without UI you should use BroadcastReceiver or Service, not Activity:
Instead of this:
Intent myIntent = new Intent(G.context, ActivityAlarm.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(G.context, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
You should call this:
Intent myIntent = new Intent(G.context, YourReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(G.context, 0, myIntent, 0);
With this there will be no UI (because it won't start the activity), and you can put the alarm method to your BroadcastReceiver
More about the BroadcastReceiver: https://developer.android.com/reference/android/content/BroadcastReceiver.html
((ActivityAlarm ) getActivity()).alarm();
This should work for you.

Android :: how can I restart service and run specific function at time x

PROBLEM
I want to know some concept to do like the topic said
what should be a requirement to do that
I think that PendingIntent and AlarmManager would be help to restart the service
at time x but I don't know that way to let it call function that I need
Please advice.
FOR EXAMPLE
I have 2 functions in my service class and I want to register it
to run one of these two (Depend on user propose) in the future at time x
SOME CODE THAT I WORK AROUND (EDIT)
public class MyActivity extends Activity implements View.OnClickListener {
private Button b1;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
b1 = (Button)findViewById(R.id.cmd1);
b1.setOnClickListener(this);
}
#Override
public void onClick(View view) {
startIntentAt(5,MyReceiver.class);
finish();
}
private void startIntentAt(int seconds, Class<?> c) {
Intent myIntent = new Intent(getBaseContext(), c);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getBaseContext(),0, myIntent, 0);
AlarmManager alarmManager= (AlarmManager)getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, seconds);
//long interval = 60 * 1000; //
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
public class MyReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent scheduledIntent = new Intent(context, TargetActivity.class);
scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(scheduledIntent);
}
}
}

Reuse in Android - why can I not set a repeating alarm and cancel it using the same instance of a PendingIntent?

When binding onClick in activity_main.xml to setAlarm to one button and unsetAlarm to another button in the same activity, the following code will not let you unset the alarm when clicking the button linked to the unsetAlarm method.
...package name and includes ommitted...
public class MainActivity extends Activity {
private AlarmManager alarmManager;
private PendingIntent notifyIntent;
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
}
public void setAlarm(View v) {
Intent myIntent = new Intent(MainActivity.this,
NotificationService.class);
notifyIntent = PendingIntent.getService(MainActivity.this, 0,
myIntent, 0);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 1);
Log.v(TAG, "time for alarm trigger:" + calendar.getTime().toString());
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), 1 * 60 * 1000, notifyIntent);
}
public void unsetAlarm(View v) {
alarmManager.cancel(notifyIntent);
Log.v(TAG, "cancelling notification");
}
}
The solution was to (as I was provided in Notifications and AlarmManager - cancelling the alarm I set) recreate the pendingIntent in the unsetAlarm method:
public void unsetAlarm(View v) {
Intent myIntent = new Intent(MainActivity.this,
NotificationService.class);
notifyIntent = PendingIntent.getService(MainActivity.this, 0,
myIntent, 0); // recreate it here before calling cancel
alarmManager.cancel(notifyIntent);
Log.v(TAG, "cancelling notification");
}
My question is: Why can I not reuse the PendingIntent, stored in the field "notifyIntent" in the first code snippet? Why do I have to recreate it to cancel it? I have set the of MainActivity to have the attribute android:launchMode="singleInstance" so I should believe it was using the same instance when I click the notification created in the NotificationService (I have ommitted it but it just shows a notification).

Android: setting new Alarm from onReceive method

I have a collection of reminders in my database(sort by time). When my application starts I call setAlarm. I need to add code in onReceive method in order to do these tasks:
Get first reminder from my database
Get the delay associated to the reminder
Schedule a new Alarm for getting the next reminder.
I created a simple BroadcastReceiver class:
public class AlarmReceiver extends BroadcastReceiver{
private static final String DEBUG_TAG= "AlarmReceiver";
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
Log.d(DEBUG_TAG,"ALARM!!!");
// --mycode--
}
}
and the Activity class:
public class AlarmActivity extends Activity {
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
context = getApplicationContext();
}
public void setAlarm(View v){
Intent intent = new Intent(this,AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+ Delay,pendingIntent);
Log.i("SETTER","Alarm started");
}
public void stopAlarm(View v){
Intent intent = new Intent(this,AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
pendingIntent.cancel();
}
}
Now, I would that in the --mycode-- section new Delay is taken (if exists) from database and new Alarm is setted with this new Delay.
How can I set a new AlarmManager from onReceive method?
You can get AlarmManager in the broadcast receiver by accessing it from the context
AlarmManager alarmManager = (AlarmManager)arg0.getSystemService(Context.ALARM_SERVICE);
where arg0 is your context variable

Categories

Resources