JSONArray throwing out of memory exception in android - java

In my app I sync some data at the end of day to the app server.For this I wrap all my data as a JSONArray of JSONObjects.The data mainly includes about 50 pictures each with a size of approx 50kb(along with some text data).All these pictures are encoded using base64 encoding.Everthing works fine when the pictures uploaded(along with some text data) are few in number,but when I upload a large no of pictures ,say around 50 then I see in the logs that all the data is properly formed into the JSONArray,however when I try to display the JSONArray using 'array.toString()' method I encounter an out of memory exception.This I believe is due to the heap getting full(however,when I try making android:largeHeap="true" in the manifest everything is working fine,however I want to avoid using this approach,since this is not a good practice).My intention is just to write this JSONArray value into a file and then break this file into small chunks and send it across to the server.
Please guide me of the best approach of writing the JSONAray value to the file which won't lead to OOM issues.Thanks !
Following is the format of the JSONArray:
[{"pid":"000027058451111","popup_time":"2014-01-13 23:36:01","picture":"...base64encoded string......","punching_time":"Absent","status":"Absent"},{"pid":"000027058451111","popup_time":"2014-01-13 23:36:21","picture":"...base64encoded string......","punching_time":"Absent","status":"Absent"}]
Following are the main snippets of my code:
JSONObject aux;
JSONArray array = new JSONArray();
.
.
// Looping through each record in the cursor
for (int i = 0; i < count; i++) {
aux = new JSONObject();
try {
aux.put("pid", c.getString(c.getColumnIndex("pid")));
aux.put("status", c.getString(c.getColumnIndex("status")));
aux.put("pop_time", c.getString(c.getColumnIndex("pop_time")));
aux.put("punching_time", c.getString(c.getColumnIndex("punching_time")));
aux.put("picture", c.getString(c.getColumnIndex("image_str"))); // stores base64encoded picture
} catch (Exception e) {
e.printStackTrace();
}
array.put(aux); // Inserting individual objects into the array , works perfectly fine,no error here
c.moveToNext(); // Moving the cursor to the next record
}
Log.d("Log", "length of json array - "+array.length()); // shows me the total no of JSONObjects in the JSONArray,works fine no error
// HAD GOT OOM HERE
//Log.d("Log", "JSONArray is - " + array.toString());
if (array.length() != 0){
try {
String responseCode = writeToFile(array); //Writing the JSONArray value to file,which will then send file to server.
if(responseCode.equals("200"))
Log.d("Log","Data sent successfully from app to app server");
else
Log.d("Log","Data NOT sent successfully from app to app server");
} catch (Exception e) {
e.printStackTrace();
}
}
.
.
private String writeToFile(JSONArray data) {
Log.d("Log", "Inside writeToFile");
File externalStorageDir = new File(Environment.getExternalStorageDirectory().getPath(), "Pictures/File");
if (!externalStorageDir.exists()) {
externalStorageDir.mkdirs();
}
String responseCode = "";
File dataFile = new File(externalStorageDir, "File");
/* FileWriter writer;
String responseCode = "";
try {
writer = new FileWriter(dataFile);
writer.append(data);
writer.flush();
writer.close();
responseCode = sendFileToServer(dataFile.getPath(), AppConstants.url_app_server); // Sends the file to server,worked fine for few pictures
} catch (IOException e) {
e.printStackTrace();
}*/
try {
FileWriter file = new FileWriter("storage/sdcard0/Pictures/File/File");
file.write(data.toString()); // GOT OOM here.
file.flush();
file.close();
Log.d("Log","data written from JSONArray to file");
responseCode = sendFileToServer(dataFile.getPath(), AppConstants.url_app_server); // Sends the file to server,worked fine for few pictures
} catch (IOException e) {
e.printStackTrace();
}
return responseCode;
}
public String sendFileToServer(String filename, String targetUrl) {
.
.
// Sends the file to server,worked fine for few pictures
.
.
return response;
}

