3

I have two activities: one is the main (A), and the second one which is started from A (B). I start B with startActivityForResult(intent, id).

I know I can send the result back to A via the setResult() method, but as far as I know, the result isn't sent until finish() is called. I need to send data from B to A without closing B (even several times before closing). Is there a way to achieve that?

As far as I've read, there are not many options to achieve this. I could use SharedPreferences but then I'd need also some kind of event to inform A that it has to read a value!

Any ideas appreciated.

------ FINAL SOLUTION ------

Finally I got it thanks to @Nathaniel Waggoner's advice. Here's what I did:

Inside my activity I declared the extension of BroadcastReceiver:

class ActivityBroadcast extends BroadcastReceiver {
  @Override
  public void onReceive(final Context context, final Intent intent) {
    final String txt2send = intent.getStringExtra("txt2send");
    if ((txt2send != null) && (!txt2send.isEmpty())) {
      // Do the needed stuff
      ...
    }
  }
}

So now I declared the ActivityBroadcast instance in my class and initialized it:

private static ActivityBroadcast broadcast_signal;
broadcast_signal = new ActivityBroadcast();

The way I control that it's just my Intent the one who triggers the onReceive method is with an IntentFilter set to the SENDTXT2SOCK customized action, this way:

// CustomActions.SENDJOIN2CHAN is just a constant from a customized public class
// where I define my own constants to not interfere with the "official" ones
registerReceiver(broadcast_signal, new IntentFilter(CustomActions.SENDTXT2SOCK));

This way I'm saying that on broadcast_signal will just be registered the CustomActions.SENDTXT2SOCK action, so any other is ignored. Now we just have to send a signal from the desired activity to that receiver:

final Intent intentResult = new Intent(CustomActions.SENDTXT2SOCK);
intentResult.putExtra("txt2send", "blabla");
sendBroadcast(intentResult);

And that's all, works like a charm!

nKn
  • 13,691
  • 9
  • 45
  • 62
  • 1
    **"I need to send data from B to A without closing B (even several times before closing)."** - Why? The moment Activity B is started and hides Activity A, then Activity A will enter a stopped state. In other words it is no longer running and therefore won't be able to process any data fed back to it in that state. I think you're misunderstanding the concept of what an `Activity` is and the `Activity` life-cycle. I can't think of any use case where a hidden / stopped `Activity` needs real-time data updates. – Squonk Jan 08 '14 at 21:21
  • I'll try to explain it better: A has an object which is an AsyncTask, which creates a socket and it's executing all the app life time. In B I want to send several data through that socket (without the need of closing B after each one), so my initial idea was sending it to A and from A to the AsyncTask, however I didn't realize it would indeed be in the stopped state... I suppose that one possible solution is passing the socket object to B. – nKn Jan 08 '14 at 21:32
  • 1
    Ouch! Firstly, contrary to popular belief, an `AsyncTask` shouldn't be used for long-running operations of any sort (networking or other). Secondly if you are using an `AsyncTask` in `Activity` A and you start `Activity` B there is a possibility (however unlikely) that `Activity` A will be destroyed by the system to free up resources - the possible outcome being an orphaned `Thread` (the one used by `doInBackground`). I would strongly recommend using a bound `Service` with worker thread to perform the network operations . It can be accessed from both Activities if necessary. – Squonk Jan 08 '14 at 21:42
  • You're right, I'll convert the AsyncTask into a Service. I'll try yet another solution proposed above relative to Broadcasts and I'll post results. Thanx! – nKn Jan 09 '14 at 07:06
  • Please post your solution as an answer rather than an edit to the question. – Donald Duck Nov 05 '21 at 19:28

4 Answers4

3

Use broadcasts and intents.

Broadcast Receivers:

http://developer.android.com/reference/android/content/BroadcastReceiver.html

