Import Database with Images in Android

The article Import and Use External Database in Android explains, how to distribute an Android application along with the data stored in SQLite database. This tutorial explains, how to store images in such a database and pack it in your application. In other words, we are going to create a database with images from our desktop computer and import it into an Android application.

Step 1:
Create a database "images.db" using your favorite SQLite database application (I use Sqliteman because it allows inserting images into the database. You can use any software or script to insert the images into the database). Create a table 'places' with a two columns 'name' and 'image'. Here the data type of 'name' is TEXT and data type of 'image' is BLOB. Insert the name and image of  some places into the database. In this example, I have inserted the names of the seven wonders of the world along with a compressed (Using TinyPng) picture of them. To download the images used in this project, Click Here.


Step 2:
Create a new application “Image Database Demo” with a package name “com.javahelps.imagedatabasedemo”. and insert the SQLiteAssetHelper library and the compressed images.db into the project as provided in Import and Use External Database in Android tutorial.

Step 3:
Create a new class 'DatabaseOpenHelper'
package com.javahelps.imagedatabasedemo;

import android.content.Context;

import com.readystatesoftware.sqliteasset.SQLiteAssetHelper;

public class DatabaseOpenHelper extends SQLiteAssetHelper {
    private static final String DATABASE_NAME = "images.db";
    private static final int DATABASE_VERSION = 1;

    public DatabaseOpenHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
}

Step 4:
Create a new class DatabaseAccess and enter the code as shown below.
package com.javahelps.imagedatabasedemo;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by gobinath on 4/7/16.
 */
public class DatabaseAccess {
    private SQLiteOpenHelper openHelper;
    private SQLiteDatabase database;
    private static DatabaseAccess instance;

    /**
     * Private constructor to avoid object creation from outside classes.
     *
     * @param context
     */
    private DatabaseAccess(Context context) {
        this.openHelper = new DatabaseOpenHelper(context);
    }

    /**
     * Return a singleton instance of DatabaseAccess.
     *
     * @param context the Context
     * @return the instance of DabaseAccess
     */
    public static DatabaseAccess getInstance(Context context) {
        if (instance == null) {
            instance = new DatabaseAccess(context);
        }
        return instance;
    }

    /**
     * Open the database connection.
     */
    public void open() {
        this.database = openHelper.getWritableDatabase();
    }

    /**
     * Close the database connection.
     */
    public void close() {
        if (database != null) {
            this.database.close();
        }
    }

    /**
     * Read all quotes from the database.
     *
     * @return a List of quotes
     */
    public List<String> getNames() {
        List<String> list = new ArrayList<>();
        Cursor cursor = database.rawQuery("SELECT name FROM places", null);
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            list.add(cursor.getString(0));
            cursor.moveToNext();
        }
        cursor.close();
        return list;
    }

    /**
     * Read the BLOB data as byte[]
     *
     * @param name name of the place
     * @return image as byte[]
     */
    public byte[] getImage(String name) {
        byte[] data = null;
        Cursor cursor = database.rawQuery("SELECT image FROM places WHERE name = ?", new String[]{name});
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            data = cursor.getBlob(0);
            break;  // Assumption: name is unique
        }
        cursor.close();
        return data;
    }
}
The getImage method in this class, retrieve the BLOB image as an array of byte.

Step 5:
Create a Spinner and ImageView in the activity_main.xml as shown below.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.javahelps.imagedatabasedemo.MainActivity">

    <Spinner
        android:id="@+id/cmbName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ImageView
        android:id="@+id/imgPlace"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/cmbName"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />
</RelativeLayout>


Step 6:
Find the View objects of Spinner and ImageView in the onCreate method of MainActivity and pass the names of the places to the Spinner using an adapter.
package com.javahelps.imagedatabasedemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private Spinner cmbName;
    private ImageView imgPlace;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize the UI components
        this.cmbName = (Spinner) findViewById(R.id.cmbName);
        this.imgPlace = (ImageView) findViewById(R.id.imgPlace);

        // Define final variables since they have to be accessed from inner class
        final DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this);

        // Open the database
        databaseAccess.open();

        // Read all the names
        final List<String> names = databaseAccess.getNames();

        // Close the database
        databaseAccess.close();

        // Create adapter and set to the Spinner
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, names);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        this.cmbName.setAdapter(adapter);
    }
}

