4

In an App I am currently working on I am facing a problem regarding the communication between Activities.
Basicly I have a UI-Component, which is similar to a Combobox. However, the list of the possible values for this component has to be openend in a new Activity.
So when you clicked the component, a new Activity is opened, using startActivityForResult.
When you select the new value, it is put inside a Bundle and returned to the previous Activity. I then need to use the onActivityResult-method to get the selected value and set it to the component.
That means, that every Activity that uses this component needs to override onActivityResult and refresh the component with the new value.
What I want instead is, that the component takes care about all this stuff and you only have to register a Listener, just like you do it for a TextView and similar components.
But at the moment I just can't find a good way to do that, as the communication is tightly bound to the Activity and I just can't get the result of the Activity outside the onActivityResult.
Does anyone know a good solution for this problem?

Robert P
  • 9,398
  • 10
  • 58
  • 100
  • check this https://developer.android.com/training/implementing-navigation/ancestral.html – Rajesh Nov 21 '16 at 07:40
  • Thanks for your comment, but I can't see, how this should solve my issue... My problem is, that the `Activity` needs to return a result (the selected value), which I would like to receive without using `onActivityResult`. – Robert P Nov 21 '16 at 07:46
  • Is there any particular reason that you need to start a new activity in order to get the value? – clownba0t Nov 21 '16 at 07:46
  • Yes. The values are `Reference`s to another table. So there might be many objects. I offer a method to filter those references by different fields or search them. So this `Activity` could get pretty complex and therefore I want it to be in a sepparate `Activity`, not in a dialog. – Robert P Nov 21 '16 at 07:54
  • 1
    You can try using broadcasts :P – sssemil Nov 21 '16 at 08:01
  • 1
    Use `interface` or `broadcast` receiver. – Piyush Nov 21 '16 at 08:02
  • `Broadcast`s really could do the job, I'll try that one out. Thanks! – Robert P Nov 21 '16 at 08:03

6 Answers6

2

Solution to this- use EventBus and post sticky event on it. By doing so you don't have to override onActivityResult.

The workflow will be as following: - Create event object with your data - Remove all sticky events of the same type from the Bus - post new values by .sendSticky() method.

That event will be around until something remove it from the bus - start another activity - in this activity override method, subscribing to that event type, in it: a) take and process event with your argument b) remove it from the bus - subscribe to the bus (second Activity) in onResume() method - unsubscribe from the bus in .onPause() method

The point is, that this allow you to seamlessly handle lifecycle of second Activity, and you can subscribe/unsubscribe to the bus in base class

Sid
  • 14,176
  • 7
  • 40
  • 48
Alex Shutov
  • 3,217
  • 2
  • 13
  • 11
1

What about using BroadCastReceiver?

Basically you send a broadcast and every activity that is registered to receive that broadcast will receive that broadcast will receive the message in onReceive

First of all declare in the manifesto what you are going to listen for, something like:

   <receiver android:name=".TestBroadCast”>
      <intent-filter>
         <action android:name="io.test.TEST"/>
      </intent-filter>
   </receiver>

Than simply extend BroadCastReceiver

public class TestBroadCastReceiver extends BroadcastReceiver {

   @Override
   public void onReceive(Context context, Intent intent) {
      //TODO: Handle the Intent received.

}

Example of how to send a broadcast:

   public static final String INTENT_ACTION = "io.test.TEST";
   public static final String INTENT_EXTRA  = "someData";

   Intent intent = new Intent();
   intent.setAction(INTENT_ACTION);
   intent.putExtra(INTENT_EXTRA,"test");
   sendBroadcast(intent);

And you will get the Intent and than you can handle it as you wish :)!

UPDATE ~ Registering from code instead of manifesto

To avoid registering the service from the Manifesto you can do it from the code, with a code similar to the following listing:

IntentFilter intentFilter = new IntentFilter("io.test.TEST");
TestBroadCastReceiver mReceiver = new TestBroadCastReceiver();
context.registerReceiver(mReceiver, intentFilter);

P.S. I suggest you using LocalBroadcastReceiver if you don't need other applications to be able to send results insted of the common BroadcastReceiver for security reasons

