Application gives data from deleted database file in Android - java

I have been working on getting my database backing up to work and I have reached a point where I am not sure what to do.
Basically at first the application opens a Login activity, the user logs in and their database file (if it exists) is downloaded from the Firebase Storage, and then the application navigates to the MainActivity.
In the MainActivity I call a method that sends the user's database file to Firebase Storage. I tried to manage the process by closing the database but since i couldn't fix an error of "E/ROOM: Invalidation tracker is initialized twice :/.", then I found an answer to use a checkpoint (Backup Room database). Now I implemented the forced checkpoint method.
(MarkerDao)
#RawQuery
int checkpoint(SupportSQLiteQuery supportSQLiteQuery);
(MarkerRepository)
public void checkPoint(){
Thread thread= new Thread(() -> markerDao.checkpoint(new SimpleSQLiteQuery("pragma wal_checkpoint(full)")));
thread.start();
}
(ViewModel)
public void setCheckpoint(){
repository.checkPoint();
}
(Database back-up method in the MainActivity)
private void copyDbToFirebase(){
String currentDBPath = "/data/data/"+ getPackageName() + "/databases/locations_table";
File dbBackupFile = new File(currentDBPath);
if (dbBackupFile.exists()){
markerViewModel.setCheckpoint();
// create file from the database path and convert it to a URI
Uri backupDB = Uri.fromFile(new File(currentDBPath));
// Create a StorageReference
StorageReference dbReference = storageRef.child("users").child(userId).child("user database").child("locations_table");
// Use the StorageReference to upload the file
if (userId != null){
dbReference.putFile(backupDB).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "onSuccess: "+4 + taskSnapshot);
Toast.makeText(getApplicationContext(), "Database copied to Firebase 4", Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "onFailure: "+ e.getMessage());
}
});
}
}
}
If the user logs out, then the files in the "/data/data/"+ getPackageName() + "/databases/" are deleted, which I have manually confirmed by looking at the databases folder of the application.
My issue is that after the databases are deleted and a new user logs in, then the previous database data remains but when I manually check the app's data folder, then the /databases/ folder shows that the files were deleted and a new file is created but it doesn't show any WAL or SHM files and also I get the data of another database which is created when the application first runs, but that file is also not shown in the databases/ folder.
Can anyone explain why the folder doesn't show the files that should be present, where is the application getting the data that was deleted and how to fix it.
Edit: My application has multiple Room databases and I just realized that all the data is still readable after the files were deleted.
The method to delete the database files
private boolean deleteDatabaseFiles(File path) {
if(path.exists() ) {
File[] files = path.listFiles();
for(int i=0; i<files.length; i++) {
if(files[i].isDirectory()) {
deleteDatabaseFiles(files[i]);
}
else {
files[i].delete();
}
}
}
return true;
}

If you are using the same exact RoomDatabase object simply building another one over the same object will prevent any hold over cached data from showing up. I've tested this using multiple database swaps large and small and there is no bleed over.
If you are using a new Instance of the RoomDatabase object for every login try closing the old one after the user logs out. Room will typically close when not needed but if you need it to happen immediately, manually closing it is your best bet.
roomDb.getOpenHelper().close();

Related

Parse Server: Remove old profile image associated with a user

I am using File System Storage adapter to save uploaded files on the parse server.
In my app each user can have profile photo. when the user wants to change his photo, the old one should be deleted from the server. But the old image remains unchanged. It leads to fill the server storage after some time. Here is my code:
public void update (Uri uri)
{
ParseUser user = ParseUser.getCurrentUser();
if(uri!=null){
InputStream iStream=getContentResolver().openInputStream(uri);
byte[]image=Helper.getBytes(iStream);
ParseFile file=new ParseFile("profile.png",image);
file.saveInBackground();
user.put("photo",file);
user.saveInBackground();
}
}
Unfortunately Android SDK does not have a function to delete the file but you can do that using Cloud Code Functions or maybe a trigger. Something like this should solve your problem:
Parse.Cloud.beforeSave('_User', ({ original, object }) => {
if (original.get('photo').url() !== object.get('photo').url()) {
original.get('photo').destroy();
}
});
You should propably delete the line "file.saveInBackground();".
Because its runs in background. And when you put that file in user object saving file is not complete and parse server will upload same file to server again with the user object. and You will end having two duplicate files.
Change your code to this:
public void update (Uri uri)
{
ParseUser user = ParseUser.getCurrentUser();
if(uri!=null){
InputStream iStream=getContentResolver().openInputStream(uri);
byte[]image=Helper.getBytes(iStream);
ParseFile file=new ParseFile("profile.png",image);
user.put("photo",file);
user.saveInBackground();
}
}
With this code you upload file only once