Here's the issue. You're trying to load your entire dataset into memory. And you're running out of memory.
Android's JSON classes (and some other JSON libraries) are designed to take a Java object (in memory), serialize it to a parse tree of objects (e.g. JSONObject, JSONArray) (in memory), then convert that tree to a String (in memory) and write it out somewhere.
Specifically in your case (at the moment) it appears what when it converts the parse tree into a String it runs out of memory; That String is effectively doubling the amount of memory required at that point.
To solve your issue you have a few different choices, I'll offer 3:
Don't use JSON at all. Refactor to simply send files and information to your server.
Refactor things so that you only read X images into memory at a time and have multiple output files. Where X is some number of images. Note this is still problematic if your image sizes vary greatly / aren't predictable.
Switch to using Jackson as a JSON library. It supports streaming operations where you can stream the JSON to the output file as you create each object in the array.
Edit to add: for your code, it would look something like this using Jackson:
// Before you get here, have created your `File` object
JsonFactory jsonfactory = new JsonFactory();
JsonGenerator jsonGenerator =
jsonfactory.createJsonGenerator(file, JsonEncoding.UTF8);
jsonGenerator.writeStartArray();
// Note: I don't know what `c` is, but if it's a cursor of some sort it
// should have a "hasNext()" or similar you should be using instead of
// this for loop
for (int i = 0; i < count; i++) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("pid", c.getString(c.getColumnIndex("pid")));
jsonGenerator.writeStringField("status", c.getString(c.getColumnIndex("status")));
jsonGenerator.writeStringField("pop_time", c.getString(c.getColumnIndex("pop_time")));
jsonGenerator.writeStringField("punching_time", c.getString(c.getColumnIndex("punching_time")));
// stores base64encoded picture
jsonGenerator.writeStringField("picture", c.getString(c.getColumnIndex("image_str")));
jsonGenerator.writeEndObject();
c.moveToNext(); // Moving the cursor to the next record
}
jsonGenerator.writeEndArray();
jsonGenerator.close();
The above is untested, but it should work (or at least get you going in the right direction).

