Grant control of Activity UI in SDK2019 Community Moderator ElectionHow do save an Android Activity state using save instance state?Activity restart on rotation AndroidStop EditText from gaining focus at Activity startupHow do I pass data between Activities in Android application?How do I create a transparent Activity on Android?Activity has leaked window that was originally addedAndroid SDK installation doesn't find JDKWhen exactly is it leak safe to use (anonymous) inner classes?You need to use a Theme.AppCompat theme (or descendant) with this activityWhat's the enhancement of AppCompatActivity over ActionBarActivity?

Single word to change groups

Do people actually use the word "kaputt" in conversation?

Can "few" be used as a subject? If so, what is the rule?

Determine voltage drop over 10G resistors with cheap multimeter

10 year ban after applying for a UK student visa

Do I need an EFI partition for each 18.04 ubuntu I have on my HD?

How can I create URL shortcuts/redirects for task/diff IDs in Phabricator?

Jem'Hadar, something strange about their life expectancy

label a part of commutative diagram

Why is "la Gestapo" feminine?

Is there any common country to visit for uk and schengen visa?

Someone scrambled my calling sign- who am I?

Justification failure in beamer enumerate list

Why is participating in the European Parliamentary elections used as a threat?

Recursively updating the MLE as new observations stream in

Does the Shadow Magic sorcerer's Eyes of the Dark feature work on all Darkness spells or just his/her own?

Why do I have a large white artefact on the rendered image?

How to read string as hex number in bash?

When did hardware antialiasing start being available?

Can other pieces capture a threatening piece and prevent a checkmate?

Why is indicated airspeed rather than ground speed used during the takeoff roll?

Is xar preinstalled on macOS?

Should a narrator ever describe things based on a characters view instead of fact?

pipe commands inside find -exec?



Grant control of Activity UI in SDK



2019 Community Moderator ElectionHow do save an Android Activity state using save instance state?Activity restart on rotation AndroidStop EditText from gaining focus at Activity startupHow do I pass data between Activities in Android application?How do I create a transparent Activity on Android?Activity has leaked window that was originally addedAndroid SDK installation doesn't find JDKWhen exactly is it leak safe to use (anonymous) inner classes?You need to use a Theme.AppCompat theme (or descendant) with this activityWhat's the enhancement of AppCompatActivity over ActionBarActivity?










1















Currently we're making an Android library that contains an Activity. We want to control the exact flow and the state of the activity, but give the user that implements the library control what the UI looks like. Meanwhile, we want to expose the least amount of internal classes.



The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.



The activity makes use of a Model-View-Intent pattern, so we want to expose the immutable state. Without adjustable UI, the Activity and all its' classes are internal. With adjustable UI, a lot more classes have to made public. This increases the risk of breaking changes on updates and exposes our logic.



To expose the UI, several solution were thought of:



  • Having a static callback on the activity that calls onCreate(), so setContentView() can be set, and calls render(state: State) on every state change. Our classes are shielded as we like, but using a static for this is questionable.


  • Make the Activity open, so sdk users can subclass it. This means that every class used by the activity, has to be changed from internal to public.The classes which actually should be internal, will be hidden by obfuscating them with ProGuard.


  • It would be the nicest to pass a function in the Intent, which to my knowlegde is not possible.


  • Pass a POJO were we define parameters such as background color, which is the most restricting to the sdk user and is not in consideration.


Which solution is the best? Is there another method than the ones we thought of?










share|improve this question
























  • give the user that implements the library control what the UI looks like Can you expose everything you need using a theme?

    – Eugen Pechanec
    Mar 7 at 10:35











  • Unfortunately not. Sdk users want to use custom views and they are allowed to additional views and control them themself. Additionally, some want to add animations too.

    – Michiel
    Mar 7 at 10:39











  • It would be the nicest to pass a function in the Intent As long as your SDK activity lives in the same process as the calling code you can store the function body in a static hash map by a generated string key, pass that key in an intent (effectively a pointer to function), and have that unpacked and executed by your activity. The static hash map is a hidden implementation detail. I don't think it necessarily a best practice, your users may or may not run into memory leaks... Just an idea. And it won't work across processes which are controlled by consumer.

    – Eugen Pechanec
    Mar 7 at 10:54











  • What if you pass a class name via intent, that class has a well-known constructor and implements an interface. Your activity will then construct an instance of said class and execute whatever methods you need whenever you need them. This doesn't leak memory and can work across processes if the consumer supports it - it's not prohibited by design as in my previous example.

    – Eugen Pechanec
    Mar 7 at 10:57











  • I implemented the static hash map, which works and what I like the most. My co-worker is in favor of letting the SDK user extend our activity, which is according to him easier to use for the SDK user and less prone to memory leaks. On creating the class via reflection: I don't like to restrict the sdk user to the only parameters I can think off

    – Michiel
    Mar 7 at 13:51