Nathaniel D. Waggoner
  • 2,856
  • 2
  • 19
  • 41
  • I didn't know about this one! It doesn't help me this time because as @Squonk said, the main activity is stopped and I cannot make this activity an extension of BroadcastReceiver, but I think it will be useful for other things :) – nKn Jan 09 '14 at 06:22
  • 1) You don't need to extend broadcast receiver. You can define them as private classes within your activity. Broadcasts almost always solve this type of communication issue. It's not always the preferred method (for a number of reasons, services for example have a very good message passing (and way more) mechanism in Binders). 2) Your Activity isn't stopped - it could be. I only say this because it's important to understand that you are not immediately destroyed when your activity loses focus, rather when resources or other specifics merit it. – Nathaniel D. Waggoner Jan 09 '14 at 06:53
  • Ok, I'll give it a try today and I'll post results. Thanx!! – nKn Jan 09 '14 at 07:03
  • I would also point out that Squonk's comments are correct - you shouldn't be networking in an Async Task, a service is much better suited. – Nathaniel D. Waggoner Jan 09 '14 at 07:04
  • 1
    Yes, I just read a very complete documentation about Services and definitely I'll convert it into a Service – nKn Jan 09 '14 at 07:07
  • 1
    It works like a charm with broadcasts & intents :-) I edited my original question with the implemented solution. Also working on changing the AsyncTask into a Service :-P Thanks! – nKn Jan 09 '14 at 18:34
  • @NathanielWaggoner : **"Your Activity isn't stopped"** - It almost certainly will be. If an `Activity` is partially covered, e.g., with a dialog or another `Activity` set to a dialog theme then it will enter a paused state but even then, it is not considered to be "running" (see the `Activity` life-cycle diagram. When an `Activity` is no longer visible in any way it will enter the stopped state. It doesn't mean it will be destroyed but it is a potential candidate for destruction in extreme circumstances of low system resources. – Squonk Jan 09 '14 at 22:53
  • @Squonk I mis-spoke. I meant "Isn't destroyed". That said - just because you can't think of a use case doesn't mean you can't pass data to stopped activities, and it doesn't remove broadcasts as a valid form of communication which was his understanding. – Nathaniel D. Waggoner Jan 10 '14 at 05:12
  • @NathanielWaggoner : **"just because you can't think of a use case doesn't mean you can't pass data to stopped activities"** What I was trying to emphasise is there isn't any point in updating data in real-time in an invisible `Activity`. The primary function of the Android `Activity` class is to act as a UI framework, i.e., to allow interaction with the user. If it is not visible to the user what is the point in updating data in real-time? Further to this, the OP's question was about passing data from `Activity` B to A in order to feed it to an `AsyncTask`. This is not a good Android design. – Squonk Jan 10 '14 at 07:16
  • I'm in agreement with you on everything except the following: The "point of updating data in real-time" is irrelevant. He asked how to pass data between two Activities. The answer to that question is "Use Broadcasts". – Nathaniel D. Waggoner Jan 10 '14 at 08:38
  • Could you please elaborate how this can be used to communicate between activities? – Donald Duck Nov 05 '21 at 19:53
1

You can also give a shot to OnsharedPreferenceChangelistner

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Prachur
  • 1,100
  • 7
  • 24
  • 42
0

you can use eventBus simple library.
first register eventbus in receiver activity

   @Override
    public void onStart() {
       super.onStart();
     EventBus.getDefault().register(this);
    } 

then set a subscriber method

@Subscribe(threadMode = ThreadMode.MAIN)  
public void onMessageEvent(MessageEvent event) {/* Do something */};

then in other activity post your entity like this

EventBus.getDefault().post(new MessageEvent());
HGH806
  • 84
  • 1
  • 6
0

You can use broadcasts and observers to call a method of one activity from another activity. You will use an intent to call a broadcast from activity B, and then you will use an observer to call a method in activity A from the broadcast.

For example, if you want to call ActivityA.someMethod from ActivityB, you can do the following (don't forget implements Observer on ActivityA):

public class ActivityA extends AppCompatActivity implements Observer{
    //This is the method you want to call from ActivityB
    public void someMethod(Intent intent){
        //intent will be the Intent object created in ActivityB, you can pass data to this method by setting extras in the intent
    }

    //Define the observer and broadcast receiver classes
    private static class MyObservable extends Observable{
        private static final MyObservable instance = new MyObservable();
        public void updateValue(Object data){
            synchronized(this){
                setChanged();
                notifyObservers(data);    //This method calls ActivityA.update
            }
        }
    }

    public static class MyBroadcastReceiver extends BroadcastReceiver{
        //This class must be public and static and must be added to the manifest
        //To add this class to the manifest in Android Studio put the cursor on the name of the class, press Alt+Enter and choose "Add to manifest"
        @Override
        public void onReceive(Context context, Intent intent){    //This method will be called when the broadcast is sent from ActivityB
            MyObservable.instance.updateValue(intent);
        }
    }

    //Connect the observer to the activity in the onCreate method
    @Override
    protected void onCreate(Bundle savedInstanceState){
        MyObservable.instance.addObserver(this);
        //Do everything else in onCreate as usual
    }

    //This method will be called when the notifyObservers method is called from the oberver
    @Override
    public void update(Observable observable, Object data){
        this.someMethod((Intent) data);    //Call the method that you need
    }
}
public class ActivityB extends AppCompatActivity{
    public void callSomeMethodOnActivityB(){
        Intent intent = new Intent(this, ActivityA.MyBroadcastReceiver.class);
        //Add some extras to the intent to pass data
        sendBroadcast(intent);    //Calls ActivityA.MyBroadcastReceiver.onReceive
    }
}

Most of this answer is based on ilw's answer to "Communication between BroadcastReceiver and Activity", credits to them.

Donald Duck
  • 8,409
  • 22
  • 75
  • 99