File not found exception? (Voice recog)

Sorry for the long question, I have been stuck on this for a month, and I want to provide as much detail as possible...its just a file not found exception in a simple library... :)
I am getting a file not found exception on my variances file:
I do, however, have the variances file:
I am trying to simply implement voice recognition in my background service, so that I can detect when the user says the word hello (using pocketsphinx).
The problem happens in this method: createSphinxDir();
Here is my service:
#Override
public void onCreate() {
super.onCreate();
setupRecog();
}
private void setupRecog() {
String sphinxDir = createSphinxDir();
Log.v(TAG, "ABOUT TO CREATE SETUP");
if (sphinxDir != null) {
try {
Log.v(TAG, "SETTING UP! :)");
mSpeechRecognizer = defaultSetup()
.setAcousticModel(new File(sphinxDir, "en-us-ptm"))
.setDictionary(new File(sphinxDir, "hello.dict"))
.setBoolean("-allphone_ci", true) //WHAT IS THIS
.getRecognizer();
mSpeechRecognizer.addListener(this);
Log.v(TAG, "ADDED LISTENER");
if ((new File(sphinxDir + File.separator + "command.gram")).isFile()) {
mSpeechRecognizer.addKeywordSearch("hello",
new File(sphinxDir + File.separator + "command.gram"));
Log.v(TAG, "ADDED KEYWORD SEARCH! :)");
}
// Or wherever appropriate
mSpeechRecognizer.startListening("wakeup"); //Is this correct?
Log.v(TAG, "STARTED LISTENING");
} catch (IOException e) {
Log.v("ERROR", TAG);
}
}
}
String createSphinxDir() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String sphinxDir = prefs.getString("sphinx", null);
if (sphinxDir == null) {
Assets assets;
Log.v(TAG, "Assets are not synced, should sync now:");
try {
Log.v(TAG, "In try block!");
assets = new Assets(this);
File sphinxDirFile = assets.syncAssets();
Log.v(TAG, "Syncing assets...should set up listener");
if (sphinxDirFile != null) {
sphinxDir = sphinxDirFile.getAbsolutePath();
SharedPreferences.Editor editor = prefs.edit();
editor.putString("sphinx", sphinxDir);
editor.commit();
Log.v(TAG, "Set up listener");
}else{
Log.v(TAG, "sphinxDirFile is null!");
}
} catch (IOException e) { //THIS IS THE PLACE WHERE I AM GETTING THE ERROR!
e.printStackTrace();
Log.d(TAG, e.toString());
}
}
return sphinxDir;
}
I also have all the call back methods (onPartialResult, onResult, etc.) but they never get called.
Earlier I was getting an exception saying the variances .md5 file didn't exist, so I put a space in between the variances and the .md5, but now I am getting this error, and I don't know why...
Please let me know,
Ruchir
Earlier I was getting an exception saying the variances .md5 file didn't exist, so I put a space in between the variances and the .md5, but now I am getting this error, and I don't know why...
You should not do such things, it causes problems, instead you need to follow the documentation:
The standard way to ship resource files with your application in Android is to put them in assets/ directory of your project. But in order to make them available for pocketsphinx files should have physical path, as long as they are within .apk they don't have one. Assets class from pocketsphinx-android provides a method to automatically copy asset files to external storage of the target device. edu.cmu.pocketsphinx.Assets#syncAssets synchronizes resources reading items from assets.lst file located on the top assets/. Before copying it matches MD5 checksums of an asset and a file on external storage with the same name if such exists. It only does actualy copying if there is incomplete information (no file on external storage, no any of two .md5 files) or there is hash mismatch. PocketSphinxAndroidDemo contains ant script that generates assets.lst as well as .md5 files, look for assets.xml.
Please note that if ant build script doesn't run properly in your build process, assets might be out of sync. Make sure that script runs during the build.
To integrate assets sync in your application do the following
Include app/asset.xml build file from the demo application into your application. Edit build.gradle build file to run assets.xml:
ant.importBuild 'assets.xml'
preBuild.dependsOn(list, checksum)
clean.dependsOn(clean_assets)

