I want to get a reference to my database in one activity, and pass the referred database variable to another Activity through an intent. Is there any way I can do this?
You have to make a method in your Sqlite class to get Singleton object of that class :
public static synchronized SQLiteDatabaseHandler getInstance(Context mContext) {
if (instance == null) {
instance = new SQLiteDatabaseHandler(mContext);
}
return instance;
}
You can get Object of this class in any of your classes (no need to
pass SqliteDatabaseHandler Object to another class) :
SQLiteDatabaseHandler.getInstance(mContext);
Related
I am trying to access application resources, (string resources to be specific) from a Singleton class. Being Singleton, this class cannot hold any reference to Context objects (to prevent memory leak). While I was looking for other implementations on the net, I came across this two implementation:
Create a static context in Application class and use it across the app.
Pass context as a parameter to the method that requires it.
I don't want to use the fist one as it also uses a static reference to Context object. I understand that it's ok to have it statically in the Application class of android, but still it looks like a hack.
The second implementation is useless since i don't have any instance of context which I can pass to the someOtherMethod of the singleton.
So I came up with following implementation where I make my Singleton abstract to override its context requiring methods (for ex. getString(int resId) in the code below) when I initialize the singleton instance.
I am curious to know if this can lead to any memory leaks now?
Where am I confused with this approach:
--> The reference to context in the Overridden getString is final. I am not sure if that can cause a memory leak or not.
public abstract class SingletonClass{
.
.
.
private static SingletonClass sInstance;
private SingletonClass(Context paramContext) {
// constructor code
}
public static SingletonClass getInstance(final Context context) {
if (sInstance == null) {
sInstance = new SingletonClass(context){
#Override
public String getString(int resId) {
return context.getString(resId);
}
};
}
return sInstance;
}
public abstract String getString(int resId);
.
.
.
private void someOtherMethod(){
//uses above getString()
}
}
Your approach does have a memory leak. The first context passed into getInstance will never be garbage collected, since your anonymous class holds a reference to it. (and there is a static reference to the anonymous class). e.g., if you call getInstance(Activity), that activity will remain in memory until the process is killed!
Fortunately there is a pretty easy fix to get rid of the memory leak. You can safely hold onto the application context (context.getApplicationContext), which is basically a singleton context for lifetime of the app.
public static SingletonClass getInstance(Context c) {
if (sInstance == null) {
sInstance = new SingletonClass(c.getApplicationContext());
}
return sInstance;
}
You can depend on activity lifecycle, and require activities to pass reference to your singleton object in onResume method, and clean it in onPause.
protected void onResume() {
super.onResume();
Singleton.getInstance().onResume(this);
}
protected void onPause() {
super.onResume();
Singleton.getInstance().onPause();
}
Also, you can refresh the instance of Context and hold it in WeakReference:
class Singleton {
private WeakReference<Context> mContext;
private boolean hasContext() {
return mContext != null && mContext.get() != null;
}
public static Singleton getInstance(Context c) {
//do your singleton lazy
if (!sInstance.hasInstance()) {
sInstance.mContext = new WeakReference<>(c);
}
return sInstance;
}
}
Second case could hold a reference to finishing activity, so i don't suggest it.
From MyActivity, call to:
MyClass.getInstance();
MyClass.doStuff();
...
#EBean(scope = EBean.Scope.Singleton)
public class MyClass {
#Bean
MyManager manager;
public static void doStuff(){
manager.show();
// null pointer exception for the manager why ? how to access it ?
}
public static MyClass getInstance() {
if (_instance == null) {
_instance = new MyClass();
}
return _instance;
}
}
...
#EBean(scope = EBean.Scope.Singleton)
public class MyManager {
public void show(){ }
}
Android annotations access singleton class object into other class static method. Note : AA version 3.3.1
I am afraid you are using AA #EBean incorrectly. Did you read the documentation?
You do not have to write a getInstance() method yourself, AA will generate the appropriate method, do the injections in it, and automatically call it when injecting the bean into other components. You got a NullPointerException because you created the bean with your own getInstance() method, so no AA injections were performed. But actually you are getting a compile error in doStuff(), because you are accessing an instance field in a static method... So i assume the manager field is static, right? You should not use static fields/methods in singletons, the concept of the singleton is one instance is existing only, so using static fields/methods is redundant and also confusing.
You can fix the problem by either:
Creating an instance of MyClass by calling MyClass_.getInstance(context) manually, then use it
Inject a MyClass instance into another component with the #Bean annotation and use it from there
Is there a way to change what database an SQLiteOpenHelper object uses without having to force every class that uses the helper to replace their instance of the class?
The reason why I'm changing the database is because I have some live data and some offline data in two separate databases with identical table structures. I update the offline data and then swap them, allowing me to lock the offline database on big inserts.
You must use the singleton pattern to acces to your database with only one instance
it's look like
public class SingletonDemo {
private static SingletonDemo instance = null;
private SingletonDemo() { // do what you want here}
public static SingletonDemo getInstance() {
if (instance == null) {
synchronized (SingletonDemo.class) {
if (instance == null) {
instance = new SingletonDemo();
}
}
}
return instance;
}
...
// Add all the class function you need here
}
This is thread safe and can be use every where you need.
I have followed this link and successfully made singleton class in Android.
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
Problem is that i want a single object. like i have Activity A and Activity B. In Activity A I access the object from Singleton class. I use the object and made some changes to it.
When I move to Activity B and access the object from Singleton Class it gave me the initialized object and does not keep the changes which i have made in Activity A.
Is there any other way to save the changing?
Please help me Experts.
This is MainActivity
public class MainActivity extends Activity {
protected MyApplication app;
private OnClickListener btn2=new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent=new Intent(MainActivity.this,NextActivity.class);
startActivity(intent);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Get the application instance
app = (MyApplication)getApplication();
// Call a custom application method
app.customAppMethod();
// Call a custom method in MySingleton
Singleton.getInstance().customSingletonMethod();
Singleton.getInstance();
// Read the value of a variable in MySingleton
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
Button btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(btn2);
}
}
This is NextActivity
public class NextActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
}
}
Singleton Class
public class Singleton
{
private static Singleton instance;
public static String customVar="Hello";
public static void initInstance()
{
if (instance == null)
{
// Create the instance
instance = new Singleton();
}
}
public static Singleton getInstance()
{
// Return the instance
return instance;
}
private Singleton()
{
// Constructor hidden because this is a singleton
}
public void customSingletonMethod()
{
// Custom method
}
}
and MyApplication
public class MyApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
// Initialize the singletons so their instances
// are bound to the application process.
initSingletons();
}
protected void initSingletons()
{
// Initialize the instance of MySingleton
Singleton.initInstance();
}
public void customAppMethod()
{
// Custom application method
}
}
When i run this code, i get Hello which i have initialized in Singleton then World which i gave it in MainActivity and again shows Hello in NextActivity in logcat.
I want it to show world again in NextActivity.
Please help me to correct this.
Tip: To create singleton class In Android Studio, right click in your project and open menu:
New -> Java Class -> Choose Singleton from dropdown menu
EDIT :
The implementation of a Singleton in Android is not "safe" (see here) and you should use a library dedicated to this kind of pattern like Dagger or other DI library to manage the lifecycle and the injection.
Could you post an example from your code ?
Take a look at this gist : https://gist.github.com/Akayh/5566992
it works but it was done very quickly :
MyActivity : set the singleton for the first time + initialize mString attribute ("Hello") in private constructor and show the value ("Hello")
Set new value to mString : "Singleton"
Launch activityB and show the mString value. "Singleton" appears...
It is simple, as a java, Android also supporting singleton. -
Singleton is a part of Gang of Four design pattern and it is categorized under creational design patterns.
-> Static member : This contains the instance of the singleton class.
-> Private constructor : This will prevent anybody else to instantiate the Singleton class.
-> Static public method : This provides the global point of access to the Singleton object and returns the instance to the client calling class.
create private instance
create private constructor
use getInstance() of Singleton class
public class Logger{
private static Logger objLogger;
private Logger(){
//ToDo here
}
public static Logger getInstance()
{
if (objLogger == null)
{
objLogger = new Logger();
}
return objLogger;
}
}
while use singleton -
Logger.getInstance();
answer suggested by rakesh is great but still with some discription
Singleton in Android is the same as Singleton in Java:
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
1) Ensure that only one instance of a class is created
2) Provide a global point of access to the object
3) Allow multiple instances in the future without affecting a
singleton class's clients
A basic Singleton class example:
public class MySingleton
{
private static MySingleton _instance;
private MySingleton()
{
}
public static MySingleton getInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
}
As #Lazy stated in this answer, you can create a singleton from a template in Android Studio. It is worth noting that there is no need to check if the instance is null because the static ourInstance variable is initialized first. As a result, the singleton class implementation created by Android Studio is as simple as following code:
public class MySingleton {
private static MySingleton ourInstance = new MySingleton();
public static MySingleton getInstance() {
return ourInstance;
}
private MySingleton() {
}
}
You are copying singleton's customVar into a singletonVar variable and changing that variable does not affect the original value in singleton.
// This does not update singleton variable
// It just assigns value of your local variable
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
// This actually assigns value of variable in singleton
Singleton.customVar = singletonVar;
I put my version of Singleton below:
public class SingletonDemo {
private static SingletonDemo instance = null;
private static Context context;
/**
* To initialize the class. It must be called before call the method getInstance()
* #param ctx The Context used
*/
public static void initialize(Context ctx) {
context = ctx;
}
/**
* Check if the class has been initialized
* #return true if the class has been initialized
* false Otherwise
*/
public static boolean hasBeenInitialized() {
return context != null;
}
/**
* The private constructor. Here you can use the context to initialize your variables.
*/
private SingletonDemo() {
// Use context to initialize the variables.
}
/**
* The main method used to get the instance
*/
public static synchronized SingletonDemo getInstance() {
if (context == null) {
throw new IllegalArgumentException("Impossible to get the instance. This class must be initialized before");
}
if (instance == null) {
instance = new SingletonDemo();
}
return instance;
}
#Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Clone is not allowed.");
}
}
Note that the method initialize could be called in the main class(Splash) and the method getInstance could be called from other classes. This will fix the problem when the caller class requires the singleton but it does not have the context.
Finally the method hasBeenInitialized is uses to check if the class has been initialized. This will avoid that different instances have different contexts.
The most clean and modern way to use singletons in Android is just to use the Dependency Injection framework called Dagger 2. Here you have an explanation of possible scopes you can use. Singleton is one of these scopes. Dependency Injection is not that easy but you shall invest a bit of your time to understand it. It also makes testing easier.
Hey! I want to use a singleton class, because if I open the database every activity I get "Leak found"( that happens because I open the database even if it is already open ) . I create a singleton class , but I don't know how should I use it.
Here is my class:
package com.ShoppingList;
import com.ShoppingList.databases.DbAdapter;
public class DbManager {
DbAdapter db;
// singleton
private static DbManager instance = null;
private DbManager() {
}
public static DbManager getInstance() {
if (instance == null)
instance = new DbManager();
return instance;
}
public void setinstance(DbAdapter db){
this.db=db;
}
public DbAdapter getinstancedb(){
return db;
}
}
In the first activity I put :
db = new DbAdapter(this);
db.open();
DbManager.getInstance().setinstance(db);
and for the next activity : DbManager.getInstance().getinstancedb(); but I get force close for second activity.
Can anyone help me how to use it? Thanks...
You can extend Application class and create there an instance of DbAdapter. This way it will be shared by all your activities.
Because db has the same context and life cycle of your first activity. Make your methods public and make them do all the setup/teardown necessary to return your desired result.
regarding the leak warning. Are you closing your db manager connection in onDestroy()?