How to Update UI in a Broadcastreceiver

How to update UI in a BroadcastReceiver

I suggest you use a Handler.

  1. Initialize a Handler in the Activity, example: handler = new Handler()
  2. Provide the handler to the BroadcastReceiver in the constructor, in the same way as I did for NissanTabBroadcast above
  3. Use post() method of your Handler instance in the onReceive() method to submit the Runnable that updates the UI

This is the cleanest solution I can imagine.

public class MainActivity extends Activity {

private MyReceiver receiver;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

receiver = new MyReceiver(new Handler()); // Create the receiver
registerReceiver(receiver, new IntentFilter("some.action")); // Register receiver

sendBroadcast(new Intent("some.action")); // Send an example Intent
}

public static class MyReceiver extends BroadcastReceiver {

private final Handler handler; // Handler used to execute code on the UI thread

public MyReceiver(Handler handler) {
this.handler = handler;
}

@Override
public void onReceive(final Context context, Intent intent) {
// Post the UI updating code to our Handler
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, "Toast from broadcast receiver", Toast.LENGTH_SHORT).show();
}
});
}
}
}

How to update the UI of Activity from BroadCastReceiver

A BroadcastReceiver can be used in many ways but when it comes to something as specific as updating the UI components of an Activity, there is little advantage to declaring / defining a BroadcastReceiver in it's own Java class file.

Reasoning - the BroadcastReceiver has to have some prior "knowledge" of the Activity and what it is required to do in order to update the UI. In effect the BroadcastReceiver is tied to the Activity itself and it makes sense to declare / define it as an inner class.

Another important aspect is the Activity needs to be in a "running" (i.e., visible) state in order to guarantee manipulation of UI components. In this case, registering the receiver in onResume() and unregistering in onPause() will help prevent problems.

Using a generic template I'd do something like the following...

class MyActivity extends Activity {

boolean mIsReceiverRegistered = false;
MyBroadcastReceiver mReceiver = null;

// onCreate(...) here

@Override
protected void onResume() {

// Other onResume() code here

if (!mIsReceiverRegistered) {
if (mReceiver == null)
mReceiver = new MyBroadcastReceiver();
registerReceiver(mReceiver, new IntentFilter("YourIntentAction"));
mIsReceiverRegistered = true;
}
}

@Override
protected void onPause() {
if (mIsReceiverRegistered) {
unregisterReceiver(mReceiver);
mReceiver = null;
mIsReceiverRegistered = false;
}

// Other onPause() code here

}

private void updateUI(Intent intent) {
// Do what you need to do
}

private class MyBroadcastReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
}
}

EDIT: A couple of extra notes...

  1. The life-cycle of a BroadcastReceiver is between entering and leaving onReceive(...). Once it has returned from onReceive(...) the instance remains in a dormant state waiting for the next broadcast.
  2. Directly related to point 1 - a BroadcastReceiver isn't designed for "heavy lifting". Basically the onReceive(...) method should be kept as simple as possible. Any methods it calls should also be as light-weight as possible...get in, do your stuff, get out then wait for the next broadcast. If updating the UI is going to take some time (perhaps updating a ListView by re-querying a database for a large amount of data for example), consider calling code which performs asynchronously (an AsyncTask for example).

How can I update the UI using a broadcast receiver?

The problem is that you can't subscribe to ActionTimeTick the way you do. From the documentation:

Broadcast Action: The current time has changed. Sent every minute. You
cannot receive this through components declared in manifests
, only by
explicitly registering for it with Context.registerReceiver().

In Xamarin, the IntentFilter attribute is used by monodroid.exe when generating the intent-filter elements in the AndroidManifest.xml file so that won't work.

What you need to do, is remove the IntentFilter attribute and register the receiver programmatically in your MainActivity (for example).

protected override void OnResume()
{
base.OnResume();
RegisterReceiver(yourReceiver, new IntentFilter(Intent. ActionTimeTick));
}

protected override void OnPause()
{
base.OnPause();
UnregisterReceiver(yourReceiver);
}

update ui from broadcast receiver

One way to update your Activity from a BroadcastReciever is to create a BroadcastReciever in MainActivity:

  private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

// Extract data included in the Intent
// String message = intent.getStringExtra("message");
//update the TextView
}
};

Reigester this BroadcastReciever in onResume:

  this.registerReceiver(mMessageReceiver, new IntentFilter("some_unique_name"));

And unregiester onPause:

  this.unregisterReceiver(mMessageReceiver);

In AlarmReceiver just use:

private void updateYourActivity(Context context) {

Intent intent = new Intent("some_unique_name");

// put whatever data you want to send, if any
// intent.putExtra("message", message);

// send broadcast
context.sendBroadcast(intent);
}

Kotlin: Call a function to update UI from BroadcastReceiver onReceive

Sharing the info to register BroadcastReceiver in Kotlin

Step 1. Create BroadcastReceiver in MainActivity.kt

private val mPlugInReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
Intent.ACTION_POWER_CONNECTED -> {
//update your main background color
updateBackgroundColor()
}
Intent.ACTION_POWER_DISCONNECTED -> {
//update your main background color
updateBackgroundColor()
}
}
}
}

Step 2. Create IntentFilter

private fun getIntentFilter(): IntentFilter {
val iFilter = IntentFilter()
iFilter.addAction(Intent.ACTION_POWER_CONNECTED)
iFilter.addAction(Intent.ACTION_POWER_DISCONNECTED)
return iFilter
}

Step 3. Register receiver at onStart()

override fun onStart() {
super.onStart()
registerReceiver(mPlugInReceiver, getIntentFilter())
}

Step 4. Unregister receiver at onStop()

