0

I just tested my devices on some older phones and get a java.lang.OutOfMemoryError. Could someone please help me fix this problem?

What im trying to do: Convert a very large string to an html file, the string consists of html text. This is my code:

    OutputStream outputStream = null;
    InputStream inputStream = null;
    try {

        inputStream = new ByteArrayInputStream(htmlContent.getBytes(Charset.forName("UTF-16")));

        outputStream = new FileOutputStream(new File(dir, appBook.getPath()));

        byte[] bufferData = new byte[512];

        int bytesRead = inputStream.read(bufferData);

        while (bytesRead != -1) {
            outputStream.write(bufferData, 0, bytesRead); //add the bufferData data to the "new file"
            bytesRead = inputStream.read(bufferData); // keep on reading and filling the dynamic byte araay until it returns -1
        }

Its specifically the Charset.forName("UTF-16")) that causes the error on these older devices. If I make the htmlContentString shorter by 2 no error occurs.

This makes me think that the arrays size is to big for the ram? So how should I approach this?

logcat

03-14 16:32:39.067    5604-5604/oskaro.synesthesia.oskar.leonad.synesthesiaconverter I/dalvikvm﹕ [ 03-14 16:32:39.067  5604: 5604 D/AndroidRuntime ]
    Shutting down VM
03-14 16:32:39.067    5604-5604/oskaro.synesthesia.oskar.leonad.synesthesiaconverter W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x40fde2a0)
03-14 16:32:39.077    5604-5604/oskaro.synesthesia.oskar.leonad.synesthesiaconverter E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.OutOfMemoryError
            at java.nio.charset.CharsetEncoderICU.getArray(CharsetEncoderICU.java:235)
            at java.nio.charset.CharsetEncoderICU.encodeLoop(CharsetEncoderICU.java:169)
            at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:415)
            at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:283)
            at java.nio.charset.Charset.encode(Charset.java:451)
            at java.lang.String.getBytes(String.java:870)
            at oskaro.synesthesia.oskar.leonad.synesthesiaconverter.HtmlAddDialog.createHtmlFile(HtmlAddDialog.java:120)
            at oskaro.synesthesia.oskar.leonad.synesthesiaconverter.HtmlAddDialog.access$700(HtmlAddDialog.java:39)
            at oskaro.synesthesia.oskar.leonad.synesthesiaconverter.HtmlAddDialog$4.onClick(HtmlAddDialog.java:209)
            at android.view.View.performClick(View.java:4232)
            at android.view.View$PerformClick.run(View.java:17298)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4921)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
            at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
            at dalvik.system.NativeStart.main(Native Method)
0

1 Answer 1

2

The string was using to much memory when getBytes for the old phones to handle. So I decided to substring the string into 4 strings, than just write each string in a loop to outputstream.

If anyone provides a better (shorter or cleaner or faster) code snippet to solve this than I will mark that one as the answers. Until than, my code will do!

The writing method:

    //divide the string by 4 and read it in chunks. Otherwise
    // getBytes(Charset.forName("UTF-16") can cause out.of.memory if string is too big.
    //Important, i have to call this outside the try{} otherwise it will only do 3 loops inside splitString()?????
    String[] bookPieces = splitString(htmlContent, htmlContent.lenth()/650000);

    OutputStream outputStream = null;
    InputStream inputStream = null;
    try {
        outputStream = new FileOutputStream(new File(dir, appBook.getPath()));
        for (String text : bookPieces) {
            byte[] theBytes = text.getBytes(Charset.forName("UTF-16"));
            inputStream = new ByteArrayInputStream(theBytes);
            byte[] bufferData = new byte[1024];
            int bytesRead = inputStream.read(bufferData);

            while (bytesRead != -1) {
                outputStream.write(bufferData, 0, bytesRead); //add the bufferData data to the "new file"
                bytesRead = inputStream.read(bufferData); // keep on reading and filling the dynamic byte araay until it returns -1
            }
            //need to GC the inputsteam myself!!!!
            inputStream = null;
        }

Helper method

private String[] splitString(String str, int elements) {
    String[] splitStrings = new String[elements];
    int currentLength = 0;
    double oneFourth = str.length() / elements;
    for (int x = 1; x <= splitStrings.length; x++) {

        //for the last text chunk add "remainders" which were rounded down when (int)
        if (x == splitStrings.length) {
            splitStrings[x-1] = str.substring(currentLength, str.length());
        } else {
            splitStrings[x-1] = str.substring(currentLength, ((int) oneFourth)*x);
        }
        currentLength += (int) oneFourth;
    }
    return splitStrings;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.