I use the following code to export the database file to the phone memory. It works fine on Android 24 , but on API 28 it only gives an empty file:
public void exportDatabse() {
try {
if (sd.canWrite()) {
String backupDBPath = "nameBCK.db";
File currentDB = new File(MainActivity.this.getDatabasePath("dataBaseName.db").getPath());
File backupDB = new File(sd, backupDBPath);
if (currentDB.exists()) {
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(this,getString(R.string.stSuccess2),
Toast.LENGTH_LONG).show();
}
}
else {
REQUEST_TYPE=0;
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);}
} catch (Exception e) {
Toast.makeText(this,getString(R.string.stFaild),Toast.LENGTH_LONG).show();
}
}
And also I use onRequestPermissionsResult to request permission to write to storage.
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (REQUEST_TYPE==0) exportDatabse();
if (REQUEST_TYPE==1) importDB();
} else {
if (REQUEST_TYPE==0) Toast.makeText(this,getString(R.string.stFaild2),Toast.LENGTH_LONG).show();
if (REQUEST_TYPE==1) Toast.makeText(this,getString(R.string.stFaild3),Toast.LENGTH_LONG).show();
Log.e("value", "Permission Denied, You cannot use local drive .");
}
break;
default:
throw new IllegalStateException("Unexpected value: " + requestCode);
}
}
I have already answered this question. This problem only occurs on Android 28.
link
public class DataBase extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "database.db";
private static String DATABASE_PATH = "";
private static String LAST_DATABASE_PATH = "";
private SQLiteDatabase mDataBase;
private final Context ctx;
public DataBase2(#Nullable Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
DATABASE_PATH = context.getDatabasePath(DATABASE_NAME).getPath();
this.ctx = context;
if (!checkIfDBExists()) {
createDataBase();
}
File dbFile = new File(Environment.getDataDirectory().getPath()+"/data/"+ BuildConfig.APPLICATION_ID +"/databases");
if (dbFile.isDirectory()) {
String[] child = dbFile.list();
assert child != null;
for (int i = 0; i < child.length; i++) {
if (!(child[i].equals("database.db") || child[i].equals(DATABASE_NAME))) {
new File(dbFile, child[i]).delete();
}
}
}
}
public void createDataBase() {
this.getReadableDatabase();
this.close();
try {
copyDataBase();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try {
File DbFile = ctx.getDatabasePath(DATABASE_NAME);
if (DbFile.exists()) {
copyDataBase();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean checkIfDBExists() {
File dbFile = new File(DATABASE_PATH);
return dbFile.exists();
}
public void openDataBase() {
close();
mDataBase = SQLiteDatabase.openDatabase(DATABASE_PATH, null, CREATE_IF_NECESSARY);
}
private void copyDataBase() throws IOException {
InputStream mInput = ctx.getAssets().open("database.db");
String outfileName = DATABASE_PATH;
OutputStream mOutput = new FileOutputStream(outfileName);
byte[] buffer = new byte[1024];
int mLength;
while ((mLength = mInput.read(buffer)) > 0) {
mOutput.write(buffer, 0, mLength);
}
mOutput.flush();
mInput.close();
mOutput.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public synchronized void close() {
if (mDataBase != null)
mDataBase.close();
SQLiteDatabase.releaseMemory();
super.close();
}
}
I found the solution in two things
The First disable Write Ahead Logging using use the SQliteDatabase like said here:
Environment.getExternalStorageDirectory() deprecated in API level 29 java
The Secound use getExternalFilesDir(), getExternalCacheDir(), or getExternalMediaDir() (methods on Context) instead of Environment.getExternalStorageDirectory() ....like said here:
Environment.getExternalStorageDirectory() deprecated in API level 29 java
This two things solved the issue for me.
Related
I have an android application which downloads and play mp3 files. But I want to encrypt audio files while downloading and then decrypt to play it. I have already checked everywhere in the internet but did not find any solution. Could anyone please help me how to encrypt audio files while downloading and then decrypt during playing
Here is my code to download the files
private void download() {
if (Constant.arrayList_play.size() > 0) {
File root = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Myapp/cache");
if (!root.exists()) {
root.mkdirs();
}
File file = new File(root, Constant.arrayList_play.get(viewpager.getCurrentItem()).getMp3Name() + ".mp3");
if (!file.exists()) {
String url = Constant.arrayList_play.get(viewpager.getCurrentItem()).getMp3Url();
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription(getResources().getString(R.string.downloading) + " - " + Constant.arrayList_play.get(viewpager.getCurrentItem()).getMp3Name());
request.setTitle(Constant.arrayList_play.get(viewpager.getCurrentItem()).getMp3Name());
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationUri(Uri.parse("file://" + Environment.getExternalStorageDirectory().getAbsolutePath() + "/Myapp/cache/" + Constant.arrayList_play.get(viewpager.getCurrentItem()).getMp3Name() + ".mp3"));
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
new AsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... strings) {
String json = JsonUtils.getJSONString(Constant.URL_DOWNLOAD_COUNT + Constant.arrayList_play.get(viewpager.getCurrentItem()).getId());
Log.e("aaa - ", json);
return null;
}
}.execute();
Toast.makeText(MainActivity.this, getResources().getString(R.string.downloading), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, getResources().getString(R.string.already_download), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(MainActivity.this, getResources().getString(R.string.no_song_selected), Toast.LENGTH_SHORT).show();
}
}
So could you please help me with a code.
I have found a solution to my question and have been using it in my app since many days without any problem so I think it is good to answer my own question also as many users had asked for solution in comments. So just follow the below codes-
//Downloading and encrypting the audio
AesCipherDataSink encryptingDataSink = new AesCipherDataSink(
Util.getUtf8Bytes("4J95qN8RxBP8hTpk"),
new DataSink() {
private FileOutputStream fileOutputStream;
#Override
public void open(DataSpec dataSpec) throws IOException {
fileOutputStream = new FileOutputStream(file);
}
#Override
public void write(byte[] buffer, int offset, int length) throws IOException {
fileOutputStream.write(buffer, offset, length);
}
#Override
public void close() throws IOException {
fileOutputStream.close();
}
});
// Push the data through the sink, and close everything.
encryptingDataSink.open(new DataSpec(Uri.fromFile(file)));
URL downloadURL = new URL(strings[0]);
HttpURLConnection connection = (HttpURLConnection) downloadURL.openConnection();
connection.setChunkedStreamingMode(0);
connection.setDoInput(true);
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server error";
}
InputStream inputStream = connection.getInputStream();
byte[] buffer = new byte[1024];
int newLength;
while ((newLength = inputStream.read(buffer)) > 0) {
encryptingDataSink.write(buffer, 0, newLength);
}
encryptingDataSink.close();
inputStream.close();
//decrypting and playing the audio
DataSource.Factory factory =
new CustomDataSourceFactory(
context,
new OkHttpDataSourceFactory(new OkHttpClient(), Util.getUserAgent(context,
context.getResources().getString(R.string.app_name)))
);
MediaSource videoSource =
new ProgressiveMediaSource.Factory(factory)
.createMediaSource(Uri.parse(tempFile.getAbsolutePath()));
exoPlayer.addMediaSource(videoSource);
//CustomDataSourceFactoryClass
public class CustomDataSourceFactory implements DataSource.Factory {
private final Context context;
private final DataSource.Factory baseDataSourceFactory;
public CustomDataSourceFactory(Context context, DataSource.Factory baseDataSourceFactory) {
this.context = context.getApplicationContext();
this.baseDataSourceFactory = baseDataSourceFactory;
}
#Override
public DataSource createDataSource() {
return new CryptedDefaultDataSource(context, baseDataSourceFactory.createDataSource());
}
}
//CryptedDafaultDataSource
public class CryptedDefaultDataSource implements DataSource {
private final List<TransferListener> transferListeners;
private final DataSource baseDataSource;
private #Nullable
DataSource fileDataSource,aesCipherDataSource,dataSource;
private Context context;
CryptedDefaultDataSource(Context context, DataSource baseDataSource) {
this.context=context;
this.baseDataSource = Assertions.checkNotNull(baseDataSource);
transferListeners = new ArrayList<>();
}
#Override
public void addTransferListener(TransferListener transferListener) {
baseDataSource.addTransferListener(transferListener);
transferListeners.add(transferListener);
maybeAddListenerToDataSource(fileDataSource, transferListener);
maybeAddListenerToDataSource(aesCipherDataSource, transferListener);
}
#Override
public long open(DataSpec dataSpec) throws IOException {
Assertions.checkState(dataSource == null);
if (Util.isLocalFileUri(dataSpec.uri)) {
dataSource = getCryptedDataSource(getFileDataSource());
} else {
dataSource = getCryptedDataSource(baseDataSource);
}
return dataSource.open(dataSpec);
}
#Override
public int read(byte[] buffer, int offset, int readLength) throws IOException {
return Assertions.checkNotNull(dataSource).read(buffer, offset, readLength);
}
#Nullable
#Override
public Uri getUri() {
return dataSource == null ? null : dataSource.getUri();
}
#Override
public Map<String, List<String>> getResponseHeaders() {
return dataSource == null
? DataSource.super.getResponseHeaders()
: dataSource.getResponseHeaders();
}
#Override
public void close() throws IOException {
if (dataSource != null) {
try {
dataSource.close();
} finally {
dataSource = null;
}
}
}
private DataSource getFileDataSource() {
if (fileDataSource == null) {
fileDataSource = new FileDataSource();
addListenersToDataSource(fileDataSource);
}
return fileDataSource;
}
private DataSource getCryptedDataSource(DataSource upstreamDataSource) {
if (aesCipherDataSource == null) {
aesCipherDataSource = new AesCipherDataSource("4J95qN8RxBP8hTpk".getBytes(),upstreamDataSource);
addListenersToDataSource(aesCipherDataSource);
}
return aesCipherDataSource;
}
private void addListenersToDataSource(DataSource dataSource) {
for (int i = 0; i < transferListeners.size(); i++) {
dataSource.addTransferListener(transferListeners.get(i));
}
}
private void maybeAddListenerToDataSource(
#Nullable DataSource dataSource, TransferListener listener) {
if (dataSource != null) {
dataSource.addTransferListener(listener);
}
}
}
Yes I have searched for many solutions for days. My still persisting problem is my app crashes at start when I am trying to access an external database (created through "DB Browser for Sqlite" named "test.db").
The sole purpose is of course to prepopulate my app with some data.
I have kept the database file on assets folder in android studio. Finally I have implemented a helper class to access the database.
Here is the helper class:
public class DataBaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "test.db";
private static final int DATABASE_VERSION = 1;
private static String DATABASE_PATH = "";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.myContext = context;
if (Build.VERSION.SDK_INT >= 17) {
DATABASE_PATH = context.getApplicationInfo().dataDir + "/databases/";
} else {
DATABASE_PATH = "/data/data/" + context.getPackageName() + "/databases/";
}
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void createDatabase() throws IOException {
createDB();
}
private void createDB() {
boolean dbExists = checkDatabase();
if (dbExists) {
//do nothing
} else {
this.getReadableDatabase();
try {
copyDatabase();
} catch (IOException ie) {
throw new Error("Error copying database");
}
}
}
private boolean checkDatabase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DATABASE_PATH + DATABASE_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
checkDB.setLocale(Locale.getDefault());
} catch (SQLiteException e) {
throw new Error("SQLite exception");
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null;
}
private void copyDatabase() throws IOException {
InputStream myInput = null;
OutputStream myOutput = null;
String outFileName = DATABASE_PATH + DATABASE_NAME;
try{
myInput = myContext.getAssets().open(DATABASE_NAME);
myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}catch (IOException ie){
throw new Error("Copydatabase run error ");
}
}
#Override
public synchronized void close() {
if(myDataBase != null){
myDataBase.close();
}
super.close();
}
}
In the Main activity I have just called the createDatabase() method of the helper class. The code being below:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DataBaseHelper myDbHelper = new DataBaseHelper(this);
try{
myDbHelper.createDatabase();
}catch (IOException ioe){
throw new Error("Unable to CREATE DATABASE");
}
}
}
The logcat indicates the problem as:
AndroidRuntime: FATAL EXCEPTION: main java.lang.Error: SQLite
exception at DataBaseHelper.checkDatabase(DataBaseHelper.java:79) at
DataBaseHelper.createDB(DataBaseHelper.java:59) at
DataBaseHelper.createDatabase(DataBaseHelper.java:55) at
MainActivity.onCreate(MainActivity.java:18)
which points to my checkDatabase() method. But now I am not able to sort out the problem.
I am using Android Studio 3.0.1, DB Browser for Sqlite 3.10.1, Min API level used 17.
Please Help!
Try This
public static final String DATABASE_NAME = "abc.db";
public final static String DATABASE_PATH = "/data/data/"+ PACKAGE_NAME +
"/databases/";
public static final int DATABASE_VERSION = 1;
public void createDatabase() {
boolean dbExist1 = checkDataBase();
if (!dbExist1) {
this.getReadableDatabase();
try {
this.close();
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
// Check database already exist or not
private boolean checkDataBase() {
boolean checkDB = false;
try {
String myPath = DATABASE_PATH + DATABASE_NAME;
File dbfile = new File(myPath);
checkDB = dbfile.exists();
} catch (SQLiteException e) {
}
return checkDB;
}
// Copies your database from your local assets-folder to the just created
// empty database in the system folder
public void copyDataBase() throws IOException {
String outFileName = DATABASE_PATH + DATABASE_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
InputStream myInput = mContext.getAssets().open(DATABASE_NAME);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myInput.close();
myOutput.flush();
myOutput.close();
}
I am trying to create a new version of database in my android app. But although I change the version of database from previous version (2) to a new version (3) it doesn't invoke onUpgrade() and onCreate() . It just invoke three times the constructor. I do not understand why constructor invoked three times and also why onUpgrade() and onCreate() did not invoke?
I also tried with new database version code but result is same.
Here is my code.
public class DatabaseHelper extends SQLiteOpenHelper {
private static String PACKAGE_NAME;
private static String DB_PATH;
private static String DB_NAME = "mydata.db";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, 3);
this.myContext = context;
Log.e("UPDATED3", "CONSTRUCTOR");
PACKAGE_NAME = myContext.getPackageName();
DB_PATH = "/data/data/" + PACKAGE_NAME + "/databases/";
}
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");
}
}
}
private boolean checkDataBase() {
SQLiteDatabase checkDB = null;
try {
String myPath = DB_PATH + DB_NAME;
checkDB = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException e) {
// database does't exist yet.
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
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_READWRITE);
}
#Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.e("UPDATED3", "ONCREATE");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.e("UPDATED3", "UPDATED THE DATABASE");
}
}
I use my database this(showing below) way in any activity.
DatabaseHelper databaseHelper = new DatabaseHelper(getApplicationContext());
try {
databaseHelper.createDataBase();
databaseHelper.openDataBase();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Error: " + e.getMessage(),
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
My Tbl_Driver have 3 columns _id,Driver_Code,Driver_Name
How do i able to get the Driver_Name when the Spinner OnItemSelected, because The Spinner will only show Driver_Code
public void DriverDatabaseConn(){
DataBaseHelper myDbHelper = new DataBaseHelper(this.getApplicationContext());
myDbHelper = new DataBaseHelper(this);
try {
myDbHelper.createDataBase();
} catch (IOException ioe) {
throw new Error("Unable to create database");
}
try {
myDbHelper.openDataBase();
}catch(SQLException sqle){
throw sqle;
}
SQLiteDatabase db = myDbHelper.getReadableDatabase();
//SQLiteDatabase db = SQLiteDatabase.openDatabase("/data/data/com.example.abc2/databases/DB_BusData", null, 0);
Cursor c = db.rawQuery("SELECT * FROM Tbl_Driver", null);
//=====Add Additional=====
MatrixCursor extras = new MatrixCursor(new String[] { "_id", "Driver_Code" , "Driver_Name"});
extras.addRow(new String[] { "-1", "< Select Driver Code >","< Select Driver >" });
//extras.addRow(new String[] { "-2", "Empty Template","BB" });
Cursor[] cursors = { extras, c };
c = new MergeCursor(cursors);
//===========================
startManagingCursor(c);
//create an array to specify which fields we want to display
String[] from = new String[]{"Driver_Code"};
//create an array of the display item we want to bind our data to
int[] to = new int[]{android.R.id.text1};
//create simple cursor adapter
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, c, from, to );
adapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item );
//get reference to our spinner
Spinner s = (Spinner) findViewById( R.id.DriverSpin);
s.setAdapter(adapter);
s.setOnItemSelectedListener(
new OnItemSelectedListener() {
public void onItemSelected(
AdapterView<?> parent, View view, int position, long id) {
Spinner s = (Spinner) findViewById( R.id.DriverSpin);
TextView textView = (TextView)s.getSelectedView();
String result = textView.getText().toString();
Log.d(null,"Spinner1: position=" + result + " id=" + id);
global.Driver_ID = id;
global.Driver_Code = result;
// at here how i can get the Driver_Name column's value at here?
}
public void onNothingSelected(AdapterView<?> parent) {
Log.d(null,"Spinner1: unselected");
}
});
//db.close();
//myDbHelper.close(); //cannot close, otherwise after logout the spinner will blank
}
DataBaseHelper.java
package com.example.abc2;
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.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
public class DataBaseHelper extends SQLiteOpenHelper{
//The Android's default system path of your application database.
private static String DB_PATH = "/data/data/com.example.abc2/databases/";
private static String DB_NAME = "DB_BusData";
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 DataBaseHelper(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) {
}
#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.
}
I have rewrite your DatabaseHelpe and a Test Activity:
public class DataBaseHelper {
private static final String DB_NAME = "DB_BusData";
public static final String TABLE_NAME = "Tbl_Driver";
private Context context;
private String path;
private SQLiteDatabase database;
private boolean isInitializing = false;
public DataBaseHelper(Context context) {
this.context = context;
this.path = context.getDatabasePath(DB_NAME).getAbsolutePath();
if (TextUtils.isEmpty(this.path)) {
throw new IllegalArgumentException("database can't be null");
}
}
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
checkAndCopyDatabase();
return getDatabaseLocked(false);
}
}
/**
* Attention:just support readable database until now
*
* #return
*/
public SQLiteDatabase getWriteableDatabase() {
synchronized (this) {
checkAndCopyDatabase();
return getDatabaseLocked(true);
}
}
private void checkAndCopyDatabase() {
File file = new File(this.path);
if (file.exists() && file.length() > 0) {
Log.d("TAG", "db already exist");
} else {
try {
InputStream is = context.getAssets().open(DB_NAME);
copyStreamToFile(is, new File(this.path));
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static final void copyStreamToFile(InputStream inputStream, File file) {
ensureDir(file);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
byte[] buffer = new byte[2048];
int read = 0;
while ((read = inputStream.read(buffer)) > 0) {
fos.write(buffer, 0, read);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
quietClose(inputStream);
quietClose(fos);
}
}
private static final void ensureDir(File file) {
if (file != null && (file = file.getParentFile()) != null && !file.exists()) {
file.mkdirs();
}
}
private static final void quietClose(final Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (final IOException e) {
}
}
}
private SQLiteDatabase getDatabaseLocked(boolean writeable) {
if (this.database != null) {
if (!this.database.isOpen()) {
database = null;
} else if (!writeable || !database.isReadOnly()) {
return database;
}
}
if (isInitializing) {
throw new IllegalArgumentException("getDatabase called recursively");
}
SQLiteDatabase db = this.database;
try {
isInitializing = true;
if (db != null && writeable && db.isReadOnly()) {
if (db.isOpen()) {
db.close();
}
db = null;
}
try {
db = SQLiteDatabase.openDatabase(this.path, null,
writeable ? SQLiteDatabase.OPEN_READWRITE : SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
e.printStackTrace();
}
this.database = db;
return db;
} finally {
isInitializing = false;
if (db != null && db != database) {
db.close();
}
}
}
public static class Driver implements BaseColumns {
long id;
String code;
String name;
static final String CODE_CLOMN_NAME = "Driver_Code";
static final String NAME_CLOMN_Name = "Driver_Name";
#Override
public String toString() {
return name;
}
}
public List<Driver> queryAllDriver() {
List<Driver> drivers = null;
SQLiteDatabase db = getReadableDatabase();
if (db != null) {
Cursor cursor = null;
try {
cursor = db.query(TABLE_NAME, null, null, null, null, null, null);
if(cursor != null && cursor.moveToFirst()) {
do {
final long id = cursor.getLong(cursor.getColumnIndex(Driver._ID));
final String code = cursor.getString(cursor.getColumnIndex(Driver.CODE_CLOMN_NAME));
final String name = cursor.getString(cursor.getColumnIndex(Driver.NAME_CLOMN_Name));
Driver driver = new Driver();
driver.id = id;
driver.code = code;
driver.name = name;
if(drivers == null)
drivers = new ArrayList<DataBaseHelper.Driver>();
drivers.add(driver);
} while(cursor.moveToNext());
}
} catch (SQLiteException e) {
e.printStackTrace();
} finally {
if(cursor != null)
cursor.close();
}
db.close();
}
return drivers;
}
}
The DB open and operation code is above, then I write a Test Activity:
public class MainActivity extends Activity implements OnItemSelectedListener {
private List<Driver> drivers;
private Spinner spinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
spinner = (Spinner) findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(this);
new DBTask().execute();
}
class DBTask extends AsyncTask<Void, Void, List<Driver>> {
#Override
protected List<Driver> doInBackground(Void... params) {
DataBaseHelper dbHelper = new DataBaseHelper(MainActivity.this);
return dbHelper.queryAllDriver();
}
#Override
protected void onPostExecute(List<Driver> result) {
bindSpinner(result);
}
}
private void bindSpinner(List<Driver> drivers) {
this.drivers = drivers != null ? drivers : new ArrayList<DataBaseHelper.Driver>(0);
ArrayAdapter<Driver> adapter = new ArrayAdapter<DataBaseHelper.Driver>(this,
android.R.layout.simple_spinner_item, this.drivers);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (this.spinner != null && position >= 0 && position < this.drivers.size()) {
Driver driver = drivers.get(position);
Toast.makeText(this, "selected: driver=" + driver.name + ", code=" + driver.code,
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
Toast.makeText(this, "nothing selected", Toast.LENGTH_SHORT).show();
}
}
The Test Activity is works fine for me, I use the database that I simulated. I think you can't store spinner item in database, how many item in spinner? 10? 100 ? 1000?
You can move query data outside DataBaseHelper.java like this:
private List<Driver> queryAllDriver() {
List<Driver> drivers = null;
DataBaseHelper helper = new DataBaseHelper(this);
SQLiteDatabase db = helper.getReadableDatabase();
if (db != null) {
Cursor cursor = null;
try {
cursor = db.query(DataBaseHelper.TABLE_NAME, null, null, null, null, null, null);
if(cursor != null && cursor.moveToFirst()) {
do {
final long id = cursor.getLong(cursor.getColumnIndex(Driver._ID));
final String code = cursor.getString(cursor.getColumnIndex(Driver.CODE_CLOMN_NAME));
final String name = cursor.getString(cursor.getColumnIndex(Driver.NAME_CLOMN_Name));
Driver driver = new Driver();
driver.id = id;
driver.code = code;
driver.name = name;
if(drivers == null)
drivers = new ArrayList<DataBaseHelper.Driver>();
drivers.add(driver);
} while(cursor.moveToNext());
}
} catch (SQLiteException e) {
e.printStackTrace();
} finally {
if(cursor != null)
cursor.close();
}
db.close();
}
return drivers;
}
This works on the emulator but not on my phone. At least it seems so because it does not find the table when I query it on the phone.
This my class that inherits from SQLiteOpenHelper
public class DBHelper extends SQLiteOpenHelper {
private final static String DB_NAME = "klb_db.sqlite";
private final static int DB_VERSION = 1;
private String dbPath;
private Context context;
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.context = context;
dbPath = "/" + Environment.getDataDirectory() + "/data/" + context.getPackageName() + "/databases/";
}
public void initializeDatabase() {
try {
File file = new File(dbPath + DB_NAME);
if (!file.exists()) {
InputStream inputStream = context.getAssets().open(
"klb_db.sqlite");
OutputStream outputStream = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
inputStream.close();
outputStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In dbadapter, open method:
public DBAdapter open() {
dbHelper.initializeDatabase();
db = dbHelper.getWritableDatabase();
return this;
}
In activity that uses it:
#Override
protected void onStart() {
super.onStart();
QuizDAO quizDAO = new QuizDAO(this);
quizDAO.open();
Cursor cursor = quizDAO.getQuestion(10);
Toast.makeText(this, cursor.getString(1), Toast.LENGTH_LONG).show();
}
try to increase you bytes
byte[] buffer = new byte[1024];
to
byte[] buffer = new byte[2048];
EDITED
#Override
protected void onStart() {
super.onStart();
QuizDAO quizDAO = new QuizDAO(this);
quizDAO.open();
Cursor cursor = quizDAO.getQuestion(10);
cursor.moveToFirst()
Toast.makeText(this, cursor.getString(1), Toast.LENGTH_LONG).show();
}