6

I am learning Android concepts Activity and BroadCastReceiver. I want to update the content of Activity from the BroadtCastReceiver both are in different java class.

It is something like

MyActivity.java and MyBroadtCastReceiver.java

Is this possible to do this in Android ?

N Sharma
  • 33,489
  • 95
  • 256
  • 444
  • 1
    Make your `BroadcastReceiver` an inner class of your `Activity`. – Squonk Aug 09 '14 at 06:33
  • 1
    @Squonk No I don't want to have a inner class. I have something like this MyActivity.java and MyBroadtCastReceiver.java. Isn't there any way to do this ? – N Sharma Aug 09 '14 at 06:39
  • 1
    OK some points / questions... 1. Why don't you want an inner class? 2. How are you going to register the receiver? 3. If the receiver isn't registered by the `Activity` how are you going to know if the `Activity` actually exists at the point it receives a broadcast? 4. Generally, the answer is - No, you can't do this in any reliable way from outside an `Activity` which may or may not exist and even if it does exist will be in an indeterminate state (running, paused, stopped etc). Having the receiver as an inner class is the only guaranteed way of doing it. – Squonk Aug 09 '14 at 06:45
  • possible duplicate of [Android Best Practice on Updating the UI from BroadcastReceiver to a certain activity](http://stackoverflow.com/questions/3275042/android-best-practice-on-updating-the-ui-from-broadcastreceiver-to-a-certain-act) – GovindRathod Aug 09 '14 at 07:23

6 Answers6

27

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).
Squonk
  • 48,735
  • 19
  • 103
  • 135
  • 1
    +1 Thanks helpful. here can we use `LocalBroadCastManager` to achieve same task ? – N Sharma Aug 09 '14 at 08:17
  • Does it cause any leaks when the activity is destroyed, as Broadcast Receiver is an inner class within the activity. – Neanderthal May 24 '16 at 12:25
  • Important to also mention that you should not start long running background threads from a `BroadcastReceiver`. See here under *Effects process state* : https://developer.android.com/guide/components/broadcasts.html – Rany Albeg Wein May 01 '17 at 19:40
  • Quick note: registerReceived didn't work for me. I used: LocalBroadcastManager.getInstance(this).registerReceiver( mReceiver, new IntentFilter(Constants.BROADCAST_ACTION)); – Mariano L Jan 04 '18 at 19:22
1

Yes its possible. This is what i do. Class i send the broadcast from (BackgroundActivity.java):

public static final String BROADCAST_BUFFER_SEND_CODE = "com.example.SEND_CODE";

onCreate(){
   bufferIntentSendCode = new Intent(BROADCAST_BUFFER_SEND_CODE);
}

private void sendBufferingBroadcastSendCode() {
   bufferIntentSendCode.putExtra("buffering", "1");
   sendBroadcast(bufferIntentSendCode);
}

The class it will receive the broadcast(SendCode.java):

onResume(){
        registerReceiver(broadcastBufferReceiver, new IntentFilter(BackgroundActivity.BROADCAST_BUFFER_SEND_CODE));
}

// set up broadcast receiver
private BroadcastReceiver broadcastBufferReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent bufferIntent) {
        SendCode.this.LoadMessages(alarmNumber);
    }
};

I unregister it in onPause

this.unregisterReceiver(broadcastBufferReceiver);
0

Register a new BroadcastReceiver object in your activity with same intent-filters as your MyBroadtCastReceiver. Since BroadcastReceiver and MyBroadtCastReceiver has same intent-filters both of their onReceive() will be invoked. Whatever update that you want to do in Activity can be done in onReceive of your BroadcastReceiver.

Rajesh Batth
  • 1,672
  • 2
  • 19
  • 23
0
You can do like this:

public class MyActivity extends Activity{

// used to listen for intents which are sent after a task was
// successfully processed
private BroadcastReceiver mUpdateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        new UpdateUiTask().execute();
    }
};

@Override
public void onResume() {        
    registerReceiver(mUpdateReceiver, new IntentFilter(
            YOUR_INTENT_ACTION));
    super.onResume();
}

