17

I want to pass an interface from 1st activity to 2nd activity.

I want to initiate methods from the interface from the 2nd activity which will affect the 1st activity.

I'm well aware that it's very overkilling not using the onActivityResult mechanism, and that it might not be good programming, but roll with me please.

Here's the issue - my interface can't implement Serializable / Parcelable since interface can't implement another class.

This is my interface :

public interface ITest {
     void onSuccess(String text);
}

But, i can't start my activity with this interface since it's not Parcelable.

intent.putExtra("testInterface", new ITest() {
    @Override 
    void onSuccess(String text) {
    }
}

Obviously, i receive a compilation error : Cannot resolve method 'putExtra(java.lang.String, ITest)'

Dus
  • 4,052
  • 5
  • 30
  • 49

3 Answers3

23

You cannot "pass an interface". An "interface" is an abstract thing. What you want to pass is a concrete implementation of that interface, ie: an object (that happens to implement your interface). When you instantiate your "interface" (in your example, like this:

intent.putExtra("testInterface", new ITest() {
    @Override 
    void onSuccess(String text) {
    }
}

you are actually creating an instance of an anonymous class that implements the interface ITest. To pass this in an Intent you would need to make this class also implement Parcelable or Serializable.

However, even if you did that, it would not solve your problem. What you need to understand is that you can't pass objects (instances) by putting them as "extras" in an Intent. When you do that, Android actually serializes and then deserializes the object so that you end up with 2 objects, one is a serialized/deserialized copy of the original.

If you want ActivityB to communicate with ActivityA, you will need to use another technique. Try one of these:

  • ActivityB sends a broadcast Intent, which ActivityA listens for
  • ActivityA starts ActivityB using startActivityForResult() and ActivityB sends data back to ActivityA using setResult()
  • Use public static (ie: global) variables to communicate
  • Store data in shared preferences, or a file, or a database

What you really need to understand is that, under certain conditions, the following can occur:

  • your app is running with ActivityA in the stack and ActivityB on the top of the stack
  • user presses HOME
  • Android moves your task to the background and eventually kills the hosting process
  • User returns to your app (by starting it again or selecting it from "recent task" list)
  • Android creates a new process for your app, and instantiates ActivityB, then calls onCreate(), onStart() and onResume() of ActivityB.

In this case, there is no instance of ActivityA anymore. That instance is dead. So ActivityB cannot communicate with ActivityA because it no longer exists.

David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • As i mentioned above, i'd like a different approach than startActivityForResult. Your explanation was quite deep, but still hasn't solved my issue, however - ill give you the acceptance. Thanks ! – Dus Aug 11 '16 at 12:32
  • I gave you several alternatives to `startActivityForResult()`. Maybe you can explain a bit more about what you are trying to do and we can suggest another alternative. – David Wasser Aug 11 '16 at 13:00
  • 1
    Your explanation was good enough... got me thinking that its not really worth the work, and it might be too much of an overkill. – Dus Aug 11 '16 at 13:06
  • 2
    good explanation about the error that using "static" can cause – hasanghaforian Jan 27 '19 at 06:27
1

A similar need sometimes comes up for me when there is no ActivityA around but I still need some code to be executed that ActivityB doesn't know about.

What I will usually do in this case is pass a Messenger in the intent. (A Messenger implements Parcable so it can be passed).

ActivityB will send defined messages to the messenger, And ActivityA will execute the corresponding interface calls when receiving the correct messages.

Vlad
  • 735
  • 2
  • 10
  • 19
0

A simple solution for the problem would be making the interface Itest extend the Parcelable class. That way, the implementing class of the interface will have to implement Parcelable methods, and you can pass the interface reference in putParcelable method. Hope this helps.

gaurav jain
  • 3,119
  • 3
  • 31
  • 48
  • Was thinking about it, but then - you can't pass the interface in writeParcel or readParcel. Seems to be not possible overall. – Dus Aug 11 '16 at 10:21
  • writeToParcel and createFromParcel would need to be implemented by the class implementing 'Itest'. I don't think you manually need to call those methods. So the interface shouldn't create a problem there. – gaurav jain Aug 11 '16 at 10:26