I am using the below code for downloading an already uploaded sqlite db file from google drive to the data/data/packagename/databases folder, but when the method completes, I am seeing a db corruption warning message logged in logcat and also all the data on the device for the app is overwritten and shows up blank, upon opening the app.
mfile = Drive.DriveApi.getFile(mGoogleApiClient, mResultsAdapter.getItem(0).getDriveId());
mfile.openContents(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null).setResultCallback(contentsOpenedCallback);
--mfile is an instance of DriveFile
final private ResultCallback<ContentsResult> contentsOpenedCallback = new ResultCallback<ContentsResult>()
{
#Override
public void onResult(ContentsResult result)
{
if (!result.getStatus().isSuccess())
{
FileUtils.appendLog(getApplicationContext(), Tag + "-onResult", "Error opening file");
return;
}
try
{
if (GetFileFromDrive(result))
{
//FileUtils.Restore(getApplicationContext());
SharedPrefHelper.EditSharedPreference(getApplicationContext(), Constants.PREFS_DO_RESTORE, false);
}
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
private boolean GetFileFromDrive(ContentsResult result)
{
Contents contents = result.getContents();
//InputStreamReader rda = new InputStreamReader(contents.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(contents.getInputStream()));
FileOutputStream outStream;
String currLine;
boolean restoreSuccess = false;
File sourceDbFile = BackupDBBeforeDeletion();
if(sourceDbFile != null)
sourceDbFile.delete();
try
{
outStream = new FileOutputStream(getApplicationContext().getDatabasePath(Constants.DB_NAME));
while ((currLine = reader.readLine()) != null)
{
outStream.write(currLine.getBytes());
}
outStream.flush();
reader.close();
outStream.close();
restoreSuccess = true;
}
catch (FileNotFoundException e)
{
// TODO: Log exception
}
catch (IOException e)
{
// TODO: Log Exception
}
return restoreSuccess;
}
When the method GetFileFromDrive completes, a db corruption shows up on LogCat and all the existing data on the app's datanase file (sqlite db) is gone.
Please help, as I have verified that the drive uploaded sqlite db file is correct and well formed, by downloading the same and opening it up in Sqlite Browser. It's the download from drive that is not working.
This solution is not working for me. The sqlite files I got from google drive is more longer than I saved in google drive. That, probably, happen because you are using a Buffereader class and the method readline that reads data in char.
In my project and experience this solutions does not work, I got a corrupted sqlite db.
So... I save sqlite db in google drive in byte so **I read from google drive the same sqlite db in byte, using BufferedInputStream.
This works perfectly for me:
DriveContents contents = result.getDriveContents();
BufferedInputStream bis = new BufferedInputStream(contents.getInputStream());
byte[] buffer = new byte[1024];
int bytesread = 0;
FileOutputStream outStream;
/*if(currentDB != null)
currentDB.delete();*/
try
{
outStream = new FileOutputStream(currentDB);
while( (bytesread = bis.read(buffer)) != -1)
{
outStream.write(buffer,0,bytesread);
}
outStream.flush();
bis.close();
outStream.close();
}
catch (FileNotFoundException e)
{
Log.i(TAG,e.getMessage());
}
catch (IOException e)
{
Log.i(TAG,e.getMessage());
}
finally {
Toast.makeText(getActivity().getBaseContext(),"Data from Google Drive restored successfully." , Toast.LENGTH_LONG).show();
}
contents.discard(mGoogleApiClient);
I was able to finally fix my own issue, by replacing the file.openContents with file.open and setting a result call back with DriveContents result back rather than ContentsResult.
Also, used the DriveContents to set an InputStream on the same (initially opened in Mode_Read_Only in open method) and then writing it out into a physical ".db" file on the data base path location.
Now, the database doesn't get corrupted and restores data successfully.
Related
My application allows users to select an image to upload. When users select an image from a picasa album my data intent comes back with dat=content://com.sec.android.gallery3d.provider/picasa/item/....
Apparently when selecting an image from a picasa folder, I must handle getting the image differently as noted in this answer.
But before I implement a fix, I want to be able to reproduce the crash so I can verify my fix actually works. So how can I get a Picasa folder on my new (marshmallow) Android test device since Picasa has been killed by Google?
The most guaranteed way of getting a file send inside an intent, is to open a stream to it and copy it over to a private folder on your app.
This way works for local file, content uri, picasa, all of it.
Something like that:
private File getSharedFile() {
Uri uri = intent.getExtras().getParcelable(Intent.EXTRA_STREAM);
// or using the new compat lib
Uri uri = ShareCompat.IntentReader(this).getStream();
InputStream is = null;
OutputStream os = null;
try {
File f = ... define here a temp file // maybe getCacheDir();
is = getContentResolver().openInputStream(uri);
os = new BufferedOutputStream(new FileOutputStream(f));
int read;
byte[] bytes = new byte[2048];
while ((read = is.read(bytes)) != -1) {
os.write(bytes, 0, read);
}
return f;
} catch (Exception e) {
... handle exceptions, buffer underflow, NPE, etc
} finally {
try { is.close(); } catch (Exception e) { /* u never know */ }
try {
os.flush();
os.close();
} catch (Exception e) { /* seriously can happen */ }
}
return null;
}
I am trying to read a file i download from Dropbox (using Dropbox CORE API).
private void downloadropboxfile(final String filename)
{
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
File file = new File(getCacheDir(),filename);
if(!file.exists())
file.createNewFile();
FileOutputStream outputStream = new FileOutputStream(file);
DropboxAPI.DropboxFileInfo info=mDBApi.getFile("/" + filename, null, outputStream, null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
Then in another function i call the downloaddropbox function and try to read the file content on Onclick event.
String filename = "info.txt";
downloadropboxfile(filename);
String strLine = "";
try {
InputStream instream = new FileInputStream(new File(getCacheDir(),filename));
InputStreamReader inputreader = new InputStreamReader(instream);
BufferedReader bReader = new BufferedReader(inputreader);
/** Reading the contents of the file , line by line */
while ((strLine = bReader.readLine()) != null) {
mTestOutput.setText(strLine);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
My problem is that i don't get the file content immediately. I need to click the button 3-4 times in order to read the file content. What's the problem with my code?
You're calling downloaddropboxfile, which starts a new thread to download the file. But then you're immediately trying to read the local file (before it's downloaded).
If you haven't worked with threading before, the important thing to understand is that downloaddropboxfile returns almost immediately, but the thread it starts keeps running in the background. You'll need to wait for it to finish before trying to do something with the downloaded file.
I literally looked through stackoverflow trying to find the right answer... maybe I am doing something wrong.
I am making my first more elaborate app, that is quizz app for children. I want the scores to be saved in the highscorestable.txt, that will be later opened, updated, read, etc. The file should exist after closing the application to reuse it with the next game and so on.
I was using http://developer.android.com/guide/topics/data/data-storage.html . I want the file to be saved on the phone memory.
I have the following code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_high_scores);
Intent intent = getIntent();
String userData;
scores =(EditText)findViewById(R.id.scores);
if(intent.getStringExtra(EndScreen.EXTRA_MESSAGE)!=null)
{
userData = intent.getStringExtra(EndScreen.EXTRA_MESSAGE);
}
else
{
userData="";
}
String temp = "";//to widzi przy zaladowaniu
String output = "";
String g="";
//FIRST READING not necessary?
try{
FileInputStream fin = openFileInput("highscorestable.txt");
int c;
while( (c = fin.read()) != -1){
temp = temp + Character.toString((char)c);
}
fin.close();
}
catch (Exception e) {
// e.printStackTrace();
}
if(temp.equals(null))
{
temp = "";
}
//output = userData; //+ temp;
FileOutputStream fos;//WRITING
try {
fos = openFileOutput("highscorestable.txt", Context.MODE_PRIVATE);
fos.write(userData.getBytes());
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
//READING2
try{
FileInputStream fin = openFileInput("highscorestable.txt");
int c;
while( (c = fin.read()) != -1){
g = g + Character.toString((char)c);
}
fin.close();
output= output+g;
scores.setText(output);
}
catch (Exception e) {
}
The intent itself works, actually everything works, however the fileitself does not last. I mean, when I start a new game, the old data is not restored. How to fix it?
Try using sharedPrefrences: http://developer.android.com/training/basics/data-storage/shared-preferences.html
They are stored permanently in the app as XML and are only readable to the app if configured properly. (unless you NEED text, read here: http://developer.android.com/training/basics/data-storage/files.html . Remember to add the permissions to your manifest)
EDIT:
try appending to the file not writing
I'm trying to read a file created by another Android application.
File file = new File("/data/data/air.br.com.screencorp.MobilePlayer/br.com.screencorp.MobilePlayer/Local Store/token");
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
Log.d("SIZE", "Total file size to read (in bytes) : "
+ fis.available());
int content;
StringBuilder token = new StringBuilder();
while ((content = fis.read()) != -1) {
token.append((char) content);
}
Log.d("TOKEN", token.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null)
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
I don't know why, but I'm not allowed to access that file. I have the READ_EXTERNAL_STORAGE permission on my manifest.
Should I use SharedPreferences?
Thanks.
Data of other applications private data can not be accessed from your app. This is the security model of android. The app should have set MODE_WORLD_READABLE permission on the file, only then can you access the file
I'm having issues using the Cards from the recently released GDK. Basically, Card.addImage() can only take two arguments, a resource id or a URI.
For my use case, I need to open an image that exists as a file not directly as a resource. So for testing purposes I'm including the images in the assets folder. Trying to access them directly from the asset folder fails, so I'm copying them from there to internal storage. Once they're copied, I generate a URI from the file and assign it to the card. The resulting card shows a grey block where the image should be.
String fileName = step.attachment; //of the form, "folder1/images/image1.jpg"
File outFile = new File(getFilesDir()+File.separator+fileName);
FileChannel inputChannel = null;
FileChannel outputChannel = null;
try {
//check to see if the file has already been cached in internal storage before copying
if(!outFile.exists()) {
FileInputStream inputStream = new FileInputStream(getAssets().openFd(fileName).getFileDescriptor());
FileOutputStream outputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
inputChannel = inputStream.getChannel();
outputChannel = outputStream.getChannel();
outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally{
try {
if(inputChannel!=null)
inputChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(outputChannel!=null)
outputChannel.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
card.addImage(Uri.fromFile(outFile));
It's hard to diagnose because I have no clue what the Card is doing internally.
Instead of writing
new FileInputStream(getAssets().openFd(fileName).getFileDescriptor());
can you try
getAssets().openFd(fileName).createInputStream();
and see if it works?
To answer your original question, the addImage method supports resource: and file: URIs.
This is very strange, but I managed to solve my problem. I replaced the file copy code with the following and it appears to have solved my issues
InputStream in = null;
OutputStream out = null;
try {
in = getAssets().open(step.attachment);
out = new FileOutputStream(outFile);
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + step.attachment, e);
}
It's not clear to me why/how I was copying my entire apk, but I'm guessing it's the call to
getAssets().openFd(fileName).getFileDescriptor()
Perhaps it was returning the file descriptor of the apk. It's odd because I've seen some claim that the previous method works.