Open database Android - android

I need to open a database from my phone's memory (/storage/emulated/0) and I've got "SQLiteCantOpenDatabaseException" the database to open (created by DB browser from linux) have the tables "android_metadata" and them respective fields (locale...es_US).
I need open and read data from the external db (the app need to download the db from website and read data and put in textview into the app activities )
The app has permission to read and write external memory
code below (only the code of button to get the database reference)
case R.id.button4:
{
int ID,IDn,IDa;
String cabeceras[] ={"nombre","apellido",_ID},lectura=new String(),err="";
ArrayList<String> arregloDatos = new ArrayList<>();
try {
SQLiteDatabase db = SQLiteDatabase.openDatabase(Environment.getExternalStorageDirectory().getPath() +"/"+"pruebaDB.db", null, SQLiteDatabase.OPEN_READWRITE);
Cursor cursor = db.query("persona", cabeceras, null, null, null, null, null);
ID = cursor.getColumnIndex(_ID);
IDn = cursor.getColumnIndex("nombre");
IDa = cursor.getColumnIndex("apellido");
while (cursor.moveToNext()) {
lectura = cursor.getString(ID) + " " + cursor.getString(IDn) + " " + cursor.getString(IDa);
arregloDatos.add(lectura);
}
Intent i = new Intent(this, Main2Activity.class);
i.putStringArrayListExtra("cadena", arregloDatos);
startActivity(i);
}catch (Exception g)
{
Toast msg =Toast.makeText(this,g.getClass().toString(),Toast.LENGTH_SHORT);
msg.show();
}
break;
}
Edit: i find the problem, the problem is the cursor, becose i comment it and the app not show any exception.
now...my problem is "how to read data from SQliteDatabase object"

I don't think you are able to write SQLDatabases to external. If it is all string or int data, you could write the Database to internal, then write a function that will iterate through the table and concatenate the data and write it to external as a .txt.
Yep, just read the documentation on the .openDatabase method. I think the first param is looking for the path portion of the content URI, not an ext memory file path.
https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#openDatabase(java.lang.String,%20android.database.sqlite.SQLiteDatabase.CursorFactory,%20int,%20android.database.DatabaseErrorHandler)

Related

How to Update SQLite database when user add Contacts in Android Phone?

I am creating SQLite Database for my Mobile App. The App Database will store copy of contacts that are stored in Android Phones. Below code is used to copy contacts from Database. My problem is that every time App is opened , it copies entire data into SQLite Database that has resulted lot of duplicate entry. If I try to check existence of entries before copying the records into SQLite database then every time when App is launched, it will be checking of duplicity resulting overloading on application.
In order to solve the problem I thought if any response comes after successful addition of contact by user, then we can use this response to add contacts in SQLite database and then we can take out Database copying on launch of App. As I am new into the world of Android, requesting you to advice best way to tackle this problem.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button prd = (Button) findViewById(R.id.duct);
prd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
load_contacts();
display_cotacts();
Log.i("Activity Main", "Completed Displaying List");
}
});
}
private void load_contacts(){
openDB();
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
//String[] from = {ContactsContract.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone_ID};
if(cur.getCount()>0) {
while(cur.moveToNext()){
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString((cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
if(Integer.parseInt(cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) >0){
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id},null);
while(pCur.moveToNext()){
Integer mobile = pCur.getInt(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String email = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
Integer imageID = pCur.getInt(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO_FILE_ID));
String status = "available";
String time = "now";
long newId = myDb.insertRow(name,mobile,email,imageID,status,time);
Toast.makeText(MainActivity.this, "Name: " + name + "Phone no:" + mobile + "Email:" + email + "image:" + imageID + "image_thumbnail:" + status, Toast.LENGTH_LONG).show();
}
//closeDB();
pCur.close();
}
}
}
}
I'd suggest to use INSERT OR IGNORE INTO exampletable (UserId, UserName, ContactName) VALUES('1','UserName','ContactName'); // the variables are just examples;
or INSERT OR REPLACE INTO exampletable (UserId, UserName, ContactName) VALUES('1','UserName','ContactName');
Replace will update the existing entry with the new variable values and ignore is pretty self-explanatory.
This would fix your problem of doubled entrys and the checking of this would be done by your sqlite-database.
For checking the last modification date you should have a look at this stackoverflow answer.
You could simply retrieve this date and check wether it differs with the last time the contact was modified. But this will also be done for every contact, so not a perfect solution at all.