First and foremost.Thanks a Billion to Brian Roach for assisting me.His inputs helped me solve the problem.I am sharing my answer.
What was I trying to solve? - In my project I had some user data(name,age,picture_time) and some corresponding pictures for each of the user data.At the EOD I needed to sync all this data to the app server.However when I tried to sync a lot of pictures(say 50 of 50kb approx) I faced an OOM(Out of Memory) issue.Initially, I was trying to upload all the data using a conventional JSONArray approach,however soon I found that I was hitting OOM.This, I attribute to the heap getting full when I was trying to access the JSONArray(which had loads of values and why not ?, afterall I was encoding the pics by base64encoding,which trust me has a hell lot of string data in it !)
Inputs from Brian suggested that I write all my data into a file one by one.So,after the whole process is complete I get one single file that has all the data(name,age,picture_time,base64encoded pictures etc) in it,and then I stream this file to the server.
Following is the code snippet which takes the user data from app database,corresponding pictures from sd card,loops through all the records,creates a JSONArray of JSONObjects using Jackson Json Library(which you need to include in your libs folder,should you use this code) and stores them into a file.This file is then streamed to the server(this snippet not included).Hope this helps someone!
// Sync the values in DB to the server
Log.d("SyncData", "Opening db to read files");
SQLiteDatabase db = context.openOrCreateDatabase("data_monitor", Context.MODE_PRIVATE, null);
db.execSQL("CREATE TABLE IF NOT EXISTS user_data(device_id VARCHAR,name VARCHAR,age VARCHAR,picture_time VARCHAR);");
Cursor c = db.rawQuery("SELECT * FROM user_data", null);
int count = c.getCount();
if (count > 0) {
File file = new File(Environment.getExternalStorageDirectory().getPath(), "Pictures/UserFile/UserFile");
JsonFactory jsonfactory = new JsonFactory();
JsonGenerator jsonGenerator = null;
try {
jsonGenerator = jsonfactory.createJsonGenerator(file, JsonEncoding.UTF8);
jsonGenerator.writeStartObject();
jsonGenerator.writeArrayFieldStart("user_data"); //Name for the JSONArray
} catch (IOException e3) {
e3.printStackTrace();
}
c.moveToFirst();
// Looping through each record in the cursor
for (int i = 0; i < count; i++) {
try {
jsonGenerator.writeStartObject(); //Start of inner object '{'
jsonGenerator.writeStringField("device_id", c.getString(c.getColumnIndex("device_id")));
jsonGenerator.writeStringField("name", c.getString(c.getColumnIndex("name")));
jsonGenerator.writeStringField("age", c.getString(c.getColumnIndex("age")));
jsonGenerator.writeStringField("picture_time", c.getString(c.getColumnIndex("picture_time")));
} catch (Exception e) {
e.printStackTrace();
}
// creating a fourth column for the input of corresponding image from the sd card
Log.d("SyncData", "Name of image - " + c.getString(c.getColumnIndex("picture_time")));
image = c.getString(c.getColumnIndex("picture_time")).replaceAll("[^\\d]", ""); //Removing everything except digits
Log.d("SyncData", "imagename - " + image);
File f = new File(Environment.getExternalStorageDirectory().getPath(), "Pictures/UserPic/" + image + ".jpg");
Log.d("SyncData", "------------size of " + image + ".jpg" + "= " + f.length());
String image_str;
if (!f.exists() || f.length() == 0) {
Log.d("SyncData", "Image has either size of 0 or does not exist");
try {
jsonGenerator.writeStringField("picture", "Error Loading Image");
} catch (Exception e) {
e.printStackTrace();
}
} else {
try {
// Reusing bitmaps to avoid Out Of Memory
Log.d("SyncData", "Image exists,encoding underway...");
if (bitmap_reuse == 0) { //ps : bitmap reuse was initialized to 0 at the start of the code,not included in this snippet
// Create bitmap to be re-used, based on the size of one of the bitmaps
mBitmapOptions = new BitmapFactory.Options();
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(f.getPath(), mBitmapOptions);
mCurrentBitmap = Bitmap.createBitmap(mBitmapOptions.outWidth, mBitmapOptions.outHeight, Bitmap.Config.ARGB_8888);
mBitmapOptions.inJustDecodeBounds = false;
mBitmapOptions.inBitmap = mCurrentBitmap;
mBitmapOptions.inSampleSize = 1;
BitmapFactory.decodeFile(f.getPath(), mBitmapOptions);
bitmap_reuse = 1;
}
BitmapFactory.Options bitmapOptions = null;
// Re-use the bitmap by using BitmapOptions.inBitmap
bitmapOptions = mBitmapOptions;
bitmapOptions.inBitmap = mCurrentBitmap;
mCurrentBitmap = BitmapFactory.decodeFile(f.getPath(), mBitmapOptions);
if (mCurrentBitmap != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
mCurrentBitmap.compress(Bitmap.CompressFormat.JPEG, 35, stream);
Log.d("SyncData", "------------size of " + "bitmap_compress" + "= " + mCurrentBitmap.getByteCount());
} catch (Exception e) {
e.printStackTrace();
}
byte[] byte_arr = stream.toByteArray();
Log.d("SyncData", "------------size of " + "image_str" + "= " + byte_arr.length);
stream.close();
stream = null;
image_str = Base64.encodeToString(byte_arr, Base64.DEFAULT);
jsonGenerator.writeStringField("picture", image_str);
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
try {
jsonGenerator.writeEndObject(); //End of inner object '}'
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
c.moveToNext(); // Moving the cursor to the next record
}
try {
jsonGenerator.writeEndArray(); //close the array ']'
//jsonGenerator.writeStringField("file_size", "0"); // If need be, place another object here.
jsonGenerator.writeEndObject();
jsonGenerator.flush();
jsonGenerator.close();
} catch (JsonGenerationException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
c.close();
db.close();
}

Related

App Intent Problem | Your app contains an Intent Redirection vulnerability

I got this message after updating app in play console. I am sharing code of a method where the error is, as suggested by Google. I never updated this part of the code and it never showed any problem before. I am not sure why it is showing me an error. Do I need to update the way of saving a file? I hope to find a solution here.
public void saveDocument(ScannedDocument scannedDocument) {
Mat doc = (scannedDocument.processed != null) ? scannedDocument.processed : scannedDocument.original;
Intent intent = getIntent();
String fileName;
boolean isIntent = false;
Uri fileUri = null;
if (intent.getAction().equals("android.media.action.IMAGE_CAPTURE")) {
fileUri = ((Uri) intent.getParcelableExtra(MediaStore.EXTRA_OUTPUT));
Log.d(TAG, "intent uri: " + fileUri.toString());
try {
fileName = File.createTempFile("onsFile", ".jpg", this.getCacheDir()).getPath();
} catch (IOException e) {
e.printStackTrace();
return;
}
isIntent = true;
} else {
String folderName = mSharedPref.getString("storage_folder", FOLDER_NAME);
File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString()
+ "/" + folderName);
if (!folder.exists()) {
folder.mkdirs();
Log.d(TAG, "wrote: created folder " + folder.getPath());
}
fileName = folder.getAbsolutePath()
+ "/DOC-"
+ new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date())
+ ".jpg";
}
Mat endDoc = new Mat(Double.valueOf(doc.size().width).intValue(),
Double.valueOf(doc.size().height).intValue(), CvType.CV_8UC4);
Core.flip(doc.t(), endDoc, 1);
Imgcodecs.imwrite(fileName, endDoc);
endDoc.release();
try {
ExifInterface exif = new ExifInterface(fileName);
exif.setAttribute("UserComment", "Generated");
String nowFormatted = mDateFormat.format(new Date().getTime());
exif.setAttribute(ExifInterface.TAG_DATETIME, nowFormatted);
exif.setAttribute(ExifInterface.TAG_DATETIME_DIGITIZED, nowFormatted);
// exif.setAttribute("Software", "OpenNoteScanner " + BuildConfig.VERSION_NAME + "");
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
}
if (isIntent) {
InputStream inputStream = null;
OutputStream realOutputStream = null;
try {
inputStream = new FileInputStream(fileName);
realOutputStream = this.getContentResolver().openOutputStream(fileUri);
// Transfer bytes from in to out
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) > 0) {
realOutputStream.write(buffer, 0, len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
try {
inputStream.close();
realOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
animateDocument(fileName, scannedDocument);
Log.d(TAG, "wrote: " + fileName);
if (isIntent) {
new File(fileName).delete();
setResult(RESULT_OK, intent);
finish();
} else {
addImageToGallery(fileName, this);
}
refreshCamera();
}
Google has a page on Mitigating Intent Redirection vulnerabilities that you should read carefully.
The short version is that the vulnerability could potentially1 be exploited by a malicious app to allow it to access private app components or files.
The document explains three possible ways to mitigate this vulnerability. Unfortunately, there is not enough context to be sure which of the three is most appropriate for your app. However, the first one is straightforward:
"If the affected app component does not need to receive Intents from other apps then you can make that app component private by setting `android:exported="false" in your Manifest."
I never updated this part of the code and it never showed any problem before.
That could mean that this is a relatively new kind of Android vulnerability, or that Google's methodology for detecting it has become more rigorous since last time you published your app.
Do I need to update the way of saving a file?
Possibly yes. Or possibly one of the mitigations will be sufficient.
I hope to find a solution here.
There are some possible solutions in the Google document I linked to.
1 - It is moot if it is actually possible to exploit the vulnerability in your app. The point is that Google Play Store's scanning / analysis / testing methodology has found what they believe to be a problem. Their goal is to protect Play Store users.

Reading Large file A, Search Records matching records from file B and write file C in java

I have two files assume its already sorted.
This is just example data, in real ill have around 30-40 Millions of records each file Size 7-10 GB file as row length is big, and fixed.
It's a simple text file, once searched record is found. ill do some update and write to file.
File A may contain 0 or more records of matching ID from File B
Motive is to complete this processing in least amount of time possible.
I am able to do but its time taking process...
Suggestions are welcome.
File A
1000000001,A
1000000002,B
1000000002,C
1000000002,D
1000000002,D
1000000003,E
1000000004,E
1000000004,E
1000000004,E
1000000004,E
1000000005,E
1000000006,A
1000000007,A
1000000008,B
1000000009,B
1000000010,C
1000000011,C
1000000012,C
File B
1000000002
1000000004
1000000006
1000000008
1000000010
1000000012
1000000014
1000000016
1000000018\
// Not working as of now. due to logic is wrong.
private static void readAndWriteFile() {
System.out.println("Read Write File Started.");
long time = System.currentTimeMillis();
try(
BufferedReader in = new BufferedReader(new FileReader(Commons.ROOT_PATH+"input.txt"));
BufferedReader search = new BufferedReader(new FileReader(Commons.ROOT_PATH+"search.txt"));
FileWriter myWriter = new FileWriter(Commons.ROOT_PATH+"output.txt");
) {
String inLine = in.readLine();
String searchLine = search.readLine();
boolean isLoopEnd = true;
while(isLoopEnd) {
if(searchLine == null || inLine == null) {
isLoopEnd = false;
break;
}
if(searchLine.substring(0, 10).equalsIgnoreCase(inLine.substring(0,10))) {
System.out.println("Record Found - " + inLine.substring(0, 10) + " | " + searchLine.substring(0, 10) );
myWriter.write(inLine + System.lineSeparator());
inLine = in.readLine();
}else {
inLine = in.readLine();
}
}
in.close();
myWriter.close();
search.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Read and Write to File done in - " + (System.currentTimeMillis() - time));
}
My suggestion would be to use a database. As said in this answer. Using txt files has a big disadvantage over DBs. Mostly because of the lack of indexes and the other points mentioned in the answer.
So what I would do, is create a Database (there are lots of good ones out there such as MySQL, PostgreSQL, etc). Create the tables that are needed, and read the file afterward. Insert each line of the file into the DB and use the db to search and update them.
Maybe this would not be an answer to your concrete question on
Motive is to complete this processing in the least amount of time possible.
But this would be a worthy suggestion. Good luck.
With this approach I am able to process 50M Records in 150 Second on i-3, 4GB Ram and SSD Hardrive.
private static void readAndWriteFile() {
System.out.println("Read Write File Started.");
long time = System.currentTimeMillis();
try(
BufferedReader in = new BufferedReader(new FileReader(Commons.ROOT_PATH+"input.txt"));
BufferedReader search = new BufferedReader(new FileReader(Commons.ROOT_PATH+"search.txt"));
FileWriter myWriter = new FileWriter(Commons.ROOT_PATH+"output.txt");
) {
String inLine = in.readLine();
String searchLine = search.readLine();
boolean isLoopEnd = true;
while(isLoopEnd) {
if(searchLine == null || inLine == null) {
isLoopEnd = false;
break;
}
// Since file is already sorted, i was looking for the //ans i found here..
long seachInt = Long.parseLong(searchLineSubString);
long inInt = Long.parseLong(inputLineSubString);
if(searchLine.substring(0, 10).equalsIgnoreCase(inLine.substring(0,10))) {
System.out.println("Record Found - " + inLine.substring(0, 10) + " | " + searchLine.substring(0, 10) );
myWriter.write(inLine + System.lineSeparator());
}
// Which pointer to move..
if(seachInt < inInt) {
searchLine = search.readLine();
}else {
inLine = in.readLine();
}
}
in.close();
myWriter.close();
search.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Read and Write to File done in - " + (System.currentTimeMillis() - time));
}

How to find directory for File Output Stream in Android app?

I have an app which gets data from an Arduino via bluetooth. The data are written into various ArrayLists and saved in files afterwards. Here is the code:
public boolean SaveValues(ArrayList<String> arrayList1, ArrayList<String> arrayList2, String valueType, String timeStart, String timeStop) {
String filename = "File_" + valueType + "_" + timeStart + " bis " + timeStop;
FileOutputStream outputStream = null;
if(arrayList1.size() == 0)
return false;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
for (int i = 0; i < arrayList1.size(); i++) {
outputStream.write(arrayList1.get(i).getBytes());
outputStream.write("\n".getBytes());
outputStream.write(arrayList2.get(i).getBytes());
outputStream.write("\n".getBytes());
}
outputStream.close();
return true;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I also save the valuetype, timeStart and timeStop into a database to be able to find the files. My problem is, that somehow the table where I save these values got deleted, so I am not able to find the files in the app. I would like to find the files maybe on the phone or something. Actually, I just need the filenames to be able to open them in the app, because they contain data I need. So, where can I find these files?
I have tried searching in the phones files. The files, and all the other apps data, should be saved in Android/data/package-name but I can't find the package name in Android/data. I also tried to search for "File_" in the files, because that's what every one of my files start with. But no file gets found.

Downloading an image in java

I have to download an image from the nasa website. Problem is, that my code sometimes works, sucessfully downloading an image, while sometimes saves only 186B (don't know why exactly 186).
Problems is for sure connected with the way nasa sahres those photos. For instance, an image from that link https://mars.jpl.nasa.gov/msl-raw-images/msss/00001/mcam/0001ML0000001000I1_DXXX.jpg is saved sucessfully, while from that link https://mars.nasa.gov/mer/gallery/all/2/f/001/2F126468064EDN0000P1001L0M1-BR.JPG fails.
Here is my code
public static void saveImage(String imageUrl, String destinationFile){
URL url;
try {
url = new URL(imageUrl);
System.out.println(url);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream(destinationFile);
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Does someone have an idea, why is doesn't work?
public boolean downloadPhotosSol(int i) throws JSONException, IOException {
String url0 = "https://api.nasa.gov/mars-photos/api/v1/rovers/spirit/photos?sol=" + this.chosenMarsDate + "&camera=" + this.chosenCamera + "&page=" + i + "&api_key=###";
JSONObject json = JsonReader.readJsonFromUrl(url0);
if(json.getJSONArray("photos").length() == 0) return true;
String workspace = new File(".").getCanonicalPath();
String pathToFolder = workspace+File.separator+this.getManifest().getName() + this.chosenMarsDate + this.chosenCamera +"Strona"+i;
new File(pathToFolder).mkdirs();
for(int j = 0;j<json.getJSONArray("photos").length();j++) {
String url = ((JSONObject) json.getJSONArray("photos").get(j)).getString("img_src");
SaveImage.saveImage(url, pathToFolder+File.separator+"img"+j+".jpg");
}
return false;
}
When you get a 186 byte file, open it with a text editor and see what is inside. It could contain an HTTP error message in HTML format. If instead you see the first 186 bytes of your image file, then something is not working right with your program.
EDIT: From your comments it looks like you are getting an HTTP 301 response, which is a redirect to another location. A web browser handles this automatically without you noticing. However, your Java program is not following the redirect to the new location. You need to use an HTTP Java library that handles redirects.
Best and short way of doing it:
try(InputStream in = new URL("http://example.com/image.jpg").openStream()){
Files.copy(in, Paths.get("C:/File/To/Save/To/image.jpg"));
}

Get percentage of extraction with XZ Java for android

I am using the XZ Java library to extract a .xz file on Android of size around 16MB. I am running the extraction/decompression code as an AsyncTask and so, I would like to see the percentage of extraction via the onProgressUpdate(Integer ... values) method.
My decompression code looks something like this.
byte[] buf = new byte[8192];
String name = null;
try {
name = "my_archive.xz";
InputStream in = getResources().openRawResource(R.raw.my_archive);//new FileInputStream(name); //
FileOutputStream out = openFileOutput("my_archive.sqlite", Context.MODE_PRIVATE);
label = (TextView)findViewById(R.id.textLabel);
try {
in = new XZInputStream(in);
label.setText("Writing db file.");
int size;
while ((size = in.read(buf)) != -1) {
out.write(buf,0,size);
progress++;
publishProgress(progress);
}
}
catch (Exception e)
{
System.err.println("Input Stream error: "+e.getMessage());
}
finally {
// Close FileInputStream (directly or indirectly
// via LZMAInputStream, it doesn't matter).
in.close();
}
} catch (FileNotFoundException e) {
System.err.println("LZMADecDemo: Cannot open " + name + ": "
+ e.getMessage());
System.exit(1);
} catch (EOFException e) {
System.err.println("LZMADecDemo: Unexpected end of input on "
+ name);
System.exit(1);
} catch (IOException e) {
System.err.println("LZMADecDemo: Error decompressing from "
+ name + ": " + e.getMessage());
System.exit(1);
}
The progress variable should actually hold the percentage value. If anyone has worked with this library, and if you figured out an easy way to calculate the percentage of progress please help me out here.
Thanks in advance for the help.
I tried to get the size of the archive file using the available() method on the inputstream like below.
InputStream in = getResources().openRawResource(R.raw.my_archive);
int fileSize = in.available();
And during extraction process, I calculated progress like below:
int size;
int counter=0;
while ((size = in.read(buf)) != -1) {
out.write(buf,0,size);
counter++;
progress = (int) (counter*100*1024/(double)fileSize);
publishProgress(progress);
}
However, this doesn't result in the right progress for some reason. The progress goes upto 108% before its finished. I know I'm doing something wrong here, so please improve this answer with the right calculation.
Thanks

Categories

Resources