JavaScript is disabled in your browser.
Please enable JavaScript settings in your browser to allow this website work correctly.

Using a Pre-Populated SQLite Database in Android

December 14, 2012

Most Android code samples and manuals assume that a SQLite database is created at runtime. But what if we want to use an existing database—for instance, a database created and populated on a PC?

Creating the Pre-Populated Database

To make a database on a PC, you can use the SQLite Database Browser, which is available for most platforms. Let’s say you have already created a simple database in the yourdb.sqlite3 file with one table called friends, which contains a list of your friends and has two fields: id and name. To make your database work correctly on an Android device, you have to make two modifications.

1. Rename the id field of your table to “_id”. It can be easily done by clicking the Modify Table button, and then choosing the necessary table and field names.

2. Add the android_metadata table. To do that, open the Execute SQL tab and paste this simple code into the SQL string field:


CREATE TABLE android_metadata (locale TEXT);

INSERT INTO android_metadata VALUES ('en_US');

Click the Execute query button—and the database is ready. The database is now created and located in the assets folder. We'll show you how to use it in your Android app after the jump.

Implementing the ExternalDbOpenHelper Class

The ExternalDbOpenHelper class is inherited from SQLiteOpenHelper. The application databases are stored in the data/data//databases/ folder on your device. That’s the folder where we need to copy our database. The commented code listing is shown below.

package com.softeq.android.prepopdb.dbhelper;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class ExternalDbOpenHelper extends SQLiteOpenHelper {

//Path to the device folder with databases
public static String DB_PATH;

//Database file name
public static String DB_NAME;
public SQLiteDatabase database;
public final Context context;

public SQLiteDatabase getDb() {
return database;
}

public ExternalDbOpenHelper(Context context, String databaseName) {
super(context, databaseName, null, 1);
this.context = context;
//Write a full path to the databases of your application
String packageName = context.getPackageName();
DB_PATH = String.format("//data//data//%s//databases//", packageName);
DB_NAME = databaseName;
openDataBase();
}

//This piece of code will create a database if it’s not yet created
public void createDataBase() {
boolean dbExist = checkDataBase();
if (!dbExist) {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
Log.e(this.getClass().toString(), "Copying error");
throw new Error("Error copying database!");
}
} else {
Log.i(this.getClass().toString(), "Database already exists");
}
}

//Performing a database existence check
private boolean checkDataBase() {
SQLiteDatabase checkDb = null;
try {
String path = DB_PATH + DB_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
Log.e(this.getClass().toString(), "Error while checking db");
}
//Android doesn’t like resource leaks, everything should 
        // be closed
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}

//Method for copying the database
private void copyDataBase() throws IOException {
//Open a stream for reading from our ready-made database
//The stream source is located in the assets
InputStream externalDbStream = context.getAssets().open(DB_NAME);

//Path to the created empty database on your Android device
String outFileName = DB_PATH + DB_NAME;

//Now create a stream for writing the database byte by byte
OutputStream localDbStream = new FileOutputStream(outFileName);

//Copying the database
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
localDbStream.write(buffer, 0, bytesRead);
}
//Don’t forget to close the streams
localDbStream.close();
externalDbStream.close();
}

public SQLiteDatabase openDataBase() throws SQLException {
String path = DB_PATH + DB_NAME;
if (database == null) {
createDataBase();
database = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READWRITE);
}
return database;
}

@Override
public synchronized void close() {
if (database != null) {
database.close();
}
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}

This class can now be used in any Android application. All we need to do is pass the database file name and context (in most cases, it is Application) to the constructor.

Have Database, Will Travel

Let’s create a sample application with a simple architecture and minimal functionality. When launched, it will output a list of friend names from our database.

Note: Uninstall the application from the Android device before every test run. The database file is created only after the first run of the application.

The project has only one activity inherited from ListActivity with the following markup:


android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:id="@android:id"
android:layout_width="fill_parent"
android:layout_height="fill_parent"

and the following logic:

package com.softeq.android.prepopdb.activity;

import java.util.ArrayList;

import com.softeq.android.prepopdb.R;
import com.softeq.android.prepopdb.R.layout;
import com.softeq.android.prepopdb.dbhelper.ExternalDbOpenHelper;
import android.app.Activity;
import android.app.ListActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class PrepopSqliteDbActivity extends ListActivity {
    
    private static final String DB_NAME = "yourdb.sqlite3";
    
    //A good practice is to define database field names as constants
private static final String TABLE_NAME = "friends";
private static final String FRIEND_ID = "_id";
private static final String FRIEND_NAME = "name";

private SQLiteDatabase database;
private ListView listView;
private ArrayList friends;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //Our key helper
        ExternalDbOpenHelper dbOpenHelper = new ExternalDbOpenHelper(this, DB_NAME);
        database = dbOpenHelper.openDataBase();
        //That’s it, the database is open!
        fillFreinds();
        setUpList();
    }

private void setUpList() {
//We use a standard adapter and an element layout for brevity’s sake
setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, friends));
  listView = getListView();

//Let’s set a message shown upon tapping an item
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View view,
int position,long id) {
Toast.makeText(getApplicationContext(),
((TextView) view).getText() +
          " could be Softeq's friend",
          Toast.LENGTH_SHORT).show();
}
}
}

//Extracting elements from the database
private void fillFreinds() {
friends = new ArrayList();
Cursor friendCursor = database.query(TABLE_NAME, new String[] {FRIEND_ID,
            FRIEND_NAME}, null, null, null, null, FRIEND_NAME);
friendCursor.moveToFirst();
if(!friendCursor.isAfterLast()) {
do {
String name = friendCursor.getString(1);
friends.add(name);
} while (friendCursor.moveToNext());
}
friendCursor.close();
}
}

That’s it! If you used our database example, you will now see the following picture on your screen:


You can download the complete example source here: PrepopSqliteDb.zip.

Happy coding!

 

Get the FREE Softeq Newsletter

subscribe

Softeq Newsletter is worth your while

Sign up for the free Softeq Newsletter to be the first to learn about special offers and half-year round-ups. We promise not to betray your trust and not to go overboard with irrelevant information. We guarantee your personal data is safe and protected by our privacy policy with us and will not be shared with anyone externally. You can unsubscribe from the newsletter at any time. Contact us if you have any questions.

* — means required fields

Start a Project with Softeq