Sid
  • 14,176
  • 7
  • 40
  • 48
  • I'll try to go with `BroadCastReceiver`. However, I won't register it in the `Manifest`, but in the source code of the component. That way, the `Activity` does not need to know anything about it. – Robert P Nov 21 '16 at 09:33
  • @Springrbua yes that's even better, I'll update the question to make it complete :) – Sid Nov 21 '16 at 09:34
  • @Springrbua I understand that you know how to the register from code, but I have updated the answer so someone who does not can find it :) Best of luck! – Sid Nov 21 '16 at 09:40
  • Thanks for updating your answer. In my case I need to register it in the sourcecode, because the name of the `BraodCast` is dynamic. I could have multiple components, which allow you to choose different `Reference`s (for example a `Delivery address` and a `Billing address`). The component, which is responsible for the `Delivery address` should ofc only get that `BraodCast`. Therefore I have an "IntentFilterPrefix" like "io.test.TEST." as well as a suffix which might be "delivery" or "billing". – Robert P Nov 21 '16 at 09:47
  • 1
    I just wanted to let you know, that this solution works perfectly in my case. The component just needs to register itself as a `BroadcastReceiver` and open the `ChooserActivity` on click. The `ChooserActivity` then just needs to send a `Broadcast`, containing the selected `Reference`. This way, my component handles everything and can inform it's `Listener`s about changes. – Robert P Nov 21 '16 at 16:45
  • @Springrbua I am very glad that you found that helpful :)! – Sid Nov 21 '16 at 16:48
1

You can implement Observer Design Pattern, the better implementation of that are BroadcastReceiver and a Library which implement event bus design Otto

Bills
  • 768
  • 7
  • 19
0

Hello @Alex Shutov was right Try this https://github.com/greenrobot/EventBus http://greenrobot.org/eventbus/

Bipin Bharti
  • 1,034
  • 2
  • 14
  • 27
  • I would like to avoid using external libraries, as long as possible. However, if i can't find another method, I''ll come back to this. Thanks! – Robert P Nov 21 '16 at 08:04
  • ohk no Problem try broadcastreceiver – Bipin Bharti Nov 21 '16 at 08:06
  • If you know, how to solve this issue using an `Interface`, please update your answer. At the moment I can't see, how an `Interface` would help me. The communication still would need to go from one activity to the other, which is the step I would like to avoid. – Robert P Nov 21 '16 at 08:14
  • ohk just a minute – Bipin Bharti Nov 21 '16 at 08:56
  • hello try this one http://stackoverflow.com/questions/994840/how-to-create-our-own-listener-interface-in-android – Bipin Bharti Nov 21 '16 at 09:00
  • I still can't see, how this could help me in my case. As I switch `Activity`, I don't have a reference to my component anymore, so I can't notify it. The only way would be to pass my component (which is a `View`) to the new `Activity` in a `Bundle`. However, most `View`s should generally not be passed and most of them can't even be serialized (no parameterless constructor)... – Robert P Nov 21 '16 at 10:14
0

Use EventBus here is the link https://github.com/greenrobot/EventBus only 3 steps and yes it is 3rd PartyLibrary. its very light should not affect your app size as well

vijay surya
  • 135
  • 1
  • 6
0

Generally for such scenario I will keep the data in Main Activity as static data and use and update them in other activities.

For example you can declare and populate these 2 variables in Main Activity (i.e. MainActivity)

public static ArrayList arrayList ;

public static SparseBooleanArray sparseBooleanArray ;

now all other activities while populating list values, they can populate from array list using name MainActivity.arrayList. When user select or unselect a value only sparseBooleanArray will be updated with a boolean value.

while populating values first time in arrayList and sparseBooleanArray , ensure to use same index so they will be in sync

arrayList.add(1,"List Item 1") ;

sparseBooleanArray.put(1,false ) ; // represent selected value for List Item 1

In case you have plan to use this functionality for multiple activities, arraylist will remain same, however there will be one SparseBooleanArray for each activity to store activity wise selected values.