I have search hi and low, read many different post and tutorials but yet I can't seem to figure out how to get my images to save in a database.
It seems that every time I attempt to put an image into the database it causes the database to not be created and then I get a force close. I would love some help.
Here is my code
package com.ondrovic.boombozzpassport;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.provider.BaseColumns;
import android.util.Log;
public class Database extends SQLiteOpenHelper implements BaseColumns {
private final static String DB_NAME = "boombozz.db";
private final static int DB_VERSION = 1;
static final String TABLE_BEERS = "beers";
static final String COL_NAME = "name";
static final String COL_BREWER = "brewer";
static final String COL_ABV = "abv";
static final String COL_RATE = "rating";
static final String COL_BDESC = "breifdescription";
static final String COL_FDESC = "fulldescription";
static final String COL_TYPE = "type";
static final String COL_PIC = "picture";
private Context mContext;
private Bitmap picture = null;
public Database(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE beers (" + "_id INTEGER PRIMARY KEY, "
+ "name TEXT, " + "brewer TEXT, " + "abv REAL, "
+ "rating REAL, " + "breifdescription TEXT, "
+ "fulldescription TEXT, " + "type TEXT, " + "picture BLOB);");
addBeer(db, "NAME 1", "BREWER 1", "TYPE 1", "BDESC 1", "FDESC 1", 0, 0, R.drawable.beer1);
}
private void addBeer(SQLiteDatabase db, String name, String brewer,
String type, String bdesc, String fdesc, int abv, int rate, int image) {
final ContentValues cv = new ContentValues();
cv.put(COL_NAME, name);
cv.put(COL_BREWER, brewer);
cv.put(COL_TYPE, type);
cv.put(COL_BDESC, bdesc);
cv.put(COL_FDESC, fdesc);
cv.put(COL_ABV, abv);
cv.put(COL_RATE, rate);
final Bitmap bitmap = BitmapFactory.decodeResource(
mContext.getResources(), image);
writeBitmap(cv, COL_PIC, bitmap);
db.insert(TABLE_BEERS, null, cv);
}
static void writeBitmap(ContentValues cv, String name, Bitmap image) {
if (image != null) {
try {
int size = image.getWidth() * image.getHeight() * 2;
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
image.compress(CompressFormat.PNG, 100, out);
out.flush();
out.close();
cv.put(name, out.toByteArray());
} catch (IOException e) {
}
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w("onUpgrade", "Upgrading database from version: " + oldVersion
+ " to version: " + newVersion);
db.execSQL("DROP TABLE IF EXISTS beers");
}
}
Are you downloading those images? If yes, save it to the SDCard/Phone Memory as suggested by Venkata Krishna. It's pretty simple to save your image into the disk.
First we create a method to check if we can read and write into the external storage disk.
/**
* #return true if the external storage is mounted or read only.
*/
public static boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);
}
/**
* #return true if the external storage is mounted and writable.
*/
public static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}
Then, another method that will check if we have enough space available in the external storage disk.
/**
* #return the amount of free space on the external storage.
*/
public static long getAvailableExternalMemorySize() {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
Now we create the method that will tell us if we can store the file in the sdcard.
/**
* #return true if the external storage is available, writable,
* and contains enough free space.
*/
public static boolean isExternalStorageAvailable() {
if (!isExternalStorageWritable()) return false;
long availableSize = getAvailableExternalMemorySize();
if (availableSize < REQUIRED_STORAGE_SPACE) {
return false;
}
return true;
}
Where REQUIRED_STORAGE_SPACE is a constant with the amount of space that your app will use to store images and other stuff.
Now we'll create a method to store the image.
/**
* #return the File from the given filename.
*/
public static File getImageFile(String filename) {
if (!isExternalStorageReadable()) return null;
// The images folder path.
String imagesFolder = Environment.getExternalStorageDirectory().getPath()
+ "Android/data/your.app.package/images/";
// Creating the file.
File file = new File(imagesFolder + filename);
return file;
}
/**
* Write the contents of the HTTP entity to the external
* storage if available and writable.
*/
public static boolean storeImage(HttpEntity entity, String filename) throws IOException {
if (isExternalStorageAvailable()) {
File file = getImageFile(filename);
if (file == null) return false;
// Write to file output stream.
FileOutputStream os = new FileOutputStream(file);
entity.writeTo(os);
os.close();
return true;
}
return false;
}
Put all of these methods into a class, let's say ImageHelper, check if you have permissions in your manifest file to write into the external storage and you are good to go.
save image in sdcard or phone memory and store that saved image path in database.whenever you want to access the image then take image path from database and using that path access image.
Related
I've been struggling to create a SQLite DB within my Android application.
I've looked at numerous tutorials, and quite a few existing questions on stack overflow and other sites.
Here is my DatabaseHelper class
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DatabaseHelper extends SQLiteOpenHelper {
public SQLiteDatabase db;
public static final String DATABASE_NAME = "user.db";
//Module table
public static final String MODULE_TABLE = "modules_table";
public static final String MODULE_COL_1 = "ID";
public static final String MODULE_COL_2 = "CODE";
public static final String MODULE_COL_3 = "TITLE";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
Log.d("SQL", "SQLite dbhelper");
db = getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
//db.execSQL("create table " + MODULE_TABLE + "(" + MODULE_COL_1 + " INTEGER PRIMARY KEY AUTOINCREMENT, " + MODULE_COL_2 + " TEXT, " + MODULE_COL_3 + " TEXT " +")");
db.execSQL("create table modules_table (ID INTEGER PRIMARY KEY
AUTOINCREMENT, CODE TEXT, TITLE TEXT)");
Log.d("SQL", "SQLite onCreate");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + MODULE_TABLE);
onCreate(db);
}
}
I've managed to get SQLite dbhelper to appear in logcat, but cannot get SQLite onCreate to appear, and cannot find the db anywhere in the file explorer or the device itself, both emulated and real device.
Any help would be greatly appreciated, and apologies for the formatting of the code!
I'd suggest using the following (temporarily) in the activity :-
DatabaseHelper myDBHelper = new DatabaseHelper(this); //<<<<<<<<< you appear to already have the equivalent of this line (if so use whatever variable name you have given to the DatabaseHelper object)
Cursor csr = myDBHelper.getWritableDatabase().query("sqlite_master",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(csr);
csr.close();
Run and then check the log. You should see output for your modules_table and also sqlite_sequence (the latter because you have coded autoincrement.
sqlite_master is a system table that stores system information, such as table and index names i.e. the schema.
Additional - access to the database file
On a device that isn't rooted each applications data (data/data) is protected so you won't be able to see the database file.
On an emulator, it depends upon the emulator. I believe later versions of Android studio do now allow access e.g. :-
Note the above is Android 10.1 Pie (API 28) and hence the database has Write-Ahead Logging (WAL) and thus the -shm and -wal files also exist.
The package is mjt.pvcheck. The full path is data/data/mjt.pvcheck/databases.
As you can see cache directory, then I'd suggest that for some reason, perhaps a failure, the database doesn't exist, but you do appear to have access as per however upon checking through the virtual device file explorer the only sub folder I have within my package is the cache.
Perhaps, try rerunning on the device (note in device explorer re-select the device as it doesn't refresh), which may be another reason why you didn't see the database.
I don't use SQL query like
db.execSQL("create table modules_table (ID INTEGER PRIMARY KEY
AUTOINCREMENT, CODE TEXT, TITLE TEXT)");
Log.d("SQL", "SQLite onCreate");
instead, I'm using my own implementation of SQLiteOpenHelper class
import android.content.Context;
import android.content.res.AssetManager;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.zip.GZIPOutputStream;
public class DbProvider extends SQLiteOpenHelper {
private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(true);
private static final int VERSION = 0;
private final String DB_NAME = "mydb";
private final AssetManager assets;
private DbProvider(Context context) {
super(context, DB_NAME, null, VERSION);
assets = context.getAssets();
}
#NonNull
public static DbProvider getInstance() {
return new DbProvider(App.getContext());
}
#NonNull
public static ReentrantReadWriteLock.WriteLock writeLock() {
return LOCK.writeLock();
}
#NonNull
public static ReentrantReadWriteLock.ReadLock readLock() {
return LOCK.readLock();
}
#NonNull
public static ReentrantReadWriteLock getLock() {
return LOCK;
}
public static void close(DbProvider instance) {
try {
instance.close();
} catch (Exception ex) {
}
}
#Override
public void onCreate(SQLiteDatabase db) {
executeQuery(db, "db-scripts/database.sql", false);
Log.w("database", "database create");
executeQuery(db, "db-scripts/database_updates.sql", true);
Log.w("database", "database update");
}
private void executeQuery(SQLiteDatabase db, String sql, boolean shouldHandleExceptions) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new InputStreamReader(assets.open(sql)));
String line;
File tempDbScript = new File(Environment.getExternalStorageDirectory(), "iErunt/dbBackup");
tempDbScript.getParentFile().mkdirs();
tempDbScript.createNewFile();
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(tempDbScript));
while ((line = bufferedReader.readLine()) != null) {
line = line.replaceAll("\t+", " ").replaceAll("\n+", " ").replaceAll(" +", " ").replaceAll(";", ";\n");
if (line.startsWith("--") || line.isEmpty()) {
continue;
}
bufferedWriter.write(line);
bufferedWriter.flush();
}
bufferedWriter.close();
bufferedReader.close();
bufferedReader = new BufferedReader(new FileReader(tempDbScript));
db.beginTransaction();
while ((line = bufferedReader.readLine()) != null) {
if (!(line = line.trim().replace(";", "")).isEmpty()) {
if (shouldHandleExceptions) {
try {
db.execSQL(line);
} catch (SQLException ex) {
Log.e("database", ex.getMessage(), ex);
}
} else {
db.execSQL(line);
}
}
}
db.setTransactionSuccessful();
db.endTransaction();
tempDbScript.delete();
} catch (IOException ex) {
Log.e("database", ex.getMessage(), ex);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
}
}
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
executeQuery(db, "db-scripts/database_updates.sql", true);
}
}
and put initial DB schema of your database in assets/db-scripts/database.sql
and whenever you make DB modifications put your alter queries in assets/db-scripts/database_updates.sql. Be sure to increase VERSION of the database when updating the database.
What this class does is read your entire SQL script and executes one by one. which significantly reduces development time.
Note: You'll need android.permission.WRITE_EXTERNAL_STORAGE permission, as this creates a temp file and deletes it at the end
Hope this helps!
I added a pre-populated database to the assets directory in an Android App, but when I delete and add a new one the query results still return old data.
I followed this tutorial, and below is my database class:
package com.example.fishselector;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import android.content.ContentValues;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
class DB extends SQLiteOpenHelper {
private static String DB_PATH = "/data/data/com.example.fishselector/databases/";
private static String DB_NAME = "sqldb3";
private SQLiteDatabase myDataBase;
private final Context myContext;
/**
* Constructor
* Takes and keeps a reference of the passed context in order to access to the application assets and resources.
* #param context
*/
public DB(Context context) {
super(context, DB_NAME, null, 1);
this.myContext = context;
}
/**
* Creates a empty database on the system and rewrites it with your own database.
* */
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
//do nothing - database already exist
} else {
//By calling this method and empty database will be created into the default system path
//of your application so we are gonna be able to overwrite that database with our database.
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* #return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
//database does't exist yet.
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
/**
* Copies your database from your local assets-folder to the just created empty database in the
* system folder, from where it can be accessed and handled.
* This is done by transfering bytestream.
* */
private void copyDataBase() throws IOException {
//Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
//Open the database
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
#
Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
#
Override
public void onCreate(SQLiteDatabase db) {
try {
createDataBase();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#
Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
// Add your public helper methods to access and get content from the database.
// You could return cursors by doing "return myDataBase.query(....)" so it'd be easy
// to you to create adapters for your views.
}
It's not working because you are not deleting the database file on the file system.
What your code does is copy the file from assets into the private storage area for your app in /data/data/com.example.fishselector/databases/.
Then the next time you run it you check if it already exists there, and if it does, do nothing:
boolean dbExist = checkDataBase();
if (dbExist) {
//do nothing - database already exist
} else {
So simply deleting it or replacing it in assets won't mean a thing because hey ho, there it still is, in /data/data/ as if nothing happened.
To fix: in your emulator, go into "Settings/Apps/YourApp/" and click "Clear Data". This will delete any data in the private storage area for your app. Then you can try and run your app again and it will not find the file and will copy your new database over from assets.
I'm writing a Java-based program that downloads a JavaScript file from GitHub, parses it into a String, and then pushes it to a MediaWiki site. The problem is that the JS file has fairly complicated regex in it, and Java is parsing it into escape characters (e.g. [^\S\r\n] getting parsed into /\s). Is there a way I can store a String without these escape characters being activated?
EDIT: The code:
package org.wikipedia.afchbuddy;
import java.io.IOException;
import static java.lang.System.*;
import java.nio.file.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.channels.*;
import java.net.URL;
import java.io.FileOutputStream;
import javax.security.auth.login.LoginException;
/**
* This is a bot script designed to allow sysops to push releases for AFCH
* on-wiki.
*
* #author Nathan2055
*/
public class AFCHBuddy {
private static String username;
private static String password;
private static String location;
private static String buffer;
private static String error = "An error occured trying to access and write to Wikipedia. If you report this error, please provide the following debug info:";
private static String basescript = "https://raw.github.com/WPAFC/afch/develop/src/";
private static String basescript_stable = "https://raw.github.com/WPAFC/afch/master/src/";
private static String mediawikilocation = "MediaWiki:Gadget-afchelper.js";
/**
* The main bot script.
*
* #param args This program accepts three command line arguments, 0 is the
* push location (stable, beta, or testwiki), 1 is your username, and 2 is
* your password.
*/
public static void main(String[] args) {
if (args.length != 3) {
err.println("Incorrect number of arguments. Please see the README for more information.");
System.exit(1);
}
location = args[0];
username = args[1];
password = args[2];
switch (location) {
case "testwiki":
build("testwiki");
break;
case "beta":
build("beta");
break;
case "stable":
build("stable");
break;
default:
err.println("Error: Unknown build location.");
System.exit(1);
}
}
/**
* This method does the actual work of performing the edits.
*
* #param destarg The destination wiki.
*/
private static void build(String destarg) {
Wiki wiki;
try {
if ("testwiki".equals(destarg)) {
wiki = new Wiki("test.wikipedia.org");
} else {
wiki = new Wiki();
}
wiki.login(username, password);
downloadFile(basescript + "MediaWiki:Gadget-afchelper.js", "afch.js");
buffer = readFile("afch.js");
wiki.edit(mediawikilocation, buffer, "Update afch.js using AFCHBuddy");
downloadFile(basescript + "MediaWiki:Gadget-afchelper.css", "afch.css");
buffer = readFile("afch.css");
wiki.edit("MediaWiki:Gadget-afchelper.css", buffer, "Update afch.css using AFCHBuddy");
downloadFile(basescript + "core.js", "core.js");
buffer = readFile("core.js");
wiki.edit(mediawikilocation + "/core.js", buffer, "Update core.js using AFCHBuddy");
downloadFile(basescript + "redirects.js", "redirects.js");
buffer = readFile("redirects.js");
wiki.edit(mediawikilocation + "/redirects.js", buffer, "Update redirects.js using AFCHBuddy");
downloadFile(basescript + "submissions.js", "submissions.js");
buffer = readFile("submissions.js");
wiki.edit(mediawikilocation + "/submissions.js", buffer, "Update submissions.js using AFCHBuddy");
downloadFile(basescript + "ffu.js", "ffu.js");
buffer = readFile("ffu.js");
wiki.edit(mediawikilocation + "/ffu.js", buffer, "Update ffu.js using AFCHBuddy");
wiki.logout();
err.println("Files syncronized successfully.");
System.exit(0);
} catch (IOException | LoginException e) {
err.println(error);
e.printStackTrace(err);
System.exit(1);
}
}
/**
* Converts a file to a String.
*
* #param path This accepts the path of the file to be processed in String
* form.
* #return The output String.
* #throws IOException The exception if something goes wrong while reading
* the file.
*/
private static String readFile(String path) throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return Charset.defaultCharset().decode(ByteBuffer.wrap(encoded)).toString();
}
/**
* This downloads the input URL and saves it to dest.
*
* #param URL The file's location on the internet.
* #param dest The file's soon to be location on your computer.
* #throws IOException The exception if something goes wrong while
* processing.
*/
private static void downloadFile(String URL, String dest) throws IOException {
URL website = new URL(URL);
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(dest);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
}
Kind of need help understanding what this code actually outputs. Does it out put a uuid to a file?
I found it on http://android-developers.blogspot.com/2011/03/identifying-app-installations.html
public synchronized static String id(Context context) {
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private static String readInstallationFile(File installation) throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(File installation) throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
out.write(id.getBytes());
out.close();
}
}
The code exactly how it is posted in my app.
package com.UUIID;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.util.Log;
import java.io.RandomAccessFile;
import java.util.UUID;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.TextView;
public class UUIDActivity extends Activity {
/** Called when the activity is first created. */
TextView text;
private static final String TAG = "Installation";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "program started");
text = (TextView) findViewById(R.id.textfield);
}
class Installation {
private String sID = null;
private static final String INSTALLATION = "INSTALLATION";
public synchronized String id(Context context) {
if (sID == null) {
File installation = new File(context.getFilesDir(),
INSTALLATION);
try {
if (!installation.exists())
writeInstallationFile(installation);
Log.d(TAG, "Inside of installation If statement");
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private String readInstallationFile(File installation)
throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
Log.d(TAG, "Right before it calls f to close");
f.close();
return new String(bytes);
}
private void writeInstallationFile(File installation)
throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id = UUID.randomUUID().toString();
Log.d(TAG, "Right before the file gets written out.");
out.write(id.getBytes());
out.close();
}
}
}
public synchronized static String id(Context context)
returns a persistent UUID (generated by UUID.randomUUID()). In other words, it will return the same UUID every time. As #Alonso Domiguez answered, it's probably an installation ID, based on the naming. The goal is to give each instance of the application that uses this code a unique ID.
The trick here is
if (!installation.exists())
writeInstallationFile(installation);
sID = readInstallationFile(installation);
The function:
writeInstallationFile(installation)
generates a random UUID, and writes that the UUID to a hard-coded file. However, it will only be called once; because after the first call, !installation.exists() will always be false (because the writing of the UUID creates that file).
From my point of view it returns the UUID of the installation, not "a UUID to a file" as such thing doesn't exist.
The UUID gets generated the first time you try to get that ID for the installation and stored inside a file so further calls using the same context will return that previous generated UUID.
The code returns a random UUID, which is persisted to a file. If the UUID was already generated it reads it from the file, otherwise it creates it randomly and then saves it to the file
This question already has answers here:
Ship an application with a database
(15 answers)
Closed 9 years ago.
I have already created an SQLite database. I want to use this database file with my Android project. I want to bundle this database with my application.
Instead of creating a new database, how can the application gain access to this database and use it as its database?
NOTE:
Before trying this code, please find this line in the below code:
private static String DB_NAME ="YourDbName"; // Database name
DB_NAME here is the name of your database. It is assumed that you have a copy of the database in the assets folder, so for example, if your database name is ordersDB, then the value of DB_NAME will be ordersDB,
private static String DB_NAME ="ordersDB";
Keep the database in assets folder and then follow the below:
DataHelper class:
import java.io.File;
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 DataBaseHelper extends SQLiteOpenHelper {
private static String TAG = "DataBaseHelper"; // Tag just for the LogCat window
private static String DB_NAME ="YourDbName"; // Database name
private static int DB_VERSION = 1; // Database version
private final File DB_FILE;
private SQLiteDatabase mDataBase;
private final Context mContext;
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
DB_FILE = context.getDatabasePath(DB_NAME);
this.mContext = context;
}
public void createDataBase() throws IOException {
// If the database does not exist, copy it from the assets.
boolean mDataBaseExist = checkDataBase();
if(!mDataBaseExist) {
this.getReadableDatabase();
this.close();
try {
// Copy the database from assests
copyDataBase();
Log.e(TAG, "createDatabase database created");
} catch (IOException mIOException) {
throw new Error("ErrorCopyingDataBase");
}
}
}
// Check that the database file exists in databases folder
private boolean checkDataBase() {
return DB_FILE.exists();
}
// Copy the database from assets
private void copyDataBase() throws IOException {
InputStream mInput = mContext.getAssets().open(DB_NAME);
OutputStream mOutput = new FileOutputStream(DB_FILE);
byte[] mBuffer = new byte[1024];
int mLength;
while ((mLength = mInput.read(mBuffer)) > 0) {
mOutput.write(mBuffer, 0, mLength);
}
mOutput.flush();
mOutput.close();
mInput.close();
}
// Open the database, so we can query it
public boolean openDataBase() throws SQLException {
// Log.v("DB_PATH", DB_FILE.getAbsolutePath());
mDataBase = SQLiteDatabase.openDatabase(DB_FILE, null, SQLiteDatabase.CREATE_IF_NECESSARY);
// mDataBase = SQLiteDatabase.openDatabase(DB_FILE, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
return mDataBase != null;
}
#Override
public synchronized void close() {
if(mDataBase != null) {
mDataBase.close();
}
super.close();
}
}
Write a DataAdapter class like:
import java.io.IOException;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
public class TestAdapter {
protected static final String TAG = "DataAdapter";
private final Context mContext;
private SQLiteDatabase mDb;
private DataBaseHelper mDbHelper;
public TestAdapter(Context context) {
this.mContext = context;
mDbHelper = new DataBaseHelper(mContext);
}
public TestAdapter createDatabase() throws SQLException {
try {
mDbHelper.createDataBase();
} catch (IOException mIOException) {
Log.e(TAG, mIOException.toString() + " UnableToCreateDatabase");
throw new Error("UnableToCreateDatabase");
}
return this;
}
public TestAdapter open() throws SQLException {
try {
mDbHelper.openDataBase();
mDbHelper.close();
mDb = mDbHelper.getReadableDatabase();
} catch (SQLException mSQLException) {
Log.e(TAG, "open >>"+ mSQLException.toString());
throw mSQLException;
}
return this;
}
public void close() {
mDbHelper.close();
}
public Cursor getTestData() {
try {
String sql ="SELECT * FROM myTable";
Cursor mCur = mDb.rawQuery(sql, null);
if (mCur != null) {
mCur.moveToNext();
}
return mCur;
} catch (SQLException mSQLException) {
Log.e(TAG, "getTestData >>"+ mSQLException.toString());
throw mSQLException;
}
}
}
Now you can use it like:
TestAdapter mDbHelper = new TestAdapter(urContext);
mDbHelper.createDatabase();
mDbHelper.open();
Cursor testdata = mDbHelper.getTestData();
mDbHelper.close();
EDIT: Thanks to JDx
For Android 4.1 (Jelly Bean), change:
DB_PATH = "/data/data/" + context.getPackageName() + "/databases/";
to:
DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
in the DataHelper class, this code will work on Jelly Bean 4.2 multi-users.
EDIT: Instead of using hardcoded path, we can use
DB_PATH = context.getDatabasePath(DB_NAME).getAbsolutePath();
which will give us the full path to the database file and works on all Android versions
If you are having pre built data base than copy it in asset folder and create an new class as DataBaseHelper which implements SQLiteOpenHelper
Than use following code:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DataBaseHelperClass extends SQLiteOpenHelper{
//The Android's default system path of your application database.
private static String DB_PATH = "/data/data/package_name/databases/";
// Data Base Name.
private static final String DATABASE_NAME = "DBName.sqlite";
// Data Base Version.
private static final int DATABASE_VERSION = 1;
// Table Names of Data Base.
static final String TABLE_Name = "tableName";
public Context context;
static SQLiteDatabase sqliteDataBase;
/**
* Constructor
* Takes and keeps a reference of the passed context in order to access to the application assets and resources.
* #param context
* Parameters of super() are 1. Context
* 2. Data Base Name.
* 3. Cursor Factory.
* 4. Data Base Version.
*/
public DataBaseHelperClass(Context context) {
super(context, DATABASE_NAME, null ,DATABASE_VERSION);
this.context = context;
}
/**
* Creates a empty database on the system and rewrites it with your own database.
* By calling this method and empty database will be created into the default system path
* of your application so we are gonna be able to overwrite that database with our database.
* */
public void createDataBase() throws IOException{
//check if the database exists
boolean databaseExist = checkDataBase();
if(databaseExist){
// Do Nothing.
}else{
this.getWritableDatabase();
copyDataBase();
}// end if else dbExist
} // end createDataBase().
/**
* Check if the database already exist to avoid re-copying the file each time you open the application.
* #return true if it exists, false if it doesn't
*/
public boolean checkDataBase(){
File databaseFile = new File(DB_PATH + DATABASE_NAME);
return databaseFile.exists();
}
/**
* Copies your database from your local assets-folder to the just created empty database in the
* system folder, from where it can be accessed and handled.
* This is done by transferring byte stream.
* */
private void copyDataBase() throws IOException{
//Open your local db as the input stream
InputStream myInput = context.getAssets().open(DATABASE_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DATABASE_NAME;
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//transfer bytes from the input file to the output file
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
/**
* This method opens the data base connection.
* First it create the path up till data base of the device.
* Then create connection with data base.
*/
public void openDataBase() throws SQLException{
//Open the database
String myPath = DB_PATH + DATABASE_NAME;
sqliteDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}
/**
* This Method is used to close the data base connection.
*/
#Override
public synchronized void close() {
if(sqliteDataBase != null)
sqliteDataBase.close();
super.close();
}
/**
* Apply your methods and class to fetch data using raw or queries on data base using
* following demo example code as:
*/
public String getUserNameFromDB(){
String query = "select User_First_Name From "+TABLE_USER_DETAILS;
Cursor cursor = sqliteDataBase.rawQuery(query, null);
String userName = null;
if(cursor.getCount()>0){
if(cursor.moveToFirst()){
do{
userName = cursor.getString(0);
}while (cursor.moveToNext());
}
}
return userName;
}
#Override
public void onCreate(SQLiteDatabase db) {
// No need to write the create table query.
// As we are using Pre built data base.
// Which is ReadOnly.
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// No need to write the update table query.
// As we are using Pre built data base.
// Which is ReadOnly.
// We should not update it as requirements of application.
}
}
Hope this will help you...
I had trouble with the other DatabaseHelpers regarding this problem, not sure why.
This is what worked for me:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = DatabaseHelper.class.getSimpleName();
private final Context context;
private final String assetPath;
private final String dbPath;
public DatabaseHelper(Context context, String dbName, String assetPath)
throws IOException {
super(context, dbName, null, 1);
this.context = context;
this.assetPath = assetPath;
this.dbPath = "/data/data/"
+ context.getApplicationContext().getPackageName() + "/databases/"
+ dbName;
checkExists();
}
/**
* Checks if the database asset needs to be copied and if so copies it to the
* default location.
*
* #throws IOException
*/
private void checkExists() throws IOException {
Log.i(TAG, "checkExists()");
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
Log.i(TAG, "creating database..");
dbFile.getParentFile().mkdirs();
copyStream(context.getAssets().open(assetPath), new FileOutputStream(
dbFile));
Log.i(TAG, assetPath + " has been copied to " + dbFile.getAbsolutePath());
}
}
private void copyStream(InputStream is, OutputStream os) throws IOException {
byte buf[] = new byte[1024];
int c = 0;
while (true) {
c = is.read(buf);
if (c == -1)
break;
os.write(buf, 0, c);
}
is.close();
os.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
If you already have a database, keep it in your asset folder and copy it in your application. For more detail, see Android database basics.
You can do this by using a content provider. Each data item used in the application remains private to the application. If an application want to share data accross applications, there is only technique to achieve this, using a content provider, which provides interface to access that private data.