Question

My app reads in large amounts of data from text files assets and displays them on-screen in a TextView. (The largest is ~450k.) I read the file in, line-by-line into a SpannableStringBuffer (since there is some metadata I remove, such as section names). This approach has worked without complaints in the two years that I've had the app on the market (over 7k active device installs), so I know that the code is reasonably correct.

However, I got a recent report from a user on a LG Lucid (LGE VS840 4G, Android 2.3.6) that the text is truncated. From log entries, my app only got 9,999 characters in the buffer. Is this a known issue with a SpannableStringBuffer? Are there other recommended ways to build a large Spannable buffer? Any suggested workarounds?

Other than keeping a separate expected length that I update each time I append to the SpannableStringBuilder, I don't even have a good way to detect the error, since the append interface returns the object, not an error!

My code that reads in the data is:

    currentOffset = 0;
    try {
        InputStream is = getAssets().open(filename);
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        ssb.clear();
        jumpOffsets.clear();
        ArrayList<String> sectionNamesList = new ArrayList<String>();
        sectionOffsets.clear();
        int offset = 0;
        while (br.ready()) {
            String s = br.readLine();
            if (s.length() == 0) {
                ssb.append("\n");
                ++offset;
            } else if (s.charAt(0) == '\013') {
                jumpOffsets.add(offset);
                String name = s.substring(1);
                if (name.length() > 0) {
                    sectionNamesList.add(name);
                    sectionOffsets.add(offset);
                    if (showSectionNames) {
                        ssb.append(name);
                        ssb.append("\n");
                        offset += name.length() + 1;
                    }
                }
            } else {
                if (!showNikud) {
                    // Remove nikud based on Unicode character ranges
                    // Does not replace combined characters (\ufb20-\ufb4f)
                    // See
                    // http://en.wikipedia.org/wiki/Unicode_and_HTML_for_the_Hebrew_alphabet
                    s = s. replaceAll("[\u05b0-\u05c7]", "");
                }
                if (!showMeteg) {
                    // Remove meteg based on Unicode character ranges
                    // Does not replace combined characters (\ufb20-\ufb4f)
                    // See
                    // http://en.wikipedia.org/wiki/Unicode_and_HTML_for_the_Hebrew_alphabet
                    s = s.replaceAll("\u05bd", "");
                }
                ssb.append(s);
                ssb.append("\n");
                offset += s.length() + 1;
            }
        }

        sectionNames = sectionNamesList.toArray(new String[0]);

        currentFilename = filename;

        Log.v(TAG, "ssb.length()=" + ssb.length() +
                 ", daavenText.getText().length()=" +
                daavenText.getText().length() +
                ", showNikud=" + showNikud +
                ", showMeteg=" + showMeteg +
                ", showSectionNames=" + showSectionNames +
                ", currentFilename=" + currentFilename
                );

After looking over the interface, I plan to replace the showNikud and showMeteg cases with InputFilters.

Was it helpful?

Solution

Is this a known issue with a SpannableStringBuffer?

I see nothing in the source code to suggest a hard limit on the size of a SpannableStringBuffer. Given your experiences, my guess is that this is a problem particular to that device, due to a stupid decision by an engineer at the device manufacturer.

Any suggested workarounds?

If you are distributing through the Google Play Store, block this device in your console.

Or, don't use one massive TextView, but instead use several smaller TextView widgets in a ListView (so they can be recycled), perhaps one per paragraph. This should have the added benefit of reducing your memory footprint.

Or, generate HTML and display the content in a WebView.

OTHER TIPS

After writing (and having the user run) a test app, it appears that his device has this arbitrary limit for SpannableStringBuilder, but not StringBuilder or StringBuffer. I tested a quick change to read into a StringBuilder and then create a SpannableString from the result. Unfortunately, that means that I can't create the spans until it is fully read in.

I have to consider using multiple TextView objects in a ListView, as well as using Html.FromHtml to see if that works better for my app's long term plans.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top