How do I protect ContentResolver from being accessed by just any app?

Android newbie here.
I'm starting to learn about ContentProviders and I've set up my first ContentProvider which internally accesses a private SQLiteOpenHelper class to read and write data out of my database.
I take it one of the main benefits of ContentProviders is that you put all your data accessing code in the one place and the only time you're supposed to access the database is via ContentResolvers which use the ContentProvider's URI? [correct me if i'm wrong, i just figure that is the case as all the examples put SQLiteOpenHelper as a private class]
So I've recently written an update method in my ContentProvider which clears a column in my database. It looks roughly like this
#Override
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) {
SQLiteDatabase database = dbHelper.getWritableDatabase();
int count;
switch (uriMatcher.match(uri)) {
case FACT_ID:
String segment = uri.getPathSegments().get(1);
count = database.update(TABLE_FACT, values,
KEY_ID
+ "="
+ segment
+ (!TextUtils.isEmpty(where) ? " AND (" + where
+ ')' : ""), whereArgs);
break;
case CLEAR_DATESEEN:
ContentValues cv = new ContentValues();
cv.putNull(KEY_DATESEEN);
count = database.update(TABLE_FACT, cv, null, null);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
The CLEAR_DATESEEN bit of the code is the one that clears the column.
This works but I was just wondering, doesn't this mean that any app on the device that calls that URI should be able to clear that column as well? What if I did not want other apps messing with my data?
Is there any way to prevent certain apps or only allow certain apps to be able to call my ContentProvider?
Unless you have set-up a special permission and provide that information to other apps (developers), your content provider is accessible only for your app. Please see Content Provider Permissions.

Android Select from attached database

I have an Android application where I have attached a database to my current database connection, but when I try to select from a table from the attached database I get an error reporting that there is no such table.
SQLiteDatabase dbc;
try {
dbc = openOrCreateDatabase(DATABASE_RECOVERY,Context.MODE_PRIVATE,null);
dbc.execSQL(TABLE_COMPLETE);
dbc.execSQL("ATTACH DATABASE '" + DBRECOVERY_FULL_PATH + "' as MasterDb;");
dbc.execSQL("SELECT * FROM MasterDb.properties;");
db.close();
dbc.close();
} catch(SQLException e) {
Toast.makeText(getApplicationContext(), "SQLException: " + e.toString(),
Toast.LENGTH_SHORT).show();
}
I have also tried:
dbc.execSQL("SELECT 'MasterDb', * FROM MasterDb.properties;");
But each time, it is reporting that there is no such table.
Using the query method from SQLiteDatabase can simplify your work, but according to your query try using dbc.execSQL("SELECT * FROM MasterDb");
Don't forget that to use an "attached" database you need to open it with this flag:
SQLiteDatabase.NO_LOCALIZED_COLLATORS
See SQLiteDatabase OpenDatabase.
To open the database you will need to run something like this:
String path = getDatabasePath("YourDbName").getAbsolutePath();
SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.CREATE_IF_NECESSARY + SQLiteDatabase.NO_LOCALIZED_COLLATORS);
I had this same issue. I forgot to copy the new DB to the file path before attaching it.

Storing audio file in a database

I'm developing an application. I need to use at least 400 audio files which can be played for some respective texts. My question is which is the best and optimized way to do this?
One solution is putting all the audio files in the resources folder and referring from there. This will never be a feasible solution as the application size will increase. Is there any way to convert the audio file into some format and dump into the SQLite database and retrieve them flexibly? If so, what options do I have?
Storing the files as BLOB in a SQLite db will not save you any space vs storing them as files. If these files are not meant to be associated to any dynamic data, I would just put them in assets folders, that way they'll be compiled into the APK and might be a tad faster to retrieve that if they were in a db.
try the following code... it stored for me.....
#Override
public void onClick(View arg0) {
SQLiteDatabase myDb;
String MySQL;
byte[] byteImage1 = null;
byte[] byteImage2 = null;
MySQL="create table emp1(_id INTEGER primary key autoincrement, sample TEXT not null, picture BLOB);";
myDb = openOrCreateDatabase("Blob List", Context.MODE_PRIVATE, null);
myDb.execSQL(MySQL);
String s=myDb.getPath();
textView.append("\r\n" + s+"\r\n");
myDb.execSQL("delete from emp1");
ContentValues newValues = new ContentValues();
newValues.put("sample", "HI Hello");
try
{
FileInputStream instream = new FileInputStream("/sdcard/AudioRecorder/AudioRecorder.wav");
BufferedInputStream bif = new BufferedInputStream(instream);
byteImage1 = new byte[bif.available()];
bif.read(byteImage1);
textView.append("\r\n" + byteImage1.length+"\r\n");
newValues.put("picture", byteImage1);
long ret = myDb.insert("emp1", null, newValues);
if(ret<0) textView.append("\r\n!!! Error add blob filed!!!\r\n");
} catch (IOException e)
{
textView.append("\r\n!!! Error: " + e+"!!!\r\n");
}
Cursor cur = myDb.query("emp1",null, null, null, null, null, null);
cur.moveToFirst();
while (cur.isAfterLast() == false)
{
textView.append("\r\n" + cur.getString(1)+"\r\n");
cur.moveToNext();
}
///////Read data from blob field////////////////////
cur.moveToFirst();
byteImage2=cur.getBlob(cur.getColumnIndex("picture"));
bmImage.setImageBitmap(BitmapFactory.decodeByteArray(byteImage2, 0, byteImage2.length));
textView.append("\r\n" + byteImage2.length+"\r\n");
cur.close();
myDb.close();
}
});
Anybody correct me if I'm wrong, but SQLite has an restriction of total row size < 1024kb. If all of your audio files are small enough, you could store them as BLOBs.
The main reason for storing sound files on database might be product line approach. You can develop many many similar applications by just modifying your database and not touching your code.
I do not comment on application size because there are comments about it and I do not look at it.
Yes. You can store your small sized sound files in sqlite database as blob fields. It works well. First store your data in database then retrieve it and put it in a temp file. That way you can store your sound files in database.
Check this:
soundDataFile = File.createTempFile( "sound", "sound" );
FileOutputStream fos = new FileOutputStream( soundDataFile );
fos.write( soundData );
fos.close();
mediaPlayer.reset();
mediaPlayer.setDataSource( soundDataFile.getAbsolutePath() );
mediaPlayer.prepare();
mediaPlayer.start();
What is the motivation behind storing the files in the sql lite db? I dont see much benefit to that over storing the file path in the db, and the actual file on the file system...

