I am relatively new to android development and being from a c# background it is entirely possible my entire strategy is wrong, but I am continually getting warned by Eclipse when degugging that I haven't closed a database connection properly causing a memory leak.
I have a base database class that extends SQLiteOpenHelper:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public MySQLiteOpenHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
public MySQLiteOpenHelper(Context context) {
this(context, "myDb", null, 1);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE MyTable (A INT)");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public Cursor executeSelect(String sql, String[] parameters) {
return getReadableDatabase().rawQuery(sql, parameters);
}
}
A generic entity:
public class MyClass {
private int a;
public void setA(int value) {
this.a = value;
}
public int getA() {
return this.a;
}
}
And essentially a service for MyClass (although in reality this extends a generic abstract class for reusability purposes)
public class MyClassService {
private MySQLiteOpenHelper helper;
private Context context;
public MyClassService(Context context) {
this.context = context;
}
private MySQLiteOpenHelper getHelper() {
if (helper == null) {
helper = new MySQLiteOpenHelper(this.context);
}
return helper;
}
public void dispose() {
if (helper != null) {
helper.close();
helper = null;
}
}
public ArrayList<MyClass> getAll()
{
ArrayList<MyClass> list = new ArrayList<MyClass>();
Cursor cursor = getHelper().executeSelect("SELECT A FROM MyTable", new String[0]);
while (cursor.moveToNext()) {
MyClass item = new MyClass()
item.setA(cursor.getInt(0));
list.add(item);
}
cursor.close();
return list;
}
}
So, my question is when I use a line of code like this from an Activity:
ArrayList<MyClass> list = new MyClassService(this).getAll();
is the instance of MyClassService disposed of immediately, or could this be the source of my memory leaks.
Would I be better calling the full code to ensure the database is closed using the dispose method?
MyClassService svc = new MyClassService(this);
ArrayList<MyClass> list = svc.getAll();
svc.dispose();
The Garbage Collector would be able to collect your class, as well as the Helper class, since these are no longer part of the Object chain (not a technical term - just something I made up). However, you would still need to explicitly close the database (if you don't this would definitely be your memory leak culprit). As it stands, you can do this in your Object's finalize() method, which is called during garbage collection:
#Override
public void finalize() {
dispose();
}
I usually prefer, however, to do things a little differently. Data Stores like this are often best written as Singletons, since they may be accessed by multiple classes, and if different instances are created they will still open a new access point for reading a writing, and could cause many issues. You sort of have a singleton-style setup in that there is one helper variable in your code, but you may want to simply make your Helper class the singleton. You can do this by removing your constructors and adding this:
private static MySQLiteOpenHelper self;
private MySQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
private MySQLiteOpenHelper(Context context) {
this(context, "myDb", null, 1);
}
public static MySQLiteOpenHelper sharedHelper(Context context) {
if (self == null)
self = new MySQLiteOpenHelper(context);
return self;
}
Then, instead of keeping track of a helper object in MyClassService using getHelper(), you can get THE helper using:
MySQLiteOpenHelper.sharedHelper(context);
The benefit of doing this means you only have to keep track of one Helper throughout the entire app, and in the helper's finalize() method, you can now close the database. This will be called when the app process is killed, and prevent any memory leaks:
public void finalize()
{
close();
}
You should explicitly call dispose - not doing so won't cause a memory leak (the object can be collected immediately after new MyClassService(this).getAll() because there aren't any live references to the object), but may cause your database to run out of available connections.
You forgot to call close on the database object returned from getReadableDatabase().
Related
I stumbled upon a pseudo-singleton class that is responsible for housing a few collections. It looks something like this:
public class PseudoSingleton {
private List<Object> collection1;
private List<Object> collection2;
private static PseudoSingleton instance = null;
public static synchronized PseudoSingleton getInstance() {
if (instance == null) {
instance = new PseudoSingleton();
}
return instance;
}
public static synchronized void reload() {
instance = new PseudoSingleton();
}
private PseudoSingleton() {
load();
}
private void load() {
//parse some files from disk and fill collections
}
}
The reason it is coded like this is that in a few places in code a comparison of collection1 before and after reload needs to be done.
However this way seems like a major code smell to me.
I tried to refactor the code slightly by making the reload() method not static:
public synchronized void reload() {
//clear collections
//load collections
}
In order to be able to compare collection before reload I added a method that needs to be called before reloading the collection:
public List<Object> getCollection1Copy() {
return new LinkedList<>(collection1);
}
However, in review I got a comment that the previous way was better and I should leave it as is. I am not convinced. Should I insist to go my way or leave it? Or is there a better way to code it?
There are several activities and fragments that need access to a specific data, so i created a singleton object to store data in that. The problem is after a long time that the app is in background, that singleton object will disapear and become null, so when i open my app again the app crashes and throws null pointer exception to that object. What should I do? How should i share that data between activities and fragments?
Is it a good practice to store that data in database? Or bundle? or whatever?
This is my singleton:
public class Book {
private static Book ourInstance;
private int FLNB;
private Book() {
}
public static Book getInstance() {
if (ourInstance == null) {
ourInstance = new Book();
}
return ourInstance;
}
public void setFLNB(int FLNB) {
this.FLNB = FLNB;
}
public int getFLNB() {
return this.FLNB;
}
}
I set FLNB, and when singleton is gone, the value of FLNB is cleared and I need to access this value after re-initial singleton.
I'm designing a class which has a purpose of being an immutable container for some objects. It happens very often that the Container object is holding just a single object and since it's immutable, I tend to implement it as follows:
public abstract class Container{
public abstract Iterable<Object> getObjectGroup();
private Container(){ }
public static Container createSingle(final Object o) {
return new Container() {
#Override
public Iterable<Object> getObjectGroup() {
return new Iterable<Object>() {
#Override
public Iterator<Object> iterator() {
return new Iterator<Object>() {
private boolean next = true;
#Override
public boolean hasNext() {
return next;
}
#Override
public Object next() {
next = false;
return o;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Unable to remove from an immutable container");
}
};
}
};
}
};
}
public static Container createMultiple(final Collection<Object> o) {
return new Container() {
#Override
public Iterable<Object> getObjectGroup() {
return Collections.unmodifiableCollection(o);
}
};
}
}
QUESTION: Is it actually justified to make such a distinction between containers for single and multiple objects. I primiraly do this in order to not waste the memory for creating a specific collection object like ArrayList<T> or TreeSet<T> which is definitely redundant in case of a single-object Container.
There is no absolute answer to this question: Whether the distinction between a uni-object container and a multi-object container is justified depends totally on the context of your problem.
I would say that unless you already know that you are running into memory issues and that the memory issue is caused by these collections, it is a premature optimization that just adds complexity. And even if you are running into performance issues, there is likely something better to optimize than this code.
So the answer should probably be the same as it is to every other question of form "Should I increase complexity to optimize time/memory usage": Not unless it is a problem.
What are the best practices to structure big android databases? From what I've seen so far doing some research on this topic, I've seen that most people are using a DatabaseHelper, which extends SQLiteOpenHelper. Does this also apply when you have multiple tables?
For example, in my current project, I have about 30 tables. So far, all of my tables are being created in my DatabaseHelper class, which currently is getting pretty huge. For every module, I also have a (class)Source class, which has all the CRUD methods in that module, and is using a singleton instance of my DatabaseHelper class.
Somehow it feels unnatural to have all of that code in my DatabaseHelper class. Have I done it the right way, or are there some better way to do this?
I would recommend to produce the database via an DB-Client like Squirell or something else. Then you can deploy the database to your app via the assets folder of your app.
Have a look at this thread
I've taken the following approach which helps separate responsibility. First off, start with an abstract database adapter. Its responsibility is to manage access to the database, create tables (if required), handle upgrades, etc. It provides no access to any tables.
public abstract class DBAdapter {
private static final String DATABASE_NAME = "database.db";
private static final int DATABASE_VERSION = 1;
protected final Context context;
protected SQLiteDatabase database;
private DatabaseManager databaseManager;
private static class DatabaseManager extends SQLiteOpenHelper
{
private static final String CREATE_TABLE_PERSON = "create table ...";
//define other tables here
DatabaseManager(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_PERSON);
//create other tables here
}
}
public DBAdapter(Context aContext)
{
context = aContext;
}
public DBAdapter open() throws SQLException {
if (databaseManager == null)
{
databaseManager = new DatabaseManager(context);
}
database = databaseManager.getWritableDatabase();
return this;
}
public void close() {
databaseManager.close();
}
}
Then, for each table, provide an implementation of your DBAdapter. It provides the access to your tables and the column definitions. Alternatively, you can also create DBAdapter implementations for each multi-table joins you need to do. This class provides the create/read/update/delete (CRUD) functionality for this type of access (table or multi-table join).
public class PersonAdapter extends DBAdapter
{
static final String COLUMN__ID = "_id";
static final String TABLE_PERSON = "Person";
static final String COLUMN_DATE_OF_BIRTH = "DateOfBirth";
static final String COLUMN_SURNAME = "Surname";
//etc.
public PersonAdapter(Context aContext) {
super(aContext);
}
public long deletePerson(long personId)
{
open();
long numberRowsDeleted =
database.delete(TABLE_PERSON, COLUMN__ID + "=" + personId, null);
close();
return numberRowsDeleted;
}
//your other Person CRUD methods go here
}
It's just something that puzzles me. Is it possible to use the current instance of the class within the constructor?
I've created a BroadcastReceiver that registers itself with the context within the constructor of the BroadcastReceiver. In addition it will unregister again. Is this good style?
Here's my example:
public class MyBroadcastReceiver extends BroadcastReceiver {
protected Context context;
protected MyOnBroadcastReceivedListener listener;
protected int receiverId;
protected String receiverTag;
public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
super();
this.context = context;
this.listener = listener;
this.receiverId = receiverId;
this.receiverTag = receiverTag;
IntentFilter intentFilter = new IntentFilter(receiverTag);
context.registerReceiver(this, intentFilter); // <--- Look at the use of this here
}
public void detach() {
if (context != null) {
context.unregisterReceiver(this); // <--- Look at the use of this
}
}
#Override
public void onReceive(Context context, Intent intent) {
// ...
if (listener != null) {
listener.onBroadcastReceived(receiverId, "Bla", "Blub");
}
}
}
Yes, no trouble at all.
Inside the constructor, the object has been created but still no reference has been returned to the rest of the java code. You can use this without worries.
Anyway, in some frameworks where some attributes may be initialized automatic (Context Dependent Injection, CDI), it is not possible to fully initialize the class in the constructor (because such attributes are still not available and may be needed). These frameworks rely in that you mark a method as #PostConstruct; after all attributes are set that method will be called (just so you know what it means when you find it).
If you refer to using this in constructor code, then yes - it is perfectly valid, otherwise constructor would not be really able to construct to much within own instance. I'd however suggest following common practice and prefix your class members (most commonly used prefix is 'm') which helps avoid problems which are sometimes hard to debug. So instead of:
protected Context context;
protected MyOnBroadcastReceivedListener listener;
you would have:
protected Context mContext;
protected MyOnBroadcastReceivedListener mListener;
You can do this, but is not a good style. Passing this from inside a class constructor is dangerous as the current, still constructing object might not be fully intialized.
For example, you might one day add a new int field to the MyBroadcastReceiver, but overlook that you have the statement context.registerReceiver(this, intentFilter); and add the intialization of the new field at the end of the constructor:
public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
super();
this.context = context;
this.listener = listener;
this.receiverId = receiverId;
this.receiverTag = receiverTag;
IntentFilter intentFilter = new IntentFilter(receiverTag);
context.registerReceiver(this, intentFilter); // <--- Look at the use of this here
this.newField = 1;
}
Now, you might expect that in the Context.registerReceiver method the newField to be 1 as it initialized in the MyBroadcastReceiver constructor. But you will get the value 0.
See also the following SO question for more information and more potential problems that could appear: Passing "this" in java constructor
Yes it works. I tried a simple test case. and it works. :
public class Test {
private int variable;
private Test2 test2;
public Test(int variable, Test2 test2) {
this.variable = variable;
this.test2 = test2;
test2.printTest(this);
}
public int getVariable() {
return variable;
}
public static void main(String[] args) {
Test test = new Test(111111,new Test2());
}
}
class Test2{
Test2() {
}
public void printTest(Test test){
System.out.println(test.getVariable());
}
}
And it works like a charm