Step 7:
Set OnItemSelectedListener to Spinner and retrieve the image of the selected place from the database and convert it to Bitmap using toBitmap method as shown below.
package com.javahelps.imagedatabasedemo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Spinner;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private Spinner cmbName;
    private ImageView imgPlace;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize the UI components
        this.cmbName = (Spinner) findViewById(R.id.cmbName);
        this.imgPlace = (ImageView) findViewById(R.id.imgPlace);

        // Define final variables since they have to be accessed from inner class
        final DatabaseAccess databaseAccess = DatabaseAccess.getInstance(this);

        // Open the database
        databaseAccess.open();

        // Read all the names
        final List<String> names = databaseAccess.getNames();

        // Close the database
        databaseAccess.close();

        // Create adapter and set to the Spinner
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, names);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        this.cmbName.setAdapter(adapter);

        this.cmbName.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                // Get the selected name
                String name = names.get(position);

                // Open the database
                databaseAccess.open();

                // Retrieve the selected image as byte[]
                byte[] data = databaseAccess.getImage(name);
                // Convert to Bitmap
                Bitmap image = toBitmap(data);
                // Set to the imgPlace
                imgPlace.setImageBitmap(image);

                // Close the database
                databaseAccess.close();
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                // Do nothing
            }
        });
    }

    /**
     * Convert byte[] to Bitmap
     *
     * @param image
     * @return
     */
    public static Bitmap toBitmap(byte[] image) {
        return BitmapFactory.decodeByteArray(image, 0, image.length);
    }
}
Step 8:
Save all the changes and run the application.



Find the project at Git Hub.
Previous
Next Post »

16 comments

Write comments
Felix
AUTHOR
April 10, 2016 at 5:29 PM delete

Just ask, of on thats you using spinner,how about using listview and images only?

Reply
avatar
Gobinath
AUTHOR
April 10, 2016 at 8:45 PM delete

Its all about your preference. I just wanted to keep the project as simple as possible so that the readers can well focus on the database related issues. That's the only reason for selecting Spiner :). By the way, I would suggest ViewPager than ListView for sliding images.

Reply
avatar
Felix
AUTHOR
April 11, 2016 at 12:28 PM delete

Hi Thanks sir for your answer :),
im try this code and run 100% , but idk how to retrieve image on text in a same time on listview , bc if i have hundresd picture its not effective if i call all image from drawable so im using this way, but still dont know how to do that

Reply
avatar
Gobinath
AUTHOR
April 11, 2016 at 9:42 PM delete

Try this code where you have to pack the name and image into Place objects and return the List to MainActivity. Then display them using a customized ListView. Check the following link for customized ListView [1].

public List getImage(String name) {
List list = new ArrayList();
Cursor cursor = database.rawQuery("SELECT * FROM places", null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
Place place = new Place(cursor.getString(0), cursor.getBlob(1));
list.add(place);
cursor.moveToNext();
}
cursor.close();
return list;
}

class Place {
private String name;
private byte[] image;
public Place(String name, byte[] image) {
this.name = name;
this.image = image;
}
// getter methods
}

[1] http://www.javahelps.com/2015/02/android-customized-listview.html

Reply
avatar
Felix
AUTHOR
April 14, 2016 at 9:46 AM delete

hi sorry again :D, i think thebest one is save images on drawable resource, but how to retrieve some data on list with exactly images using custom listview?

Reply
avatar
Gobinath
AUTHOR
April 17, 2016 at 5:32 PM delete

Hi,
Try this code to retrieve the drawable images using their name.\

String imageName = "sample";
int id = this.getResources().getIdentifier(imageName, "drawable", this.getPackageName());
this.imageView.setImageResource(id);