Android - How to populate Content Provider only once on App install?

I have a database in my application that is used as a ContentProvider.
It holds settings values for the application, and when I install the application I
want it to add a hardcoded set of values just once.
This is how I am trying to do it at the minute.
if(settings.size()<= 0){
Settings s = new Settings("voipusernameTa", "xxxxxxxxx", "xxxxx",
"displayNameTa", "sip.networks.com", "sip.networks.com", "siprealmTa", 120);
addNewSettings(s);
}
And this is the addNewSettings method:
private void addNewSettings(Settings _settings) {
ContentResolver cr = getContentResolver();
String w = CiceroSettings._ID + " = " + _settings.get_Id();
Log.d("ADDNEW SETTINGS", "new setting id =" + _settings.get_Id());
Cursor c = cr.query(CiceroSettings.CONTENT_URI, null, w, null, null);
Log.d("CURSOR", "cursor created");
int dbCount = c.getCount();
c.close();
if (dbCount == 0){
ContentValues values = new ContentValues();
values.put(Settings._ID, _settings.get_Id());
values.put(Settings.VOIPUSERNAME, _settings.getVoipUserName());
values.put(Settings.VOIPAUTHID, _settings.getVoipAuthId());
values.put(Settings.PASSWORD, _settings.getPassword());
values.put(Settings.VOIPDISPLAYNAME, _settings.getVoipDisplayName());
values.put(Settings.SIPPROXYSERVER, _settings.getSipProxyServer());
values.put(Settings.SIPREGISTRAR, _settings.getSipRegistrar());
values.put(Settings.SIPREALM, _settings.getSipRealm());
values.put(Settings.EXPIRESTIME, Integer.toString(_settings.getExpiresTime()));
Log.d("CURSOR", "Values assigned");
cr.insert(CiceroSettings.CONTENT_URI, values);
Log.d("CURSOR", "Values inserted");
}
}
}
This works however each time the app starts it adds a new settings object and I only want it to app ONE object at the install of the application and thats it no more.
Has anyone a better solution for this? Or a reason why my code is flawed?
If you want to add default values to your SQL table, I think the best way would be to set them right after creating your table.
So if you are using SQLiteOpenHelper, in the onCreate method, you can call db.insert() right after creating your table so that those values will be created just once

Categories

Resources