@Override
public void onPause() {     
    unregisterReceiver(mUpdateReceiver);
    super.onPause();
}


// used to update the UI
private class UpdateUiTask extends AsyncTask<Void, Void, String> {

    @Override
    protected void onPreExecute() {

    }

    @Override
    protected String doInBackground(Void... voids) {
        Context context = getApplicationContext();
        String result = "test";
        // Put the data obtained after background task. 
        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        // TODO: UI update          
    }
}  

}
Rahil Ali
  • 957
  • 10
  • 25
0

Squonk-s answer only works, if the Activity is active currently. If you dont want to declare / define your BroadcastReceiver (BR) in an other Activity, or if you want to make some changes even if the app is not foreground, than your solution would look something like this.

First, you declare the BR, and save, or override the data needed to show in Acitvity.

public class MyBR extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // override the data. Eg: save to SharedPref
    }
}

Then in Activity, you show the data

TextView tv = findViewById(R.id.tv);
tv.setText(/*get the data Eg: from SharedPref*/);

And you should use a Timer to refresh the tv as well:

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                 public void run() {
                    TextView tv = findViewById(R.id.tv);
                    tv.setText(/*get the data Eg: from SharedPref*/);
                }
            });
        }
    }, REFRESH_RATE, REFRESH_RATE);

REFRESH_RATE could be something like 1 second, but you decide.

Zsolt Nagy
  • 13
  • 4
-3

try like this it may help you.

Define this method in activity's oncreate method in which you want to update ui,

    BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    //your code to update ui
                }
            };
   LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("giveyourappname"));

Define this action at place from where you want to update ui,

try{
        ActivityManager am = (ActivityManager) this .getSystemService(ACTIVITY_SERVICE);
        List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
        ComponentName componentInfo = taskInfo.get(0).topActivity;
        Log.d("Activity", "Current Activity ::" + taskInfo.get(0).topActivity.getClassName());
        Log.d("Package", "Package Name :  "+ componentInfo.getPackageName());

        if(componentInfo.getPackageName().equals("your application package name")){
             Intent intent = new Intent("giveyourappname");
                //add data you wnat to pass in intent
                LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
        }
    }catch(Throwable e){
        e.printStackTrace();
    }
Akash Moradiya
  • 3,318
  • 1
  • 14
  • 19
  • also check, activity in which you want to update ui is in top or not – Akash Moradiya Aug 09 '14 at 06:52
  • Do I need to handle the case of whether the activity is exist or not ? – N Sharma Aug 09 '14 at 07:00
  • yes, because if activity not running than you can not access its resources – Akash Moradiya Aug 09 '14 at 07:01
  • then chance of force close – Akash Moradiya Aug 09 '14 at 07:01
  • Then HOw to handle this case ? – N Sharma Aug 09 '14 at 07:08
  • 4
    from the documentation of `getRunningTasks()`: Note: this method is only intended for debugging and presenting task management user interfaces. This should never be used for core logic in an application, such as deciding between different behaviors based on the information found here. Such uses are not supported, and will likely break in the future. For example, if multiple applications can be actively running at the same time, assumptions made about the meaning of the data here for purposes of control flow will be incorrect. – LordRaydenMK Aug 09 '14 at 07:15
  • @MoradiyaAkash No you are wrong I have not downvoted your answer. I will accept it sure. don't worry :) I see you downvoted my question but still it doesn't make me in trouble by these silly things – N Sharma Aug 09 '14 at 07:22
  • @LordRaydenMK How I can achieve my requirement then ? please help – N Sharma Aug 09 '14 at 07:24
  • 1
    @Williams : Reread my first comment on your question and register the receiver in `onResume()` and unregister in `onPause()` methods of your `Activity`. In that way you can guarantee your `Activity` is in a "running" state when the receiver's `onReceive(...)` method is called. Having a separate Java class for a `BroadcastReceiver` which has to do something as explicit as update specific UI elements gives no advantage. – Squonk Aug 09 '14 at 07:34
  • @Squonk can you please write answer so that I can accept your answer – N Sharma Aug 09 '14 at 07:40
  • @Williams : OK give me a couple of minutes. – Squonk Aug 09 '14 at 07:56