I want my Android app to periodically update its UI based on the response from a REST service. I can't do this on the main thread because it's not permitted / bad practice to access the network on the main thread. The general wisdom on SO and the internet is to use a combination a BroadcastReceiver and AlarmManager. For example this is the advice here. I've tried two designs, neither of which I can make to work:
- Define a class extending BroadcastReceiver as an inner class of my MainActivity.
- Define the same class as an outer class.
With (1) I get this runtime error:
java.lang.RuntimeException: Unable to instantiate receiver com.dbs.alarm.MainActivity$AlarmReceiver: java.lang.InstantiationException: java.lang.Class<com.dbs.alarm.MainActivity$AlarmReceiver> has no zero argument constructor
With (2) the problem is I can't figure out how to access the view I want to modify in MainActivity.
Here is an example implementation of (1):
package com.dbs.alarm;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// I tried making this its own class, but then findViewById isn't accessible.
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// I tried wrapping this in runOnUiThread() but it made no difference.
TextView myTextView = findViewById(R.id.my_text);
CharSequence myCharSequence = "Set from UpdateReceiver.onReceive()";
myTextView.setText(myCharSequence);
}
}
private void setRecurringAlarm(Context context) {
Intent intent = new Intent(context, AlarmReceiver.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 1000,
1000, // Set so short for demo purposes only.
pendingIntent
);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRecurringAlarm(this);
}
}
I also added this to my AndroidManifest.xml, and considering that I get an exception it seems to be registered successfully:
<receiver android:name="com.dbs.alarm.MainActivity$AlarmReceiver">
</receiver>