AsyncTask with SQLiteDatabase - android

I'm a beginner in android. I want to perform basic CRUD operations of SQLiteDatabase using AsyncTask class. I have one int and 4 String parameters for table.How do i pass arguments to insert data in table from DataBaseHelper Class to AsyncTask Class.

This tutorial explains the usage of ContentProvider and Loader. Although Content Providers are overkill for small applications, it is the best way to implement a SQLiteDatabase within your application. Basically it allows you to have a app database accessible from every other application you wish and eases the usage of CRUD operations inside any of those.
With it, you don't need any reference to your SQLiteOpenHelper in order to make any operation in your database. Content Providers work by calling getContentResolver().<insert/delete/update>() directly in your Activity, keeping your code clean. Also, every operation you do using this API is sent to the background thread, leaving you no work at all besides configuring it for the first time.
A class that extends ContentProviderwill have 4 methods: insert(), delete(), update() and query(). These same methods must receive an URI that points to the table you will be using in that operation. Cool, huh? 4 methods for every operation in any table. You could also use a Constants class to map your URIs and boom: you got state of the art code.

Related

How to convert Android class to Singleton object (Kotlin)

Currently, I have a database manager class that handles all operations to the database like this:
class DatabaseManager(val context: Context) {
private val db = Firebase.firestore
//Other functions, etc.
}
It makes use of the context passed in by different activities to perform functions to the database. The thing is, every single activity that requires database functions have to instantiate this manager class first, then call the functions. I would like to make use of the Singelton design pattern to make it such that all the activities will only use a single instance of the class. I believe kotlin's objects can do this, however I also need to be able to pass in the context of the activities into this manager class. Any assistance is appreciated, thank you!
I would recommend not doing that. The problem with Singletons is that they make code hard to test, you can't fake out the database. And for a database this is a particularly bad problem, as setting up all the right fake data can be painful. Instead, take a look at injection. It can do the same thing (make a single instance shared between everyone who needs it), but it manages that global state rather than having the classes themselves manage it via a static reference, passing it in (generally via the constructor) to whoever needs it. This makes it easy to provide an alternative or mock database when needed for testing. Injection used to be a bit painful to set up, but Hilt makes it a lot easier these days.

Realm or Paper for JPA in Android?