1















Currently we're making an Android library that contains an Activity. We want to control the exact flow and the state of the activity, but give the user that implements the library control what the UI looks like. Meanwhile, we want to expose the least amount of internal classes.



The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.



The activity makes use of a Model-View-Intent pattern, so we want to expose the immutable state. Without adjustable UI, the Activity and all its' classes are internal. With adjustable UI, a lot more classes have to made public. This increases the risk of breaking changes on updates and exposes our logic.



To expose the UI, several solution were thought of:



  • Having a static callback on the activity that calls onCreate(), so setContentView() can be set, and calls render(state: State) on every state change. Our classes are shielded as we like, but using a static for this is questionable.


  • Make the Activity open, so sdk users can subclass it. This means that every class used by the activity, has to be changed from internal to public.The classes which actually should be internal, will be hidden by obfuscating them with ProGuard.


  • It would be the nicest to pass a function in the Intent, which to my knowlegde is not possible.


  • Pass a POJO were we define parameters such as background color, which is the most restricting to the sdk user and is not in consideration.


Which solution is the best? Is there another method than the ones we thought of?










share|improve this question
























  • give the user that implements the library control what the UI looks like Can you expose everything you need using a theme?

    – Eugen Pechanec
    Mar 7 at 10:35











  • Unfortunately not. Sdk users want to use custom views and they are allowed to additional views and control them themself. Additionally, some want to add animations too.

    – Michiel
    Mar 7 at 10:39











  • It would be the nicest to pass a function in the Intent As long as your SDK activity lives in the same process as the calling code you can store the function body in a static hash map by a generated string key, pass that key in an intent (effectively a pointer to function), and have that unpacked and executed by your activity. The static hash map is a hidden implementation detail. I don't think it necessarily a best practice, your users may or may not run into memory leaks... Just an idea. And it won't work across processes which are controlled by consumer.

    – Eugen Pechanec
    Mar 7 at 10:54











  • What if you pass a class name via intent, that class has a well-known constructor and implements an interface. Your activity will then construct an instance of said class and execute whatever methods you need whenever you need them. This doesn't leak memory and can work across processes if the consumer supports it - it's not prohibited by design as in my previous example.

    – Eugen Pechanec
    Mar 7 at 10:57











  • I implemented the static hash map, which works and what I like the most. My co-worker is in favor of letting the SDK user extend our activity, which is according to him easier to use for the SDK user and less prone to memory leaks. On creating the class via reflection: I don't like to restrict the sdk user to the only parameters I can think off

    – Michiel
    Mar 7 at 13:51













1












1








1


1






Currently we're making an Android library that contains an Activity. We want to control the exact flow and the state of the activity, but give the user that implements the library control what the UI looks like. Meanwhile, we want to expose the least amount of internal classes.



The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.



The activity makes use of a Model-View-Intent pattern, so we want to expose the immutable state. Without adjustable UI, the Activity and all its' classes are internal. With adjustable UI, a lot more classes have to made public. This increases the risk of breaking changes on updates and exposes our logic.



To expose the UI, several solution were thought of:



  • Having a static callback on the activity that calls onCreate(), so setContentView() can be set, and calls render(state: State) on every state change. Our classes are shielded as we like, but using a static for this is questionable.


  • Make the Activity open, so sdk users can subclass it. This means that every class used by the activity, has to be changed from internal to public.The classes which actually should be internal, will be hidden by obfuscating them with ProGuard.


  • It would be the nicest to pass a function in the Intent, which to my knowlegde is not possible.


  • Pass a POJO were we define parameters such as background color, which is the most restricting to the sdk user and is not in consideration.


Which solution is the best? Is there another method than the ones we thought of?










share|improve this question
















Currently we're making an Android library that contains an Activity. We want to control the exact flow and the state of the activity, but give the user that implements the library control what the UI looks like. Meanwhile, we want to expose the least amount of internal classes.



The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.



The activity makes use of a Model-View-Intent pattern, so we want to expose the immutable state. Without adjustable UI, the Activity and all its' classes are internal. With adjustable UI, a lot more classes have to made public. This increases the risk of breaking changes on updates and exposes our logic.



To expose the UI, several solution were thought of:



  • Having a static callback on the activity that calls onCreate(), so setContentView() can be set, and calls render(state: State) on every state change. Our classes are shielded as we like, but using a static for this is questionable.


  • Make the Activity open, so sdk users can subclass it. This means that every class used by the activity, has to be changed from internal to public.The classes which actually should be internal, will be hidden by obfuscating them with ProGuard.


  • It would be the nicest to pass a function in the Intent, which to my knowlegde is not possible.


  • Pass a POJO were we define parameters such as background color, which is the most restricting to the sdk user and is not in consideration.