override fun onStop() {
super.onStop()
unregisterReceiver(mPlugInReceiver)
}

If you have custom BroadcastReceiver, you can register using LocalBroadcastManager and create your local IntentFilter

private val mLocalBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
AnyService.UPDATE_ANY -> {

}
}
}
}

private fun getLocalIntentFilter(): IntentFilter {
val iFilter = IntentFilter()
iFilter.addAction(AnyService.UPDATE_ANY)
return iFilter
}

Register local receiver
LocalBroadcastManager.getInstance(applicationContext).registerReceiver(mLocalBroadcastReceiver, getLocalIntentFilter())

Unregister local receiver LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(mLocalBroadcastReceiver)

Update active Activity UI with BroadcastReceiver

The easiest way is to make your AlarmReceiver an inner class of your activity. This way it will have access to all fields and methods of your activity. If you don't use it anywhere else, it might as well be anonymous.
To make it update your activity only when it's active, register your receiver in onResume() and unregister it in onPause(). Notice the IntentFilter specifying intent actions your BroadcastReceiver will respond to.

Example:

private BroadcastReceiver updateReceiver;

//...

@Override
protected void onResume() {
super.onResume();

updateReceiver=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//your list update code here
}
};
IntentFilter updateIntentFilter=new IntentFilter("update");
registerReceiver(updateReceiver, updateIntentFilter);
}

@Override
protected void onPause() {
super.onPause();

if (this.updateReceiver!=null)
unregisterReceiver(updateReceiver);
}

If you still want your AlarmReceiver to be a separate class, pass some kind of callback to it during initialization:

public interface AlarmReceiverCallback {
public void onAlarmReceived(Intent intent);
}

//in your AlarmReceiver class:
private AlarmReceiverCallback callback;

public AlarmReceiver(AlarmReceiverCallback callback) {
this.callback=callback;
}

@Override
public void onReceive(Context context, Intent intent) {
callback.onAlarmReceived(intent);
}

Initialization of your AlarmReceiver will look the following way:

updateReceiver=new AlarmReceiver(new AlarmReceiverCallback() {
@Override
public void onAlarmReceived(Intent intent) {
//your list update code here
}
});

Android: How to update the UI from a static BroadcastReceiver?

The thing you need is not broadcast receiver along with AlarmManager or JobScheduler for api above 21 and greenrobot event bus.

AlarmManager Schedules the broadcast call once a day or at any time you want and every time if the broadcast is called you can trigger event from eventbus and receive that event in the place where you want it. The thing why to use event bus is we do not need to handle if the view is visible or not.iF the view is in re use state it triggers the event the view and one method is called by event bus and in that method you can do anything you want to do with view.

personally i don't prefer service because service execution is really expensive now a days.

Note: the package name where you put alarm manager and broadcast
receiver should be "alert" some samsung mobile are very optimized so
they will only let the package name with "alert to run fully". You
will also need on boot receiver to register receiver and schedule
alarmmanager in case if the phone is booted.

How to update the UI with BroadcastReceiver onReceive in Android?

Use this code:

public class MainActivity extends AppCompatActivity {
...

BroadcastReceiver br = new BroadcastReceiver(){
@Override
public void onReceive( Context context, Intent intent ){
//update UI here directly
View view = findViewById( R.id.example );
}
};

@Override
protected void onResume(){
super.onResume();
// Check state here
...
IntentFilter filter = new IntentFilter();
filter.addAction( ConnectivityManager.CONNECTIVITY_ACTION );
registerReceiver( br, filter);
}

@Override
protected void onPause(){
super.onPause();
unregisterReceiver( br );
}

...
}

Update fragment ui from broadcast receiver in MvvM architecture and Kotlin

Eventually I found a clean and modern solution like I wanted. The trick is to wrap the BroadcastReceiver in a LiveData. By using this pattern you can observe the connection LiveDada directly from your fragment and update the ui. Of Course it is also possible (like sergiy tikhonov mentioned) to have a companion object in the base activity with a LiveData that is getting updated from the BroadcastReceiver and you can observe it from the fragment, but I didn't like this approach.

So it works like this:

Create an enum with the states of the network.

enum class NetworkAvailability {
UNKNOWN,
CONNECTED,
DISCONNECTED
}

Create the class that extends the LiveData. I am using the singleton pattern because I don't want multiple instances. I create a BroadcastReceiver instance and I register/unregister it in onActive and onInactive methods of the LiveData.

class ConnectionStateLiveData(val context: Context) : LiveData<NetworkAvailability>() {

companion object {
private lateinit var instance: ConnectionStateLiveData

fun get(context: Context): ConnectionStateLiveData {
instance = if (::instance.isInitialized){
instance
}else{
ConnectionStateLiveData(context)
}
return instance
}
}

private val connectivityBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val netInfo = connectivityManager.activeNetworkInfo

value = if (netInfo != null && netInfo.isConnected) {
NetworkAvailability.CONNECTED
} else {
NetworkAvailability.DISCONNECTED
}
}
}

override fun onActive() {
super.onActive()
value = NetworkAvailability.UNKNOWN
val broadcastIntent = IntentFilter()
broadcastIntent.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
context.registerReceiver(connectivityBroadcastReceiver, broadcastIntent)
}

override fun onInactive() {
super.onInactive()
context.unregisterReceiver(connectivityBroadcastReceiver)
}
}

And finally I observe the LiveData in my fragment.

ConnectionStateLiveData.get(context).observe(viewLifecycleOwner, Observer {
if (it == NetworkAvailability.CONNECTED) {
binding.noInternetTextView.visibility = View.GONE
}
})


Related Topics



Leave a reply



Submit