How to update UI in a BroadcastReceiver
I created an application in which I registered a broadcast receiver within my main class(Main Activity
) and whenever I receive something in my BroadcastReceiver
I want to update UI for e.g. I want to show an alert box or set some text view of my MainActivity
. I receive all the values in my receiver but unable to set them, can somebody help me so that I can update my UI in the BroadcastReceiver
.
My BroadcastReceiver class is inner class of MainActivity like this :-
public class MainActivity extends Activity {
..........
public static class NissanTabBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences shrd = context.getSharedPreferences("NissanGallery", context.MODE_WORLD_READABLE);
type = shrd.getString("type", "null");
badges = shrd.getString("badge_count", "null");
//badge_tips_text.setText(badges);
/*Editor edit = shrd.edit();
edit.remove("type");*/
Toast.makeText(context, "" + type + "\n" + badge_tips_text.getText().toString(), Toast.LENGTH_LONG).show();
}
}
}
Any help will be appreciable
Thanks
I suggest you use a Handler.
- Initialize a Handler in the Activity, example:
handler = new Handler()
- Provide the handler to the BroadcastReceiver in the constructor, in the same way as I did for NissanTabBroadcast above
- Use
post()
method of your Handler instance in theonReceive()
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 re-use BroadcastReceiver in any Activity?
Consider situations where,
- You want to use the same
BroadcastReceiver
in different activities - You have written
BroadcastReceiver
in a separate file and want to accessActivity
methods, UI elements, etc.
In these cases using an interface is a great idea. I will explain the advantage and a use case in more detail. But first, let's see how it's done.
1) Create an interface
public interface MyBroadcastListener{
public void doSomething(String value);
}
2) Initialize the Listener in your BroadcastReceiver
public class MyReceiver extends BroadcastReceiver {
private MyBroadcastListener listener;
public MyReceiver(MyBroadcastListener listener){
this.listener = listener;
}
@Override
public void onReceive(Context context, Intent intent) {
listener.doSomething("Some Result");
}
}
3) Implement the interface in your Activity and override the method
public MainActivity extends AppCompatActivity implements MyBroadcastListener{
private BroadcastReceiver receiver;
@Override
public void onCreate(Bundle sis){
// Related code
receiver = new MyReceiver(this); // This is how you initialise receiver
// Register receiver etc
}
public void updateUI(String msg) {
TextView textView = (TextView) findViewById(R.id.textView);
textView .setText(msg);
}
@Override
public void doSomething(String result){
updateUI(result); // Calling method from Interface
}
}
Advantage and Use case?
Using an interface approach makes BroadcastReceiver independent of any Activity. Let's say in future you want to use this BroadCastReceiver with another activity which takes the result from BroadcastReceiver and start a DetailActivity.
Notice that this is a completely different task but you can use same BroadcastReceiver without even any code change inside the BroadcastReceiver.
How to do that?
Simple! Implement the interface in the Activity
and Override the method. That's it!
public ListActivity extends AppCompatActivity implements MyBroadcastListener{
// Your Activity code goes here
public void startDetailActivity(String title) {
Intent i = new Intent(ListActivity,this, DetailActivity.class);
i.putExtra("Title", title);
startActivity(i);
}
@Override
public void doSomething(String result){
startDetailActivity(String title); // Calling method from Interface
}
}
My case was to update the textfield in one of the fragments hosted by MainActivity.The simplest solution I found was this:--
In my MainActivity class retrieved the running instance of MainActivtiy.This is my MAinActivity
private static MainActivity mainActivityRunningInstance;
public static MainActivity getInstace(){
return mainActivityRunningInstance;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainActivityRunningInstance =this;
----------
}
Now in Broadcast reciever's onRecieve method, get that instance and call the update method
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().matches(Intents.PROVIDER_CHANGED_ACTION)) {
String textValue="the text field value";
// the null check is for, if the activity is not running or in paused state, in my case the update was required onlyif the main activity is active or paused
if(MainActivity.getInstace()!=null)
MainActivity.getInstace().updateUI(textValue);
}
Now for the part where we need to run the update in UIThread,The updateUI method of MainActivity will call the fragments update method.
public void updateUI(final String str) {
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
//use findFragmentById for fragments defined in XML ((SimpleFragment)getSupportFragmentManager().findFragmentByTag(fragmentTag)).updateUI(str);
}
});
}
and the final step is updating the fragment's text field
public void updateUI(String str){
tv_content.setText(str);
}
and Bingo, its done. I referred this link to solve my issue. Hope it help others.
Use runOnUiThread
:
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
// show alert
}
});