We are tying to use Secondary EXTERNAL storage on the emulator and this works great. The user can select external or internal storage. Android build 26.0.2
YES manifest has permissions. When this line of code is included in the launcher Activity the storage is defaulted to INTERNAL helper = new DBHelper(this);
helper is declared static. The big benefit of using that line of code is that when the app is stopped or when we close the app with Clear All in the emulator the bound data in the ArrayList that is backed by a RecyclerAdapter persists. So not using the helper declaration except when needed in the Activity creates the need to reload data from the database and populate the ArrayList. This is where we have become lost. We have tried to call the method in the DBhelper that loads the ArrayList. To no avail code below is in the ListActivity. The app always returns to the MainActivity after being closed. So the question is where and how do I place the code to repopulate the ArrayList from the database ?
}// End of onCreate Bundle
#Override
protected void onResume() {
super.onResume();
helper = new DBHelper(this);
dbList = new ArrayList<>();
dbList = helper.getDataFromDB();
}
I tried to test this and discovered that you do not need the line of code
helper = new DBHelper(this); The issue is somewhere in your MainActivity your code is making a trip over to the DBHelper BEFORE the variable THE_PATH is set where ever you are defining that variable. In my testing I found you need to establish the contents of the variable THE_PATH that is being passed to DBHelper before that trip is made. While testing I changed the config.ini to excluded the SD CARD from the emulator and Android would just use internal storage.
So as of now my testing still did not permit the user to select storage type.
If the DB is beyond the storage capacity of internal memory than just set the default to EXTERNAL storage. As you know the data is not real secure on the SD CARD
Related
I am trying to use SQLiteAssetHelper and it requires me to create database on PC and copy it to assets/databases/databasename.db. I do that, but when I check on the device, nor the database, nor the databases folder is there under my app's data folder.
I did this based on a video, and the guy there doesn't do anything else to make the copy work.
So, are the files supposed to be automatically copied over to device?
If not, how can I copy the files?
So, are the files supposed to be automatically copied over to device? If not, how can I copy the files?
Yes it will BUT only when an attempt is made to access the database. Just instantiating the class that extends SQLiteAssetHelper will not copy the database and thus if that is all you do then the database will not be visible.
The steps when using SQliteAssetHelper to take should be :-
Create your project.
Amend the build.gradle to include implementation 'com.readystatesoftware.sqliteasset:sqliteassethelper:+' in the dependencies section.
Create the assets folder and then the databases folder in the assets folder and
Copy the database file into the databases folder.
Create the Database Helper class that extends SQliteAssetHelper.
Instantiate the Database Helper
Access the database (this is when the database is copied).
If when doing step 5 you use, as an example (based upon the information in the question) :-
public class DatabaseHelper extends SQLiteAssetHelper {
public static final String DATABASENAME = "databasename.db"; //<<<<<<<<< MUST match file name in assets/databases
public static final int DATABASEVERSION = 1;
public DatabaseHelper(Context context) {
super(context, DATABASENAME, null, DATABASEVERSION);
this.getWritableDatabase(); //<<<<< will force database access and thus copy database from assets
}
}
Then when doing 6 (instantiating the database helper), then 7 is done because this.getWritableDatabase(); accesses (implicitly opens) the database.
e.g.
public class MainActivity extends AppCompatActivity {
DatabaseHelper mDBHelper; //<<<<< declares the database helper
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDBHelper = new DatabaseHelper(this); // instantiates the database helper
}
}
The procedure you're explaining requires root access to the app storage on the device which is impossible on a normal non-rooted device due to security considerations. For this, you need a rooted device OR you could use emulator in Android Studio, that's much easier and user friendly approach:
Open emulator from Android Studio -> Settings -> Memory -> Internal Storage -> Others
A pop-up window will open. Click explore. You will get access to your app's internal storage so you can manage the database folder as well.
P.S.: Also, you might just package your app with the database table you have, just as with any other file, simply place it under your src/main/assets folder and access from code in runtime. Code samples are available in this thread : Android - Copy assets to internal storage (suggested by #Ezaldeen sahb)
When an automatic update occurs, the old date save in the preferences for my app gets delete.
How can i prevent this deletion?
I want that when my app auto updates , it does not delete my old data saved.
I am not sure whether this will be a good solution but just a suggestion you can try.
step 1: whenever you changeg (add/edit/remove) your data store it in permanent storage, you may try any of the following
a. save the data in file in sd card
b. store the data to your remote server or
c. store in internal memory of the phone.
(I am not sure whether it will persists after update at case c, for reference can check here
Step 2: creae a BroadcastReceiver that listens to the ACTION_PACKAGE_REPLACED Intent. So you know when your application package is updated. NOw read the data again from the storage where you saved the data ( either 1a/1b/1c)
Caution: It is not a good thing to save user data without his concern.
Android save your SharedPreference under /data/data/your package name/shared_prefs
Generally, update application won't delete your sharedPreference.
private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
...
// First delete the existing package while retaining the data directory
if (!deletePackageLI(pkgName, null, true, PackageManager.DELETE_KEEP_DATA,
res.removedInfo, true)) {
// If the existing package wasn't successfully deleted
res.returnCode = PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
deletedPkg = false;
} else {
....
}
....
}
I think you need to check the following:
Is your device a rooted device? Apps on a rooted device can delete anything they want.
Did you use a different package name in that updated apk?
I've done my homework; I know all the ways to query an SQLite db from an Activity.
The problem is that all the examples ASSUME that i want to "load" data from the db onto the FIRST Activity screen.
But when my app's FIRST Activity is loaded I DON'T WANT TO GET ANY DATA FROM THE DB; i just want to:
(1) Check if the db file has already been created (if the setup routines have already run).
(2) If the db exists, load the SECOND Activity (with ContentProvider/Loaders, etc.) so the user can start adding data.
OR
(2) If the db DOESN'T exist, WHILE STILL IN THE FIRST ACTIVITY run the setup routines (create the db/tables from an *.sql file & INSERT the dummy data where needed)...then load the SECOND Activity (with ContentProvider/ Loaders, etc.) so the user can start adding data.
To me, the simple operation of creating the db/tables shouldn't require all the OVERHEAD of a ContentProvider and a bunch of Cursors and Loaders.
Is there anybody who could point me to a SIMPLE solution? Thanks!
Yaqub's link was helpful...
...what i did was create public static final String arrays in a DBConstants class containing the commands to create the Database on first run.
Imagine the following scenario (I allow backup / restore from my app, I'm doing backup / restore white the entire file.db):
The user make backup of the database.
In the future I do an update on my application which has a new version of the database.
what would happen if the user restore the database with the old version?
How can I avoid this kind of problem?
It would be a good idea to use BackupHelper? I did a simulation of the worst scenario of my database and gave 20k, BackupHelper is recommended for less than 1mb, it would be a good idea to use it? I think my app will never exceed 100kb.
You access SQLite databases via a SQLiteOpenHelper, which provides three callbacks: onCreate(), onUpgrade() and onOpen().
The constructor declares a version parameter, and internally it compares the database version (which is stored in the file) with the supplied argument. If the requested version is newer than the file's, your onUpgrade(db, old, new) is called and you get a chance to alter tables, fill rows and so on.
The restore procedure should simply close all open cursors and helpers and copy the new file in.
May be this is not the best approach but you can do it as:
1- Store the DB Version in the database.
2- After restoring the database, check the DB Version and do the required changes accordingly. Like
void afterRestoration()
{
long dbVersion = get from db;
if(dbVersion == 1)
{
alter table1 add column1;
}
else
{
}
}
According to http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase%28%29
Once opened successfully, the database is cached, so you can call this
method every time you need to write to the database.
Consider the following snippet:
SQLiteDatabase db1 = openHelperImplObj.getWritableDatabase();
// do something with db1
SQLiteDatabase db2 = openHelperImplObj.getWritableDatabase();
// do something with db2
db2.close();
// do something with db1
db1.close();
I presume the second call to getWritableDatabase() will return the same cached DB (the db1), wouldn't the line db2.close() cause any issue to db1 operations that happen afterward? If so, what is the recommended way to avoid such problem since the second call may happen anywhere, i.e. in a different function or even in different class.
When you open a data base by using db openHelperImplObj.getWritableDatabase();
then following thing check
1>If database is not created then it create database and open it for write mode else created first then open.
2>Second and most important what i have observed if data base is already created then it opened it but if its open already it do nothing, That means it occupy the old instance of data
base that open DB already until you close it.Thats why its better practice to close DB once it
use over
Hope you got