Android: Passing same variable between 3 activities? - java

So I have a (Kotlin) data class that gets instantiated in my startup activity (we'll just call the object dataObj). I have two other activities that need access to the dataObj that was instantiated on startup. I know I could have my data class implement the Serializable interface so that I could pass the object between the three activities using intents. But I also have been thinking that I could use a static variable in the constructor so that I could easily just grab the values for the class. I'm just trying to figure out what is recommended and what is good practice.

It really depends on your use case, but I'd generally recommend against static implementations (to include singletons, see What is so bad about singletons?). They become hard to test adequately over time and can (in short) lead to many other problems depending on implementation.
If it is a relatively simple object where state change is rare, only done in one Activity at a time, and/or irrelevant, implementing a Parcelable and passing that to each Activity via an Intent is probably best.
If this is a complex object or an object that can change dynamically, the preferable solution would be to use a dependency injection platform (such as Koin if you're using Kotlin) to instantiate the data and provide it as a dependency. Koin is pretty straight forward, a very basic implementation from the Koin website (and missing just a few lines to be complete):
// Injected by constructor
class MyViewModel(val repo : MyRepository) : ViewModel()
// declared ViewModel using the viewModel keyword
val myModule : Module = module {
viewModel { MyViewModel(get()) }
single { MyRepository() }
}
// Just get it
class MyActivity() : AppCompatActivity() {
// lazy inject MyViewModel
val vm : MyViewModel by viewModel()
}
In this case, your object would be something like MyRepository() in the example. You'd just have to add the startKoin([list of modules]) from there. If you wanted MyRepository() in your Activity you'd include it like val myRepo: MyRepository by inject(). I don't know if this is outside the scope of your project though, it all depends on what you're trying to do exactly.

One big issue with this is that static variables don't survive Android low-memory state, but sending intent between survives. Also read here about static variable. (Link)

You have two options here:
Send it via Intent after implementing Serializable or Parcelable by you data class,
Save your data object to .txt file and read it when you need it.
static it is not created for this kind of things and You shouldn't use it in this case.
In my opinion You should go with first option.

This isn't the best method (although there really isn't a perfect way to do this), but you could instantiate it in a custom Application class.
class App : Application() {
val yourObject by lazy { YourObject() } //by lazy is useful if the Object needs to hold a Context or something that isn't immediately available
}
Add android:name=".App" to the application tag in your manifest so your App class is actually used. .App assumes it's in the root of your application package.
Then, from anywhere you have a reference to a Context, you can do something like:
(context.applicationContext as App).yourObject
to access the Object.

Related

When to use static vs. intents for "global" instances of an object

I want to instantiate an object in my MainActivity class that will be used and altered by my other activities.
The object is a custom data type.
Would it best best to declare the object as public static in MainActivity and then just use MainActivity.object throughout my application? Or would it be better to just pass the object around using intents?
The main thing I'm worried about using static is that I've seen people saying you use it when you care about privacy but I'm not too sure what that means so.. hoping to get some input.
Thanks
If you need one object on all app, you can store this object in Application class

Prevent dependency on a class in Java / Kotlin, but allow extending

I wish to create a useful base Java class with a few protected methods and hooks so subclasses can be easily implemented.
However, I wish this class to ONLY be available for deriving a subclass, but not available as a dependency.
The reason is to prevent some junior/careless developers from coupling their code to this base class.
For example, if my base class is called BaseActivity.java, anyone can create their own
public class MyNewActivity extends BaseActivity
But no one can refer directly to BaseActivity with a field or method signature, for example this should not be allowed:
public void doSomethingOnBaseActivity(BaseActivity activity);
private BaseActivity someField;
public BaseActivity getActivity();
Is there any way to accomplish such a restriction in Java?
Maybe in Kotlin this would be possible?
EDIT:
This is NOT a duplicate of Kotlin: Can an abstract super class have an abstract constructor?.
I wish to prevent dependency on the base class, not just instantiation. "Abstract" doesn't help here.
No, this is not possible. This answer is true for all types, whether abstract or not, interface or class. When you are in the scope of a class (e.g. same package), and this class is not sealed then everybody in this scope can inherit it. As long you are inside the scope, you can reference this type. That's the point of access modifiers. It doesn't make sense to allow extension of a type but not referencing it. This contradicts the concept. Why would you want to do that? You can't remove that base class anyway because that would break the code of all inheritors. There is no point in allowing extension but disallowing referencing. What is the reason for this. Maybe there is a different way to accomplish your goal. The very moment somebody inherits from a type creates the dependency. This dependency is called inheritance. The subtype is a supertype. You can't hide this fact from the compiler.
If you want to omit a dependency but reuse code or provide a template of the code then don't use a type. You could use file templates or a code generator to generate the reusable code (like code snippets).
First off, let's address the why. Why are you looking for this? You're looking for a way to prevent the consumer from calling unwanted methods on a base class.
If you think you're looking for something else, think again. If you just want to hide it, think again. The end user will not care about implementation details at all.
If you created the base class, then don't publish an API that allows this in the first place. There was a chapter on this specifically in Clean Code.
If your base class extends another base class you're in trouble. You can't hide already published API, if you're extending and not encapsulating.
I wish this class to ONLY be available for deriving a subclass, but not available as a dependency. Is there any way to accomplish such a restriction in Java? Maybe in Kotlin this would be possible?
No. This is not an opinion, this is by design.
There may be a convoluted way to hide methods of parent classes but not on the class the consumer interacts with (extends).
You could have several layers of base classes each within its own Gradle module and setup implementation type dependency but then If you can extend the class, if you can see it, reference it, you can also use it anywhere.
Imagine this:
consumer module -> ConsumerActivity extends ExtensibleActivity
your library module -> ExtensibleActivity extends BaseActivity
your base library module -> BaseActivity extends Activity
Android SDK -> Activity
Consumer module only sees what's inside "your library module". It knows about ExtensibleActivity but it can't see any of its super types. The consumer can still reference ExtensibleActivity and its methods. The side effect is because the superclasses are not known from consumer's point of view, you can't pass an instance of ExtensibleActivity as an Activity because the type system doesn't know it extends an Activity, because it doesn't see the BaseActivity intermediary type. Here's a graph of what the consumer sees:
ConsumerActivity -> ExtensibleActivity -> BaseActivity (doesn't exist) -> ??? (don't know)
At this point you just have to ask yourself "should this have extended Activity in the first place?".
This is just terrible to work with. Lot of wasted effort for something that you shouldn't need to worry about.
If you want to conceal something, use composition over inheritance. Put your logic inside a Fragment or, better yet, put your logic inside a custom lifecycle aware component. That way you're in total control over the API. Make it so you don't have to worry about where it gets called from.
Write good documentation for your code and a usage manual.
And kindly allow me to break your damn library if I choose to use it incorrectly.
Do you have multiple methods in your API? Great! Nobody will prevent me from calling them out of order. You can write in your manual how it's supposed to be used, but ultimately, I'm writing my program, using your library, and if I do it wrong, then it's my fault when it breaks. This is fine.

Android - Static class method calls to server

Background -
I have an app that currently has a lot of methods in MainActivity to pull and upload data to firebase. It's quite a mess with the other app logic in there..
Problem -
I would like a separate class filled with server (firebase) access methods that can be called from any activity or fragment and run asynchronously. The class also needs access to context and be able to initialise and store variables.
PS. I'm using kotlin if that helps at all
Edit:
Have done more researching to find terms like "utility" and "static" classes which seems like an accurate way to go... If I create a static utility class with Async methods, will that achieve what I'm after? Also, can you initialise and hold variables in a static class?
Thanks :)
Solved
After more research and testing, I created an object that holds my methods and variables and just need to pass context into the relevant methods. Then just simply call objectname.methodname()