Which solution is the best? Is there another method than the ones we thought of?







android kotlin aar






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 7 at 10:35







Michiel

















asked Mar 7 at 10:29









MichielMichiel

206




206












  • give the user that implements the library control what the UI looks like Can you expose everything you need using a theme?

    – Eugen Pechanec
    Mar 7 at 10:35











  • Unfortunately not. Sdk users want to use custom views and they are allowed to additional views and control them themself. Additionally, some want to add animations too.

    – Michiel
    Mar 7 at 10:39











  • It would be the nicest to pass a function in the Intent As long as your SDK activity lives in the same process as the calling code you can store the function body in a static hash map by a generated string key, pass that key in an intent (effectively a pointer to function), and have that unpacked and executed by your activity. The static hash map is a hidden implementation detail. I don't think it necessarily a best practice, your users may or may not run into memory leaks... Just an idea. And it won't work across processes which are controlled by consumer.

    – Eugen Pechanec
    Mar 7 at 10:54











  • What if you pass a class name via intent, that class has a well-known constructor and implements an interface. Your activity will then construct an instance of said class and execute whatever methods you need whenever you need them. This doesn't leak memory and can work across processes if the consumer supports it - it's not prohibited by design as in my previous example.

    – Eugen Pechanec
    Mar 7 at 10:57











  • I implemented the static hash map, which works and what I like the most. My co-worker is in favor of letting the SDK user extend our activity, which is according to him easier to use for the SDK user and less prone to memory leaks. On creating the class via reflection: I don't like to restrict the sdk user to the only parameters I can think off

    – Michiel
    Mar 7 at 13:51

















  • give the user that implements the library control what the UI looks like Can you expose everything you need using a theme?

    – Eugen Pechanec
    Mar 7 at 10:35











  • Unfortunately not. Sdk users want to use custom views and they are allowed to additional views and control them themself. Additionally, some want to add animations too.

    – Michiel
    Mar 7 at 10:39











  • It would be the nicest to pass a function in the Intent As long as your SDK activity lives in the same process as the calling code you can store the function body in a static hash map by a generated string key, pass that key in an intent (effectively a pointer to function), and have that unpacked and executed by your activity. The static hash map is a hidden implementation detail. I don't think it necessarily a best practice, your users may or may not run into memory leaks... Just an idea. And it won't work across processes which are controlled by consumer.

    – Eugen Pechanec
    Mar 7 at 10:54











  • What if you pass a class name via intent, that class has a well-known constructor and implements an interface. Your activity will then construct an instance of said class and execute whatever methods you need whenever you need them. This doesn't leak memory and can work across processes if the consumer supports it - it's not prohibited by design as in my previous example.

    – Eugen Pechanec
    Mar 7 at 10:57











  • I implemented the static hash map, which works and what I like the most. My co-worker is in favor of letting the SDK user extend our activity, which is according to him easier to use for the SDK user and less prone to memory leaks. On creating the class via reflection: I don't like to restrict the sdk user to the only parameters I can think off

    – Michiel
    Mar 7 at 13:51
















give the user that implements the library control what the UI looks like Can you expose everything you need using a theme?

– Eugen Pechanec
Mar 7 at 10:35





give the user that implements the library control what the UI looks like Can you expose everything you need using a theme?

– Eugen Pechanec
Mar 7 at 10:35













Unfortunately not. Sdk users want to use custom views and they are allowed to additional views and control them themself. Additionally, some want to add animations too.

– Michiel
Mar 7 at 10:39





Unfortunately not. Sdk users want to use custom views and they are allowed to additional views and control them themself. Additionally, some want to add animations too.

– Michiel
Mar 7 at 10:39













It would be the nicest to pass a function in the Intent As long as your SDK activity lives in the same process as the calling code you can store the function body in a static hash map by a generated string key, pass that key in an intent (effectively a pointer to function), and have that unpacked and executed by your activity. The static hash map is a hidden implementation detail. I don't think it necessarily a best practice, your users may or may not run into memory leaks... Just an idea. And it won't work across processes which are controlled by consumer.

– Eugen Pechanec
Mar 7 at 10:54





It would be the nicest to pass a function in the Intent As long as your SDK activity lives in the same process as the calling code you can store the function body in a static hash map by a generated string key, pass that key in an intent (effectively a pointer to function), and have that unpacked and executed by your activity. The static hash map is a hidden implementation detail. I don't think it necessarily a best practice, your users may or may not run into memory leaks... Just an idea. And it won't work across processes which are controlled by consumer.

– Eugen Pechanec
Mar 7 at 10:54













What if you pass a class name via intent, that class has a well-known constructor and implements an interface. Your activity will then construct an instance of said class and execute whatever methods you need whenever you need them. This doesn't leak memory and can work across processes if the consumer supports it - it's not prohibited by design as in my previous example.

