1

I am trying to read in a large text file (~2.5 MB) into my Android application, using the following code:

private static String readFile(String path) throws IOException {
  FileInputStream stream = new FileInputStream(new File(path));
  try {
      FileChannel fc = stream.getChannel();
      MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
      /* Instead of using default, pass in a decoder. */
      return Charset.defaultCharset().decode(bb).toString();
  }
  finally {
    stream.close();
  }
}

I read here that this is the most effective way to read a file in java, but my app crashes with a force close, I believe because of an out of memory problem, as I have this code wrapped around a try-catch block.

How can I read this in and not make the app crash? I have tried several things, all result in the same, but only for large files. I cannot split the file up, that will not be acceptable in the final application.


UPDATE:

Here is the section where I actually read the file:

try                 
{
    String str = readFile(filePath);
    et.setText(str);
    et.setSelection(str.length());
}
catch (Exception ex)
{
    et.setText("There was an error reading the file: " + filePath + "\nDetails: " + ex);
}

Where et is an AutoCompleteTextView


UPDATE 2:

I have run adb and found the following:

04-11 15:26:16.805 20646 20658 W ActivityManager: Activity pause timeout for HistoryRecord{45b37620 com.ultimatecomputerservicesinc.androidhelloworld/.HelloWorld}
04-11 15:26:17.032 20727 20727 D dalvikvm: GC_EXTERNAL_ALLOC freed 1202 objects / 51792 bytes in 66ms
-- snip --
04-11 15:26:20.868 20727 20727 D dalvikvm: GC_EXTERNAL_ALLOC freed 639 objects / 25048 bytes in 38ms
04-11 15:26:20.961 25842 25842 I Process : Sending signal. PID: 25842 SIG: 9
04-11 15:26:21.102 20727 20727 D dalvikvm: GC_EXTERNAL_ALLOC freed 626 objects / 24328 bytes in 93ms
04-11 15:26:21.141 20646 20650 I ActivityManager: Process com.ultimatecomputerservicesinc.androidhelloworld (pid 25842) has died.

What does signal 9 mean?


UPDATE 3

My suspicions are correct, I ran out of memory! How can I increase the JVM size on android?