I'm developing an Android app with Android Annotations. For persistence, I firstly used a Content Provider (very complex) on top of SQLite. Then, I discovered Realm. It seemed very cool until I had to be notified for insertions to make my RecyclerView dynamic. To be notified of insertions, I made a singleton class I called RealmProxy with a proxy method for copyToRealm(), and an interface to implement to be a RealmListener. I called registered listeners in my copyToRealm() method passing them the added RealmObject, so I could populate my SortedList (support library list designed for RecyclerView) RecyclerView Adapter. I also used my RealmListener interface to send new Objects over network as soon as they are saved.
After compiling and running, I got and IllegalStateException (Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.) because I get the Realm instance from UI thread but I send them over network in a background thread obviously. Why do I get this error ? Whenever my JSON serialization library LoganSquare, based on Jackson calls a getter on my RealmObject in the background to send over network, this exception is thrown. This made me hate Realm thread policy and the fact that fine grained notifications aren't built-in. Also, Realm doesn't allow me to define any custom method. I can't even implement Comparable in a Realm Object.
When I saw Paper (thanks to Android Arsenal and Pushbullet) today, I was very interested in a no headaches JPA solution. It seems very simple, without restriction for Lists, Maps, and any class not extending a special class (Realm requires extending RealmObject and using RealmList instead of generic List which my json<>java didn't liked, forcing me to copy lists).
EDIT:
I discovered SnappyDB today. It uses the same serialization library (Kryo) as Paper, it seems to be very similar to Paper, with more features for keys management.
So my question is the following:
Should I search for workarounds and continue to use Realm, if yes, which workarounds, or should I use Paper, or SnappyDB instead ? Did anyone used Paper or SnappyDB for android?
All the best
If your question is about how to update your Object in UI thread when it gets changed in background, it is actually quite simple.
For example in your UI thread you can do this:
private Dog dog;
private RealmChangeListener listener = new RealmChangeListener() {
#Override
// This will be called when the commitTransaction gets called
// in the background thread
public void onChange() {
// It would changed to "EFG" automatically in next UI loop after
// you updated it in the background thread.
String name = dog.getName();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
dog = realm.where(Dog.class).equalTo("id", 42).findFirst();
// Assume it is "ABC" now
String name = dog.getName();
// Register the listener
realm.addChangeListener(listener);
}
And update the dog in th background service like:
// This realm will be a different instance created in this thread.
dog = realm.where(Dog.class).equalTo("id", 42).findFirst();
realm.beginTransaction();
dog.setName("EFG");
realm.commitTransaction();
The IllegalStateException is because of:
The only rule to using Realm across threads is to remember that Realm, RealmObject or RealmResults instances cannot be passed across threads. When you want to access the same data from a different thread, you should simply obtain a new Realm instance (i.e. Realm.getInstance(Context context) or its cousins) and get your objects through a query. The objects will map to the same data on disk, and will be readable & writeable from any thread!
See see doc here
And you probably need RealmBaseAdapter which can make building a ListView with Realm pretty easy. You can find example here.
JPA is not a solution, it's a definition for Java Persistence. Once you choose JPA, you need to find an implementation. In the Java world, the most widely used implementation is Hibernate. Also, you can use Hibernate ORM without using JPA.
On Android, OrmLite provides an implementation for a subset of JPA. But, as it's only a subset, you may as well skip JPA and use the equivalent Ormlite annotations. I use JPA implemented by Hibernate on my server apps, and Ormlite with no JPA on Android. I definitely recommend Ormlite.

Android SQLiteOpenHelper multithread ad AndroidTestCase support at the same time

I have a SQLiteOpenHelper that wraps my Database. the SQLiteOpenHelper subclass is implemented as Singleton to avoid MultiTread problems and it seems to work quite well.
The problem is: testing classes that uses the database.
In AndroidTestCase i want to test methods that depends on DB in isolation so i use
setContext(new RenamingDelegatingContext(getContext(), "test_"));
and than use the IsolatedContext to get a separate empty instance of the db.
So, the android app need the singleton but Junit need a simple instance.
The only approach i found at the moment is declare SQLiteOpenHelper subclass with two contructors , one static that return the singleton instance and another that return a new instance . Than add to every class that use the db add one constructor to use the singleton an other that use a new instance.
This approach it is very ugly and error prone , so there is a more logical elegant way to do so?
(ps i'm not using ContentProvider and not interested in so please do not suggest them as solution)

open sqlite database in android

How can i open a database in a class that is not a subclass of Activity?
In a subclass of Activity, i can use openOrCreateDatabase() but can i open a database in a different class?
I tried making the database instance a static one and open it in an Activity and get the static instance in the other class, but it throws an exception stating the database is closed.
Check out this tutorial.
I went through it and it's a really good tutorial on how to use SQLite in Android.
Essentially you need to create a database helper class that will do the table creation. Then you can use this helper class in your Activity to create your database and or tables.
It's common practice to use a SQLite Database Adapter and sometimes a helper class that is separate from the activity that is utilizing the database. Here is a link to a example that uses the code. THe vogella tutorial is also good but the use of a ContentProvider makes it a bit tough to understand what things need to be in there for a SQLite DB only.
Essentially, the helper class is responsible for creating, updating and deleting the DB while the adapter class handles the methods for changing values, deleting rows, and actually calling the helper to open the database.

What to do with a database, retrieved by a SQLiteOpenHelper implementation, when finished using it?

Dear Fellow Android Developers!
EDIT:
Thank you all for your answers. I see from many of them that it seems to be common (and accepted) practice to write your own close() method in your database adapter. Fair enough.
But how does that work with a ContentProvider? Usually when querying my database through my ContentProvider I simply issue something like:
Cursor managedCursor = managedQuery(...);
I don't see how I, with this methodology, can access the custom close() method in my custom ContentProvider implementation. Should I instead, from my Activity, do something like:
MyCustomProvider myProvider = (MyCustomProvider) getContentResolver();
and then:
myProvider.query(...);
myProvider.close();
And above all; is this at all necessary (as of point 2 below)?
END EDIT
To a certain degree I must say that I get the concept of the SQLiteOpenHelper, what it is, how it's used and so. I even use it on a regular basis when I write my own ContentProvider's.
The thing is that I'm not sure what to do with the SQLiteDatabase object, returned by the myOpenHelper.getWritableDatabase() (or the myOpenHelper.getReadableDatabase() function for what matters) when I'm done with it.
According to Android ContentProvider.onCreate() documentation:
You should defer nontrivial initialization (such as opening, upgrading, and scanning databases) until the content provider is used (via query(Uri, String[], String, String[], String), insert(Uri, ContentValues), etc).
[...]
If you do use SQLiteOpenHelper, make sure to avoid calling getReadableDatabase() or getWritableDatabase() from this method. (Instead, override onOpen(SQLiteDatabase) to initialize the database when it is first opened.)
The above gives me a hint where to initialize the database (the query(...), insert(...), etc functions), but it doesn't tell me anything on how to treat the created SQLiteDatbase object when I've finished using it.
Should I save it as a member variable of my ContentProvider implementation (and treat it much like a "private singleton" for future use)?
Should I just leave it when exiting the query(...), insert(...), etc. functions and trust that the SQLiteOpenHelper will manage it for me in future calls?
[Insert your alternative point-of-view here]
Being the confiding (or lazy) developer I've implemented my code according to the second alternative above. But I can't get rid of the creepy feeling that I'm neglecting something important.
It depends on what you're doing with your database. If you just do an insert, delete or select where you get an business object back, then you can close the database right after using it. As far as I know it is designed that you simply close it and request a new one when ever you need it.
But be careful when you're working with a cursor then you have to keep the database open as long as the cursor is in use. Otherwise the application will crash when the cursor has to reload data.
I guess you should close it, for example in onDestroy() of an activity that is using it.
So in my DBAdapter class I have:
/**
* Close the database
*/
public void close() {
mDb.close(); //mDb was obtained using mDbHelper.getWritableDatabase();
}
And in my activity:
public void onCreate(Bundle bundle){
...
mDBAdapter = new DBAdapter(this);
// Open or create the database
mDBAdapter.open();
}
#Override
public void onDestroy() {
// Close the database
mDBAdapter.close();
super.onDestroy();
}
Not sure if this is suitable for your provider concept.
If you check the example of use for that object in the API of Android, you can see the object is just used, but no close is necesary.
They implement the method close() though, but I havent seen they use it.

Categories

Resources