Save the image names in the database or strings.xml and using them retrieve the images at the runtime.

Reply
avatar
asmaa abdelaal
AUTHOR
April 20, 2016 at 2:54 AM delete

hi.i had followed the steps but it gives me the failed open libwvm.so . how can i fix this error ?
and another question is anyone have an idea about matching images ?

Reply
avatar
Gobinath
AUTHOR
April 20, 2016 at 6:36 AM delete

Hi,
Can you test the application on a newly created emulator with Android 6 and check whether it is working or not?

Reply
avatar
asmaa abdelaal
AUTHOR
April 21, 2016 at 12:01 AM delete

hi again ,
i had do that but each time i try to run my application ,it gives me this message.

Cannot launch AVD in emulator.
Output:
emulator: WARNING: VM heap size set below hardware specified minimum of 256MB
emulator: WARNING: Setting VM heap size to 384MB
emulator: ERROR: x86 emulation currently requires hardware acceleration!
Please ensure Intel HAXM is properly installed and usable.
CPU acceleration status: Android Emulator requires an Intel processor with VT-x and NX support. Your CPU: 'AuthenticAMD'.
sorry sir ,but could you tell me what should i do ?

Reply
avatar
Gobinath
AUTHOR
April 21, 2016 at 7:30 AM delete

Hi,
I think your processor is AMD not Intel. If so, create the emulator using armeabi system image (Look at the screenshot). If it is Intel, install the Intel Hardware Accelerated Execution Manager as shown in this link [1]

[1] https://software.intel.com/en-us/android/articles/installation-instructions-for-intel-hardware-accelerated-execution-manager-windows

Reply
avatar
asmaa abdelaal
AUTHOR
April 26, 2016 at 4:08 AM delete

sorry for being late. the Intel Hardware Accelerated Execution Manager is already installed so i create a new avd device using armeabi system image as you told me . thank you for helping me and for your time ,but unfortunately the app does not work with me :/

Reply
avatar
Gobinath
AUTHOR
April 26, 2016 at 6:04 AM delete

Hi,
Did you get the same error (if not please share the error message)? Also I want to know whether it happens only for this app or for all the applications.

Reply
avatar
Gobinath
AUTHOR
April 28, 2016 at 9:41 AM delete

Hi,
Try these steps:
Step 1: Delete your existing virtual device and create a new one with enough memory (Don't alter the default settings)
Step 2: Make sure that you have images.db.zip in assets/databases folder and the DATABASE_NAME in DatabaseOpenHelper is "images.db", because there is a RuntimeException.
Step 3: Run the application and test the output.

If you still get the error, try the solution given in this StackOverflow answer: [1]

[1]: http://stackoverflow.com/a/27989207/4382663

Reply
avatar
asmaa abdelaal
AUTHOR
May 11, 2016 at 1:06 AM delete

i'm so sorry but you are the only one who helped me . currently i'm doing my graduation project .it is an android application in which i have to use cordova and c ,c++ code using android studio .i have created a cordova-based project and then import it in android studio,then i have installed ndk but it gives me

Exception in thread "main" java.lang.IllegalArgumentException: Not a valid class name: Files\Java\jdk1.8.0_65\jre\lib\charsets.jar;C:\Program
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:129)
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:107)
at com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:64)
at com.sun.tools.javah.JavahTask.run(JavahTask.java:503)
at com.sun.tools.javah.JavahTask.run(JavahTask.java:329)
at com.sun.tools.javah.Main.main(Main.java:46)
could you help me ??

Reply
avatar
Kayo Matheus
AUTHOR
October 28, 2016 at 1:10 AM delete

Hi,
Had followed the Steos but in BitmapFactory, returned null. :( I'm add images with sqliteman too. Thanks :)

Reply
avatar
Gobinath
AUTHOR
October 31, 2016 at 8:33 AM delete

Sorry for the late reply. Try to uninstall the application from the device and install it again. If it does not solve the problem, comment below your logcat error message.

Reply
avatar

Contact Form

Name

Email *

Message *