Can't move file after DownloadManager completes download

in my Android app I am using the system Download Manager to download a photo, once recieved I process it and then I need to move it to another location. if I just copy it it works fine, if I try to move it/delete it I get an exception about it can't be moved.
Failed to delete original file '/data/user/0/com.android.providers.downloads/cache/a3133p2930-9.jpg' after copy to '/data/data/com.XXXXX.testharness/app_appdata/images/one/two/three/6/a3133p2930.jpg'
also tried:
1) remove it from download manager before trying to move it
2) set the destination directly to the target dir, but got an error I can only use public external folders.
3) tried using JAVA renameTo and Apache commons moveFile
this is a code snippet that show the relevant parts of what I am doing.
any ideas?
appreciated
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
String uriString = c.getString(
c.getColumnIndex(
DownloadManager.COLUMN_LOCAL_URI));
String uri2String = c.getString(
c.getColumnIndex(
DownloadManager.COLUMN_URI));
String localFileString = c.getString(
c.getColumnIndex(
DownloadManager.COLUMN_LOCAL_FILENAME));
File from = new File(localFileString);
File to = new File(appDataDir, localString);
File to2 = new File (appDataDir, localString + "/" + getFileNameFromUrl(uri2String));
if (!to.exists()) {
if (to.mkdirs()) {
Log.d(LCAT, "Directory Created");
}
}
dm.remove(downloadId);
//boolean a = from.renameTo(to2);
try {
FileUtils.copyFile(from, to2);
} catch (Exception e) {
Log.d(LCAT, "rename success? " + e.getMessage());
}
i think you can not delete the cache of downloadmanager, i think it clears itself automatically after you removed the downloadid from its database but if you like to have a control to your file you can set destination folder to your private external storage and then after download completed delete it.
File rootDirectory = new File(getActivity().getExternalFilesDir(null).getAbsoluteFile().toString());
if(!rootDirectory.exists()){
rootDirectory.mkdirs();
}
req.setDestinationInExternalFilesDir(getActivity(),null ,"/" + fileName);
and after your download completed you can delete it like:
from.delete();
and the doc says:
public int remove (long... ids)
Cancel downloads and remove them from
the download manager. Each download will be stopped if it was running,
and it will no longer be accessible through the download manager. If
there is a downloaded file, partial or complete, it is deleted.
http://developer.android.com/reference/android/app/DownloadManager.html#remove%28long...%29

Network error from google services in Android

I am developing an app in which i have an integrated google drive. I want to store images captured by the device under a folder in google drive.
By doing so in result.getstatus() method from google service is returning {statusCode=Failed to retrieve item from a network}
I am using following function,
final ResultCallback<DriveIdResult> idCallback = new ResultCallback<DriveIdResult>() {
#Override
public void onResult(DriveIdResult result) {
System.out.println("result.getStatus()----"+ result.getStatus());
System.out.println("result.getStatus() code----"+ result.getStatus().getStatusCode());
if (!result.getStatus().isSuccess()) {
showMessage("Cannot find DriveId. Are you authorized to view this file?");
return;
}
DriveFolder folder = Drive.DriveApi
.getFolder(getGoogleApiClient(), result.getDriveId());
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("NewFolder").build();
folder.createFolder(getGoogleApiClient(), changeSet)
.setResultCallback(createFolderCallback);
}
};
In first println---> I am getting {statusCode=Failed to retrieve item from a network}
In second println--> I am getting 7
Please help me...
I have the same status code when the file is permanently deleted. Remove any cached DriveId / resource id and create the new file.

