5

I am creating a library. It creates an activity, starts it, and finishes it after a button is pressed.

After the button is pressed, I'd like to execute some client code through an interface.

That is, users of this library pass in an implementation, and I simply execute it.

The analogous iOS code would be:

MyViewController *vc = [[MyViewController alloc] init];
vc.callOnComplete = ...
[self presentViewController:vc animated:YES completion:nil];

The desired code is:

public interface SaveStuff {
    void save();
}

In my library's Activity:

private SaveStuff saveStuff;
public void onButtonClicked(View v) {
    saveStuff.save() // client passes in saveStuff obj
    finish();
}

I've tried serialization. I made a class that implemented the interface and also implemented Serializable, and tried passing that in and extracting it with getSerializableExtra. I end up getting a non serializable exception. So far as I know, this is probably not a viable solution, as it would mean that clients must use only serializable classes in their implementations. Correct me if I am wrong on this. In my trials, the client activity was showing up in the non serializable exception.

I've tried using a static reference. Basically global state/singleton. As it turns out, according to a variety of answers such as this one: Java Static Variable becomes null, I cannot rely on any static state, and any solutions that do work with static state are just working coincidently.

I haven't tried simply starting the activity with startActivityForResult, because that would require me to cast the context we are accepting as a parameter to an Activity. The activity is started inside the library with this:

private void startNewActivity(int newVersion) {
    Intent i = new Intent(context, MyActivity.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    context.startActivity(i); // context variable is passed in by the client
}

As you can see, context is passed in by the client. I could perhaps cast the context to an Activity in order to call startActivityForResult, but I don't want to do this, as I have read that is not always safe. I could require that an Activity be passed in. This is perhaps a reasonable requirement, but I don't want to go there just yet.

I've looked at the existing questions and something I haven't tried is using broadcasts. Correct me if I am thinking about this incorrectly, but the best I could do is have the object that holds the reference to client interface implementation be a broadcast receiver, and then send a broadcast in the activity that I create. I am worried that the receiver will not persist, however. What happens if my library shows the user the activity, but then the user kills the app before pressing the button? The reference to the client code was held by the previous activity. Will nothing happen upon pressing the button?

Should I just broadcast a message, and leave it up to the client to handle these cases? How would the client handle this? Register something on app start up/shutdown? Do I have to force the user to do this to use my library? Is it reasonable?

Update:

As it turns out, we are just going to have the activity in the library access a singleton. To avoid all the issues with state being wiped based on activities being killed and the like, users of this library will be required to run a 'setup' method on the singleton, and pass in the callback obj there. They will run this on some sort of base Activity's onResume. I'll wait a little before answering self-answering this question to see if there any alternatives.

Community
  • 1
  • 1
Danedo
  • 2,193
  • 5
  • 29
  • 37
  • Does your library have some sort of public class that they can implement to set a callback in the activity? – tyczj Jul 30 '14 at 14:09
  • 1
    i don't understand at all, so you are creating an Activity and want to call some custom code? so make one method abstract and call it on some event, is it what you want? – pskink Jul 30 '14 at 14:12
  • `that would require me to cast the context we are accepting as a parameter to an Activity` - why are you not using your Activity's own context? – Nachi Jul 30 '14 at 14:35
  • @Nachi This is library code. I don't believe I have any intrinsic context, so I have the client pass it in. As I mentioned, if I am accepting a context, maybe I should just accept an Activity. But what happens if the Activity they pass in is destroyed, in the case that the user kills the app after my library shows its activity? – Danedo Jul 30 '14 at 14:38
  • I don't actually understand what you're trying to do, but if you library shows an activity, then it has a context, the activity itself is a context that you can use. If you want the user of your library to execute some code after you're done they can start your activity for result and when you return a certain result code they can do whatever they want, no point passing you the code and you executing it for them – elmorabea Jul 30 '14 at 15:20

1 Answers1

0

Why don't you use same process for android as well i.e. 1) make an interface 2) declare a public variable of interface in your activity. 3) user will initialize that interface when start to launch your activity. 4) use the interface variable to call the method.

Bhawna Raheja
  • 524
  • 6
  • 9