Accessing the Global object in play! 2.0 with Java

I have extended the GlobalSettings class as shown in the tutorial Application global settings.
How do I then gain access to the instance of this class, let's say from a view method?
I'm assuming that one instance was created when the application was started and that it is probably a member of some object.
I would have expected for example to find it here:
Play.application().getGlobalSettings()
or something similar, but I couldn't find it anywhere in the Play.* hierarchy.
Any ideas?
Thanks.
I'm new to Play 2.0, however, I think you're better served by using plugin injection. Check this out:
https://github.com/typesafehub/play-plugins/tree/master/inject
Using this approach you simply add the following line to your controller (and some other configuration, as documented in the link above):
#Inject static MyStaticObj obj;
And all the rest is done automatically using the injection framework. No need to worry about global, etc.
That said, like you I spent a lot of time trying to figure out how to use the GlobalSettings object for this before discovering the plugin injection framework.
My sense is that given how Global is implemented (as class in the default/unnamed package) it's not possible to reference it anywhere in the application code. I'm not sure if this was by design or by accident (it seems that the Play folks are thinking about Scala quite a bit these days...). Fortunately the plugin approach seems to be better way to handle these shared globals.
Just reference the Global object directly.
For example don't write :
public class Global extends GlobalSettings {}
write
object Global extends GlobalSettings {}
or
object Global extends Global {}
class Global extends GlobalSettings {}
and than you can reference Global object anywhere in your code just write :
Global.someMethod()

How to implement singleton with strategies?

I'm adapting Image Downloader from Google Android blog. I want ImageDownloader to be singleton since I'll be using it in multiple places in my application. I want also to be able to manipulate Bitmaps using different Strategies (eg. produce transparent bitmaps).
Context:
I want to be able to use ImageDownloader in one activity and set transparent bitmaps, and in another use the same ImageDownloader but get black&white bitmaps using different strategy object.
You think you do, but you don't want ImageDownloader to be a Singleton. Singleton is very much overused, and not appropriate in your case. Think about it: how can you manipulate Bitmaps using different strategies if there is only one instance of the class doing the manipulating?
What you want is the ability to create instances of ImageDownloader via static methods, which you can do without making it a Singleton. These methods are called Factory methods, and there are many good web pages describing them.
You probably want something like:
class ImageDownloader {
static ImageDownloader createImageDownloader(Strategy s) {...}
//...
}
Each call to the method with the same argument could return the same instance of ImageDownloader, provided the instances don't store state. Some versions of this approach are referred to as "Multiton". Google will tell you more.
I'm more inclined to agree with DJClayworth answer, but to answer your question, the best way to implement the singleton pattern is to use an enum:
public enum ImageDownloaderWrapper
{
INSTANCE;
public static final ImageDownloader IMAGE_DOWNLOADER;
private ImageDownloaderWrapper()
{
IMAGE_DOWNLOADER = new ImageDownloader();//this is where you would initialize it... looks like it has a default constructor
}
}
To get a hold of the instance:
ImageDownloaderWrapper.INSTANCE.IMAGE_DOWNLOADER.download(...
You can also take advantage of static imports:
import static some.package.structure.ImageDownloaderWrapper.INSTANCE;
Then it's a bit simpler:
INSTANCE.IMAGE_DOWNLOADER.download(...
To account for different strategies I guess you'd have to extend ImageDownloader and add the appropriate logic for dealing with strategies in that subclass (the type of IMAGE_DOWNLOADER should also correspond to the subclass you created).
You could pass a strategy as parameter to the methods responsible for the image downloading/manipulation.
Then the strategy passed will handle the manipulation. It's a fairly ugly hack though. See DJClayworth's answer for the more clean code ideas.

Categories

Resources