Issues with creating custom events in android

I am writing a custom event and would like some help please. Most of what I am about to talk about is based on the help provided at Custom event listener on Android app
So here is my issue. I am writing an app that needs to download updated images from the web, store the images on the phone, then later display those images. Basically, I download any needed images during a splash screen. Then when the images are downloaded and stored, the splash screen clears and any necessary (newly downloaded) images are displayed on the screen. Here is the problem: the download process is done via an asynctask so the part where the images are loaded on to the screen can't be done inside the asynctask. It has to be done on the main UI thread. I would like to create an event and a custom event listener for the main thread to listen for that basically tells the main UI thread that it is safe to start loading the downloaded images from memory.
According to the discussion from the link above, I came up with this so far... a download listener interace
public interface DataDownloadListener {
void onDownloadStarted();
void onDownloadFinished();
}
an event class...
public class DataDownloadEvent {
ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public void setOnDownload(DataDownloadListener listener){
this.listeners.add(listener);
}
}
My problem is that I don't understand where to put the last two steps in those instructions. I thought I would have to put the listener and event inside the class that actually initiates the downloads. But where? Here is my function that initiates the download and saves it to the device:
public String download(String sourceLocation) {
String filename = "";
String path = "";
try {
File externalStorageDirectory = Environment
.getExternalStorageDirectory();
URL urlTmp = new URL(sourceLocation);
filename = urlTmp.getFile()
.substring(filename.lastIndexOf("/") + 1);
path = externalStorageDirectory + PATH;
// check if the path exists
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
filename = path + filename;
f = new File(filename);
//only perform the download if the file doesn't already exist
if (!f.exists()) {
Bitmap bitmap = BitmapFactory.decodeStream(urlTmp.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(
filename);
if (bitmap != null) {
bitmap.compress(getFormat(filename), 50, fileOutputStream);
Log.d(TAG, "Saved image " + filename);
return filename;
}
}
else{
Log.d(TAG, "Image already exists: " + filename + " Not re-downloading file.");
}
} catch (MalformedURLException e) {
//bad url
} catch (IOException e) {
//save error
}
return null;
}
And the last step about registering the listener, where do I put that? The instructions say to put that somewhere during initialization. Does that mean in the onCreate method of my main activity? outside the class in the import section of the main activity? Never done a custom event before, so any help would be appreciated.
According to the discussion from the link above, I came up with this so far... a download listener interace
public interface DataDownloadListener {
void onDownloadStarted();
void onDownloadFinished();
}
an event class...
public class DataDownloadEvent {
ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public void setOnDownload(DataDownloadListener listener){
this.listeners.add(listener);
}
}
Ok...
Now in your download procedure, at the start of the download, cycle all the elements on the listeners ArrayList and invoke the onDownloadStarted event to inform all your listeners that the download is just started (in this event i presume you'll need to open the splashscreen).
Always in your download procedure, at the and of the download, cycle all the elements on the listeners ArrayList and invoke the onDownloadFinished event to inform all your listeners that the download is finished (now close the splashscreen).
How to cycle listeners on download completed
foreach(DataDownloadListener downloadListener: listeners){
downloadListener.onDownloadFinished();
}
How to cycle listeners on download started
foreach(DataDownloadListener downloadListener: listeners){
downloadListener.onDownloadStarted();
}
Don't make it static if possible... In the class that you'll use to download your files, simply add what you put in your DataDownloadEvent class (listeners arrayList and facility methods for adding and removing). You have no immediate need to use a class in that way (static members I mean).
Example
public class DownloadFileClassExample{
private ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public DownloadFileClassExample(){
}
public void addDownloadListener(DataDownloadListener listener){
listeners.add(listener);
}
public void removeDownloadListener(DataDownloadListener listener){
listeners.remove(listener);
}
//this is your download procedure
public void downloadFile(){...}
}
Then access you class in this way
DownloadFileClassExample example = new DownloadFileClassExample();
example.addDownloadListener(this); // if your class is implementing the **DataDownloadListener**
or use
example.addDownloadListener( new DataDownloadListener{...})

Categories

Resources