– Eugen Pechanec
Mar 7 at 10:57





What if you pass a class name via intent, that class has a well-known constructor and implements an interface. Your activity will then construct an instance of said class and execute whatever methods you need whenever you need them. This doesn't leak memory and can work across processes if the consumer supports it - it's not prohibited by design as in my previous example.

– Eugen Pechanec
Mar 7 at 10:57













I implemented the static hash map, which works and what I like the most. My co-worker is in favor of letting the SDK user extend our activity, which is according to him easier to use for the SDK user and less prone to memory leaks. On creating the class via reflection: I don't like to restrict the sdk user to the only parameters I can think off

– Michiel
Mar 7 at 13:51





I implemented the static hash map, which works and what I like the most. My co-worker is in favor of letting the SDK user extend our activity, which is according to him easier to use for the SDK user and less prone to memory leaks. On creating the class via reflection: I don't like to restrict the sdk user to the only parameters I can think off

– Michiel
Mar 7 at 13:51












1 Answer
1






active

oldest

votes


















0















The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.




I picture this like so:



  • Your consumer receives a State, a ViewGroup, and an Actions object, which I'll explain later.

  • Based on State the consumer is required to create several views and place them as they wish within supplied ViewGroup.

  • The consumer is also required to register above views using some Actions.register*Button methods.

  • The above logic is executed inside one callback method. Once said method finished your SDK will verify correctness (all required actions are assigned a clickable view) and proceed.

Now, how to pass this callback method to sour SDK?



1.




It would be the nicest to pass a function in the Intent




This is actually possible with relative ease (and, IMO, some severe drawbacks).



In your SDK create a static Map<Key, Callback> sCallbacks. When your consumer registers the callback using your API, you'll generate a lookup key for it and store it within the map. You can pass the key around as an Intent extra. Once your SDK activity is opened it can lookup the callback using the key from its intent.



The key can be a String or UUID or whatever fits your needs and can be put inside an intent.



Pros:



  • It's deceptively easy to implement and use.

  • The consumer can use your SDK from just one file. All the calling code is in one place.

Cons:



  • You're not in charge where the callback is created. The consumer may create it as an anonymous class inside an Activity, which results in a memory leak.

  • You lose the callback map when process dies. If the app is killed while in your SDK activity you need to gracefully handle it when the app is restarted.

  • Variables are not shared across multiple processes. If your SDK activity and the calling code are not in the same process, your SDK activity will not be able to find the callback. Remember that the consumer is free to change process for their activities and even override your own activity process.

The calling point would look something like startSdk(context) state, parent, actions -> /* ... */ .



This is by far the most comfortable method for the consumer, yet the weaknesses start to show once you leave the area of a typical consumer setup.



2.




Make the Activity open, so sdk users can subclass it.




As you explained this is not possible without making compromies on your end.



Pros: ?



Cons:



  • The consumer needs to register their subclass and unregister your original SDK activity in AndroidManifest.xml. I'm assuming the manifest merger is enabled. This is a pain, as I often forget to look here.

  • The consumer gets easy access to your activity and is free to break it as they please.

  • Unless your documentation is pristine, the consumer will have a hard time figuring out what to override in your activity.

The calling point would look something like startSdk<MySdkActivity>(context).



I really don't understand the benefits of this option, as a consumer. I lose the benefits of #1 and gain nothing in return. As a developer I can't sanction this 'let the consumer deal with it' attitude. They will break things, you'll get bug reports and you will have to handle it eventually.



3.



Here I'll try to expand on the idea mentioned first in comments.



The callback would an abstract class defined by your SDK. It would be used as follows:



  • The consumer extends this class and defines the callback body. The class needs to have an empty constructor and be static. Typically it would be defined in its own file.

  • The class name is passed in an intent to your SDK activity.

  • Your SDK activity reflectively creates an instance of the callback.

The callback class could have several methods, one could set up menu, one could setup only view hierarchy, one would get the whole activity as parameter. The consumer would pick the one they need. Again, this needs to be documented well if there are multiple options.



Pros:



  • You separate the callback from the call site (where your SDK is called from). This is good, because the callback is executed inside your activity, completely separated from calling code.

  • As a result you can't leak the calling activity.

  • The consumer doesn't need to touch AndroidManifest.xml. This is great because registering your callback has nothing to do with Android. The manifest is mainly for things that the system interacts with.

  • The callback is easily recreated after process death. It has no constructor parameters and it's stateless.

  • It works across multiple processes. If, by any chance, the consumer needs to communicate across processes they're in charge of how they achieve that. Your SDK is not making it impossible as in case #2.

  • You get to keep your classes internal.

Cons:



  • You have to bundle a proguard rule to keep the empty constructor of each class extending the abstract callback class. You also need to keep their class names.

