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.
16 comments
Write commentsJust ask, of on thats you using spinner,how about using listview and images only?
ReplyIts 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.
ReplyHi Thanks sir for your answer :),
Replyim 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
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].
Replypublic 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
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?
ReplyHi,
ReplyTry 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.
hi.i had followed the steps but it gives me the failed open libwvm.so . how can i fix this error ?
Replyand another question is anyone have an idea about matching images ?
Hi,
ReplyCan you test the application on a newly created emulator with Android 6 and check whether it is working or not?
hi again ,
Replyi 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 ?
Hi,
ReplyI 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
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 :/
ReplyHi,
ReplyDid 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.
Hi,
ReplyTry 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
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
ReplyException 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 ??
Hi,
ReplyHad followed the Steos but in BitmapFactory, returned null. :( I'm add images with sqliteman too. Thanks :)
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.
ReplyEmoticonEmoticon