04-12 20:41:48.905  6610  6610 E AndroidRuntime: FATAL EXCEPTION: main
04-12 20:41:48.905  6610  6610 E AndroidRuntime: java.lang.OutOfMemoryError
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.text.PackedIntVector.growBuffer(PackedIntVector.java:257)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.text.PackedIntVector.insertAt(PackedIntVector.java:187)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.text.DynamicLayout.reflow(DynamicLayout.java:336)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.text.DynamicLayout.<init>(DynamicLayout.java:150)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.widget.TextView.makeNewLayout(TextView.java:4987)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.widget.TextView.checkForRelayout(TextView.java:5484)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.widget.TextView.setText(TextView.java:2776)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.widget.TextView.setText(TextView.java:2644)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.widget.EditText.setText(EditText.java:75)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.widget.TextView.setText(TextView.java:2619)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at com.ultimatecomputerservicesinc.androidhelloworld.HelloWorld$1$1.run(HelloWorld.java:183)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.os.Handler.handleCallback(Handler.java:587)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:92)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:143)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:4701)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at java.lang.reflect.Method.invokeNative(Native Method)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Method.java:521)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
04-12 20:41:48.905  6610  6610 E AndroidRuntime:    at dalvik.system.NativeStart.main(Native Method)
Community
  • 1
  • 1
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • I believe signal 9 is just SIGKILL. Is the process being force closed before the exception is caught? – Steve Blackwell Apr 11 '11 at 20:04
  • I can't figure out! All I know is that it suddenly crashes, but only with a large file... – Richard J. Ross III Apr 11 '11 at 20:19
  • I would say that the exc. is logged above this logcat section (if "catch (Exception ex)" didn't swallow it). Can you please reproduce your error while logcat is running. There should be an exception logged and a stack trace. – rocky3000 Apr 11 '11 at 20:25
  • Did you solve your problem? What kind of data are you trying to read into RAM and what are you going to do with it? – rocky3000 Apr 14 '11 at 16:26
  • @rocky I gave up on the app, I will be sticking to iOS from now on, I cannot deal with a device that has 512 MB of ram and only being able to use 24 MB's of it. – Richard J. Ross III Apr 15 '11 at 15:18

2 Answers2

0

Your app doesn't actually catch any exceptions, it just cleans up resources if it does crash.

Add catch(Exception e ){} to the try/finally to catch the exceptions.

I have an app and I used to load in in 1MB files which wasn't a problem (though a DOM parser was)

Kurru
  • 14,180
  • 18
  • 64
  • 84
  • Yes, It does, outside this portion of the file, I know what I am doing. – Richard J. Ross III Apr 11 '11 at 18:20
  • @Richard J. Ross IlL: Why don't you look at logcat to see what the crash information is? Post it to check the problem is an OutOfMemoryError. Are you running it on device or emulator? – Kurru Apr 11 '11 at 18:25
  • @Kurru I am running on the device. Where can I get the logcat files? – Richard J. Ross III Apr 11 '11 at 18:27
  • @Richard J. Ross Ill: LogCat is a view in eclipse for Android messages. Whenever an app force closes it'll send the crash data there. Additionally, you can write information to LogCat using `android.util.Log` class. Open the DDMS perspective and it should be contained there by default – Kurru Apr 11 '11 at 18:31
  • Maybe I am getting you confused. I am not deploying to a device in a normal fashion, e.g. not hooking directly into eclipse. I am using the built APK to deploy to the device, and I cannot deploy any other way at this time. The device, however, is rooted, if that makes any difference... – Richard J. Ross III Apr 11 '11 at 18:35
  • Why not deploy it to your phone using the usb cable since your still in dev for testing it? – Kurru Apr 11 '11 at 18:47
  • http://stackoverflow.com/questions/601503/how-do-i-obtain-crash-data-from-my-android-application This should be useful as well – Kurru Apr 11 '11 at 18:49
  • Then open a terminal on your development machine and type "adb logcat" and perhaps pipe it into a capture file or a pager or tee it to both. Actually I think eclipse can capture logcat messages from apps it didn't install if you have the filtering set appropriately. Or just run ddms, which is what eclipse is doing anyway. – Chris Stratton Apr 11 '11 at 18:50
  • @chris "command not found", using mac osx 10.6.7, also not existent on the device itself, using ssh.. – Richard J. Ross III Apr 11 '11 at 18:57
  • @Richard J. Ross III You have internet permissions enabled? – Kurru Apr 11 '11 at 19:27
  • Uhm, I don't think so, but When I install the APK, that wasn't an option... Anyhow, I ran adb, and please check my updated question. – Richard J. Ross III Apr 11 '11 at 19:29
  • @Richard J. Ross III Internet permissions are defined in the manifest file http://developer.android.com/guide/topics/manifest/manifest-intro.html – Kurru Apr 11 '11 at 19:35
  • I got that, it still isn't uploading :( – Richard J. Ross III Apr 11 '11 at 19:39
  • logcat most definitely exists on a normal android device, but you might not have the right path in your shells to find it - and that goes for both adb client on your host machine's shell as well as the logcat binary on your device's shell. – Chris Stratton Apr 11 '11 at 20:11
  • If you want your app to use the SD Card you can't have it mounted as a virtual device to your computer. – Kurru Apr 11 '11 at 21:43
0

Please do print the exception details in the log and post the results. Do something like this:

catch( Exception err) {

    Log.e("There was an error reading the file", err);
}

This should give you some more meaningful message explaining what happened and also a trace of the methods that were being executed.

Then, we might help you further.

I've had out of memory exceptions when I parsed 2.5 MB files with a DOM parser... but I don't think you do it so this could be another problem. Anyway, I solved my problem by splitting the data into several files and parsing them one at a time. ~1MB was a "safe" size for the files.

Pedro Loureiro
  • 11,436
  • 2
  • 31
  • 37
  • Where are the log files stored? – Richard J. Ross III Apr 11 '11 at 18:32
  • you should use an android tool: logcat. To run it, fire up a console, go to your android SDK instalation folder, enter the "tools" folder and execute "adb logcat". You can use DDMS if you prefer to have a GUI (it's in the same folder). I preferlogcat. Also, if you are using eclipse, DDMS is integrated into it. You should have that on a Debug view or something. Link: http://developer.android.com/guide/developing/tools/logcat.html http://developer.android.com/guide/developing/debugging/ddms.html – Pedro Loureiro Apr 11 '11 at 18:37
  • Connect your device via USB with a pc which has Android SDK installed. Then you can use a SDK tool named "adb" (in folder platform-tools) to get the log. Like that: adb -d logcat. I don't know if you have to turn on debug mode on your phone before. – rocky3000 Apr 11 '11 at 18:43
  • Link for debugging outside of eclipse: http://developer.android.com/guide/developing/debugging/debugging-projects-cmdline.html – Pedro Loureiro Apr 11 '11 at 18:44
  • Then plug your phone to a MAC which has an Android SDK installed on it and use adb logcat. :) – rocky3000 Apr 11 '11 at 18:59
  • There is no exc. logged in your log. So run your app again, with logcat running at the same time. Then make your app crash and shortly after this there should be an exception logged together with its stack trace. This may be of interest. BTW: try to be specific in your cache blocks and do not use "catch (Exception ex)" to cache **all** exceptions. – rocky3000 Apr 11 '11 at 19:44
  • @rocky: I cannot read from the SD card while the device is plugged in! And when I try to read from the device itself, it gives me a FileIOException. – Richard J. Ross III Apr 11 '11 at 20:20
  • @Richard J. Ross III so i have no problems with reading from sd card while plugged in. Have you debug mode turned on on your device? – rocky3000 Apr 11 '11 at 20:41
  • @Rocky3000 Programs still report crash info and Log messages through logcat when debugmode is off – Kurru Apr 11 '11 at 21:42
  • [I'm sorry, I lost the track of this question] You can consider changing your parser to a different one. Pull parser should be less greedy than a DOM parser for example. Sax could be a good choice http://developer.android.com/reference/javax/xml/parsers/SAXParser.html. I'm not sure that your problem happens while parsing the file though. – Pedro Loureiro Apr 24 '11 at 19:17