I'm assuming you'll hide the intent passing as an implementation detail so the entry point could look something like startSdk<MyCallback>(context).



I like this one because it shifts all possible responsibilities from the consumer to you, the SDK developer. You make it hard for the consumer to use the API wrong. You shield the consumer from potential errors.



Now back to the first paragraph. As long as the consumer can get their hands on a context (ViewGroup.getContext()) they're able to access the activity and the application (in that process). If both the calling activity and your SDK activity live in the same process the consumer could even access their prepared Dagger component. But they don't get to override your activity methods in unexpected ways.






share|improve this answer






















    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55041556%2fgrant-control-of-activity-ui-in-sdk%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0















    The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.




    I picture this like so:



    • Your consumer receives a State, a ViewGroup, and an Actions object, which I'll explain later.

    • Based on State the consumer is required to create several views and place them as they wish within supplied ViewGroup.

    • The consumer is also required to register above views using some Actions.register*Button methods.

    • The above logic is executed inside one callback method. Once said method finished your SDK will verify correctness (all required actions are assigned a clickable view) and proceed.

    Now, how to pass this callback method to sour SDK?



    1.




    It would be the nicest to pass a function in the Intent




    This is actually possible with relative ease (and, IMO, some severe drawbacks).



    In your SDK create a static Map<Key, Callback> sCallbacks. When your consumer registers the callback using your API, you'll generate a lookup key for it and store it within the map. You can pass the key around as an Intent extra. Once your SDK activity is opened it can lookup the callback using the key from its intent.



    The key can be a String or UUID or whatever fits your needs and can be put inside an intent.



    Pros:



    • It's deceptively easy to implement and use.

    • The consumer can use your SDK from just one file. All the calling code is in one place.

    Cons:



    • You're not in charge where the callback is created. The consumer may create it as an anonymous class inside an Activity, which results in a memory leak.

    • You lose the callback map when process dies. If the app is killed while in your SDK activity you need to gracefully handle it when the app is restarted.

    • Variables are not shared across multiple processes. If your SDK activity and the calling code are not in the same process, your SDK activity will not be able to find the callback. Remember that the consumer is free to change process for their activities and even override your own activity process.

    The calling point would look something like startSdk(context) state, parent, actions -> /* ... */ .



    This is by far the most comfortable method for the consumer, yet the weaknesses start to show once you leave the area of a typical consumer setup.



    2.




    Make the Activity open, so sdk users can subclass it.




    As you explained this is not possible without making compromies on your end.



    Pros: ?



    Cons:



    • The consumer needs to register their subclass and unregister your original SDK activity in AndroidManifest.xml. I'm assuming the manifest merger is enabled. This is a pain, as I often forget to look here.

    • The consumer gets easy access to your activity and is free to break it as they please.

    • Unless your documentation is pristine, the consumer will have a hard time figuring out what to override in your activity.

    The calling point would look something like startSdk<MySdkActivity>(context).



    I really don't understand the benefits of this option, as a consumer. I lose the benefits of #1 and gain nothing in return. As a developer I can't sanction this 'let the consumer deal with it' attitude. They will break things, you'll get bug reports and you will have to handle it eventually.



    3.



    Here I'll try to expand on the idea mentioned first in comments.



    The callback would an abstract class defined by your SDK. It would be used as follows:



    • The consumer extends this class and defines the callback body. The class needs to have an empty constructor and be static. Typically it would be defined in its own file.

    • The class name is passed in an intent to your SDK activity.

    • Your SDK activity reflectively creates an instance of the callback.

    The callback class could have several methods, one could set up menu, one could setup only view hierarchy, one would get the whole activity as parameter. The consumer would pick the one they need. Again, this needs to be documented well if there are multiple options.



    Pros:



    • You separate the callback from the call site (where your SDK is called from). This is good, because the callback is executed inside your activity, completely separated from calling code.

    • As a result you can't leak the calling activity.

    • The consumer doesn't need to touch AndroidManifest.xml. This is great because registering your callback has nothing to do with Android. The manifest is mainly for things that the system interacts with.

    • The callback is easily recreated after process death. It has no constructor parameters and it's stateless.

    • It works across multiple processes. If, by any chance, the consumer needs to communicate across processes they're in charge of how they achieve that. Your SDK is not making it impossible as in case #2.

    • You get to keep your classes internal.

    Cons:



    • You have to bundle a proguard rule to keep the empty constructor of each class extending the abstract callback class. You also need to keep their class names.

    I'm assuming you'll hide the intent passing as an implementation detail so the entry point could look something like startSdk<MyCallback>(context).



    I like this one because it shifts all possible responsibilities from the consumer to you, the SDK developer. You make it hard for the consumer to use the API wrong. You shield the consumer from potential errors.



    Now back to the first paragraph. As long as the consumer can get their hands on a context (ViewGroup.getContext()) they're able to access the activity and the application (in that process). If both the calling activity and your SDK activity live in the same process the consumer could even access their prepared Dagger component. But they don't get to override your activity methods in unexpected ways.






    share|improve this answer



























      0















      The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.




      I picture this like so:



      • Your consumer receives a State, a ViewGroup, and an Actions object, which I'll explain later.

      • Based on State the consumer is required to create several views and place them as they wish within supplied ViewGroup.

      • The consumer is also required to register above views using some Actions.register*Button methods.

      • The above logic is executed inside one callback method. Once said method finished your SDK will verify correctness (all required actions are assigned a clickable view) and proceed.

      Now, how to pass this callback method to sour SDK?



      1.




      It would be the nicest to pass a function in the Intent




      This is actually possible with relative ease (and, IMO, some severe drawbacks).



      In your SDK create a static Map<Key, Callback> sCallbacks. When your consumer registers the callback using your API, you'll generate a lookup key for it and store it within the map. You can pass the key around as an Intent extra. Once your SDK activity is opened it can lookup the callback using the key from its intent.



      The key can be a String or UUID or whatever fits your needs and can be put inside an intent.



      Pros:



      • It's deceptively easy to implement and use.

      • The consumer can use your SDK from just one file. All the calling code is in one place.

      Cons:



      • You're not in charge where the callback is created. The consumer may create it as an anonymous class inside an Activity, which results in a memory leak.

      • You lose the callback map when process dies. If the app is killed while in your SDK activity you need to gracefully handle it when the app is restarted.

      • Variables are not shared across multiple processes. If your SDK activity and the calling code are not in the same process, your SDK activity will not be able to find the callback. Remember that the consumer is free to change process for their activities and even override your own activity process.

      The calling point would look something like startSdk(context) state, parent, actions -> /* ... */ .



      This is by far the most comfortable method for the consumer, yet the weaknesses start to show once you leave the area of a typical consumer setup.



      2.




      Make the Activity open, so sdk users can subclass it.




      As you explained this is not possible without making compromies on your end.



      Pros: ?



      Cons:



      • The consumer needs to register their subclass and unregister your original SDK activity in AndroidManifest.xml. I'm assuming the manifest merger is enabled. This is a pain, as I often forget to look here.

      • The consumer gets easy access to your activity and is free to break it as they please.

      • Unless your documentation is pristine, the consumer will have a hard time figuring out what to override in your activity.

      The calling point would look something like startSdk<MySdkActivity>(context).



      I really don't understand the benefits of this option, as a consumer. I lose the benefits of #1 and gain nothing in return. As a developer I can't sanction this 'let the consumer deal with it' attitude. They will break things, you'll get bug reports and you will have to handle it eventually.



      3.



      Here I'll try to expand on the idea mentioned first in comments.



      The callback would an abstract class defined by your SDK. It would be used as follows:



      • The consumer extends this class and defines the callback body. The class needs to have an empty constructor and be static. Typically it would be defined in its own file.

      • The class name is passed in an intent to your SDK activity.

      • Your SDK activity reflectively creates an instance of the callback.

      The callback class could have several methods, one could set up menu, one could setup only view hierarchy, one would get the whole activity as parameter. The consumer would pick the one they need. Again, this needs to be documented well if there are multiple options.



      Pros:



      • You separate the callback from the call site (where your SDK is called from). This is good, because the callback is executed inside your activity, completely separated from calling code.

      • As a result you can't leak the calling activity.

      • The consumer doesn't need to touch AndroidManifest.xml. This is great because registering your callback has nothing to do with Android. The manifest is mainly for things that the system interacts with.

      • The callback is easily recreated after process death. It has no constructor parameters and it's stateless.

      • It works across multiple processes. If, by any chance, the consumer needs to communicate across processes they're in charge of how they achieve that. Your SDK is not making it impossible as in case #2.

      • You get to keep your classes internal.

      Cons:



      • You have to bundle a proguard rule to keep the empty constructor of each class extending the abstract callback class. You also need to keep their class names.

      I'm assuming you'll hide the intent passing as an implementation detail so the entry point could look something like startSdk<MyCallback>(context).



      I like this one because it shifts all possible responsibilities from the consumer to you, the SDK developer. You make it hard for the consumer to use the API wrong. You shield the consumer from potential errors.



      Now back to the first paragraph. As long as the consumer can get their hands on a context (ViewGroup.getContext()) they're able to access the activity and the application (in that process). If both the calling activity and your SDK activity live in the same process the consumer could even access their prepared Dagger component. But they don't get to override your activity methods in unexpected ways.






      share|improve this answer

























        0












        0








        0








        The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.




        I picture this like so:



        • Your consumer receives a State, a ViewGroup, and an Actions object, which I'll explain later.

        • Based on State the consumer is required to create several views and place them as they wish within supplied ViewGroup.

        • The consumer is also required to register above views using some Actions.register*Button methods.

        • The above logic is executed inside one callback method. Once said method finished your SDK will verify correctness (all required actions are assigned a clickable view) and proceed.

        Now, how to pass this callback method to sour SDK?



        1.




        It would be the nicest to pass a function in the Intent




        This is actually possible with relative ease (and, IMO, some severe drawbacks).



        In your SDK create a static Map<Key, Callback> sCallbacks. When your consumer registers the callback using your API, you'll generate a lookup key for it and store it within the map. You can pass the key around as an Intent extra. Once your SDK activity is opened it can lookup the callback using the key from its intent.



        The key can be a String or UUID or whatever fits your needs and can be put inside an intent.



        Pros:



        • It's deceptively easy to implement and use.

        • The consumer can use your SDK from just one file. All the calling code is in one place.

        Cons:



        • You're not in charge where the callback is created. The consumer may create it as an anonymous class inside an Activity, which results in a memory leak.

        • You lose the callback map when process dies. If the app is killed while in your SDK activity you need to gracefully handle it when the app is restarted.

        • Variables are not shared across multiple processes. If your SDK activity and the calling code are not in the same process, your SDK activity will not be able to find the callback. Remember that the consumer is free to change process for their activities and even override your own activity process.

        The calling point would look something like startSdk(context) state, parent, actions -> /* ... */ .



        This is by far the most comfortable method for the consumer, yet the weaknesses start to show once you leave the area of a typical consumer setup.



        2.




        Make the Activity open, so sdk users can subclass it.




        As you explained this is not possible without making compromies on your end.



        Pros: ?



        Cons:



        • The consumer needs to register their subclass and unregister your original SDK activity in AndroidManifest.xml. I'm assuming the manifest merger is enabled. This is a pain, as I often forget to look here.

        • The consumer gets easy access to your activity and is free to break it as they please.

        • Unless your documentation is pristine, the consumer will have a hard time figuring out what to override in your activity.

        The calling point would look something like startSdk<MySdkActivity>(context).



        I really don't understand the benefits of this option, as a consumer. I lose the benefits of #1 and gain nothing in return. As a developer I can't sanction this 'let the consumer deal with it' attitude. They will break things, you'll get bug reports and you will have to handle it eventually.



        3.



        Here I'll try to expand on the idea mentioned first in comments.



        The callback would an abstract class defined by your SDK. It would be used as follows:



        • The consumer extends this class and defines the callback body. The class needs to have an empty constructor and be static. Typically it would be defined in its own file.

        • The class name is passed in an intent to your SDK activity.

        • Your SDK activity reflectively creates an instance of the callback.

        The callback class could have several methods, one could set up menu, one could setup only view hierarchy, one would get the whole activity as parameter. The consumer would pick the one they need. Again, this needs to be documented well if there are multiple options.



        Pros:



        • You separate the callback from the call site (where your SDK is called from). This is good, because the callback is executed inside your activity, completely separated from calling code.

        • As a result you can't leak the calling activity.

        • The consumer doesn't need to touch AndroidManifest.xml. This is great because registering your callback has nothing to do with Android. The manifest is mainly for things that the system interacts with.

        • The callback is easily recreated after process death. It has no constructor parameters and it's stateless.

        • It works across multiple processes. If, by any chance, the consumer needs to communicate across processes they're in charge of how they achieve that. Your SDK is not making it impossible as in case #2.

        • You get to keep your classes internal.

        Cons:



        • You have to bundle a proguard rule to keep the empty constructor of each class extending the abstract callback class. You also need to keep their class names.

        I'm assuming you'll hide the intent passing as an implementation detail so the entry point could look something like startSdk<MyCallback>(context).



        I like this one because it shifts all possible responsibilities from the consumer to you, the SDK developer. You make it hard for the consumer to use the API wrong. You shield the consumer from potential errors.



        Now back to the first paragraph. As long as the consumer can get their hands on a context (ViewGroup.getContext()) they're able to access the activity and the application (in that process). If both the calling activity and your SDK activity live in the same process the consumer could even access their prepared Dagger component. But they don't get to override your activity methods in unexpected ways.






        share|improve this answer














        The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.




        I picture this like so:



        • Your consumer receives a State, a ViewGroup, and an Actions object, which I'll explain later.

        • Based on State the consumer is required to create several views and place them as they wish within supplied ViewGroup.

        • The consumer is also required to register above views using some Actions.register*Button methods.

        • The above logic is executed inside one callback method. Once said method finished your SDK will verify correctness (all required actions are assigned a clickable view) and proceed.

        Now, how to pass this callback method to sour SDK?



        1.




        It would be the nicest to pass a function in the Intent




        This is actually possible with relative ease (and, IMO, some severe drawbacks).



        In your SDK create a static Map<Key, Callback> sCallbacks. When your consumer registers the callback using your API, you'll generate a lookup key for it and store it within the map. You can pass the key around as an Intent extra. Once your SDK activity is opened it can lookup the callback using the key from its intent.



        The key can be a String or UUID or whatever fits your needs and can be put inside an intent.



        Pros:



        • It's deceptively easy to implement and use.

        • The consumer can use your SDK from just one file. All the calling code is in one place.

        Cons:



        • You're not in charge where the callback is created. The consumer may create it as an anonymous class inside an Activity, which results in a memory leak.

        • You lose the callback map when process dies. If the app is killed while in your SDK activity you need to gracefully handle it when the app is restarted.

        • Variables are not shared across multiple processes. If your SDK activity and the calling code are not in the same process, your SDK activity will not be able to find the callback. Remember that the consumer is free to change process for their activities and even override your own activity process.

        The calling point would look something like startSdk(context) state, parent, actions -> /* ... */ .



        This is by far the most comfortable method for the consumer, yet the weaknesses start to show once you leave the area of a typical consumer setup.



        2.




        Make the Activity open, so sdk users can subclass it.




        As you explained this is not possible without making compromies on your end.



        Pros: ?



        Cons:



        • The consumer needs to register their subclass and unregister your original SDK activity in AndroidManifest.xml. I'm assuming the manifest merger is enabled. This is a pain, as I often forget to look here.

        • The consumer gets easy access to your activity and is free to break it as they please.

        • Unless your documentation is pristine, the consumer will have a hard time figuring out what to override in your activity.

        The calling point would look something like startSdk<MySdkActivity>(context).



        I really don't understand the benefits of this option, as a consumer. I lose the benefits of #1 and gain nothing in return. As a developer I can't sanction this 'let the consumer deal with it' attitude. They will break things, you'll get bug reports and you will have to handle it eventually.



        3.



        Here I'll try to expand on the idea mentioned first in comments.



        The callback would an abstract class defined by your SDK. It would be used as follows:



        • The consumer extends this class and defines the callback body. The class needs to have an empty constructor and be static. Typically it would be defined in its own file.

        • The class name is passed in an intent to your SDK activity.

        • Your SDK activity reflectively creates an instance of the callback.

        The callback class could have several methods, one could set up menu, one could setup only view hierarchy, one would get the whole activity as parameter. The consumer would pick the one they need. Again, this needs to be documented well if there are multiple options.



        Pros:



        • You separate the callback from the call site (where your SDK is called from). This is good, because the callback is executed inside your activity, completely separated from calling code.

        • As a result you can't leak the calling activity.

        • The consumer doesn't need to touch AndroidManifest.xml. This is great because registering your callback has nothing to do with Android. The manifest is mainly for things that the system interacts with.

        • The callback is easily recreated after process death. It has no constructor parameters and it's stateless.

        • It works across multiple processes. If, by any chance, the consumer needs to communicate across processes they're in charge of how they achieve that. Your SDK is not making it impossible as in case #2.

        • You get to keep your classes internal.

        Cons:



        • You have to bundle a proguard rule to keep the empty constructor of each class extending the abstract callback class. You also need to keep their class names.

        I'm assuming you'll hide the intent passing as an implementation detail so the entry point could look something like startSdk<MyCallback>(context).



        I like this one because it shifts all possible responsibilities from the consumer to you, the SDK developer. You make it hard for the consumer to use the API wrong. You shield the consumer from potential errors.



        Now back to the first paragraph. As long as the consumer can get their hands on a context (ViewGroup.getContext()) they're able to access the activity and the application (in that process). If both the calling activity and your SDK activity live in the same process the consumer could even access their prepared Dagger component. But they don't get to override your activity methods in unexpected ways.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Mar 7 at 18:32









        Eugen PechanecEugen Pechanec

        27.2k77192




        27.2k77192





























            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55041556%2fgrant-control-of-activity-ui-in-sdk%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to get text form Clipboard with JavaScript in Firefox 56?How to validate an email address in JavaScript?How do JavaScript closures work?How do I remove a property from a JavaScript object?How do you get a timestamp in JavaScript?How do I copy to the clipboard in JavaScript?How do I include a JavaScript file in another JavaScript file?Get the current URL with JavaScript?How to replace all occurrences of a string in JavaScriptHow to check whether a string contains a substring in JavaScript?How do I remove a particular element from an array in JavaScript?

            Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme

            List of MPs elected to the English parliament in 1640 (April) Contents List of constituencies and members See also Notes References Navigation menueNational Archives – The Glynde Place ArchivesCobbett's Parliamentary history of England, from the Norman Conquest in 1066 to the year 1803'Aldermen in Parliament', The Aldermen of the City of London: Temp. Henry III – 1912onepage&q&f&#61, false 229