首页 > 解决方案 > 超过 32767 个字符的 textview 会导致应用程序崩溃

问题描述

不显示的文本视图是大约 62000 个字符的帮助文本。我使用 api 26 和 api 27 在像素 2 上遇到用户故障。来自 Play 商店的错误消息是:

java.lang.RuntimeException: 
  at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2778)
  at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2856)
  at android.app.ActivityThread.-wrap11 (Unknown Source)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1589)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6494)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:438)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:807)

我已经能够使用 api 26 使用模拟像素 2 复制它,但使用 api 27 是可以的。我删除了所有无关代码以简化问题,并发现当我访问帮助屏幕的 help.java 时,文本视图比 32767 多一个字符(即 32768 个字符)会使应用程序崩溃。我已经包含了所有相关代码,但没有包含完整的字符串。我使用的字符串只有 CRLF、数字和字母字符。我无法弄清楚代码的问题。

日志是:

05-15 19:45:26.458 4340-4340/steve.diabetescarbcounter E/AndroidRuntime: FATAL EXCEPTION: main
    Process: steve.diabetescarbcounter, PID: 4340
    java.lang.RuntimeException: Unable to start activity ComponentInfo{steve.diabetescarbcounter/steve.diabetescarbcounter.Help}: android.view.InflateException: Binary XML file line #49: Binary XML file line #49: Error inflating class android.widget.TextView
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
     Caused by: android.view.InflateException: Binary XML file line #49: Binary XML file line #49: Error inflating class android.widget.TextView
     Caused by: android.view.InflateException: Binary XML file line #49: Error inflating class android.widget.TextView
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:334)
        at android.view.LayoutInflater.createView(LayoutInflater.java:647)
        at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58)
        at android.view.LayoutInflater.onCreateView(LayoutInflater.java:720)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:788)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
        at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:418)
        at android.app.Activity.setContentView(Activity.java:2654)
        at steve.diabetescarbcounter.Help.onCreate(Help.java:22)
        at android.app.Activity.performCreate(Activity.java:6975)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6541)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
     Caused by: java.lang.IndexOutOfBoundsException
        at android.content.res.StringBlock.nativeGetString(Native Method)
        at android.content.res.StringBlock.get(StringBlock.java:82)
        at android.content.res.AssetManager.getPooledStringForCookie(AssetManager.java:332)
        at android.content.res.TypedArray.loadStringValueAt(TypedArray.java:1272)
        at android.content.res.TypedArray.getText(TypedArray.java:175)
        at android.widget.TextView.<init>(TextView.java:1142)
        at android.widget.TextView.<init>(TextView.java:818)
        at android.widget.TextView.<init>(TextView.java:814)
        at java.lang.reflect.Constructor.newInstance0(Native Method) 
        at java.lang.reflect.Constructor.newInstance(Constructor.java:334) 
        at android.view.LayoutInflater.createView(LayoutInflater.java:647) 
        at com.android.internal.policy.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:58) 
        at android.view.LayoutInflater.onCreateView(LayoutInflater.java:720) 
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:788) 
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730) 
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:863) 
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) 
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) 
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) 
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:866) 
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:515) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:423) 
        at android.view.LayoutInflater.inflate(LayoutInflater.java:374) 
        at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:418) 
        at android.app.Activity.setContentView(Activity.java:2654) 
        at steve.diabetescarbcounter.Help.onCreate(Help.java:22) 
        at android.app.Activity.performCreate(Activity.java:6975) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
        at android.app.ActivityThread.-wrap11(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
        at android.os.Handler.dispatchMessage(Handler.java:105) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6541) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 
05-15 19:45:27.620 1407-1407/? E/hw-IPCThreadState: binder thread pool (1 threads) starved for 109 ms
05-15 19:45:27.667 1655-1669/system_process E/memtrack: Couldn't load memtrack module
05-15 19:45:27.899 1409-1409/? E/hw-IPCThreadState: binder thread pool (1 threads) starved for 118 ms
05-15 19:45:28.342 2442-2525/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded
05-15 19:45:29.338 2288-3690/com.google.android.gms.persistent E/ctxmgr: [ProducerStatusImpl]updateStateForNewContextData: inactive, contextName=7
05-15 19:45:29.371 1655-1769/system_process E/TaskPersister: File error accessing recents directory (directory doesn't exist?).
05-15 19:45:29.605 2288-2288/com.google.android.gms.persistent E/BeaconBle: Scan couldn't start for Places
05-15 19:45:32.302 1655-1673/system_process E/BatteryStatsService: modem info is invalid: ModemActivityInfo{ mTimestamp=0 mSleepTimeMs=0 mIdleTimeMs=0 mTxTimeMs[]=[0, 0, 0, 0, 0] mRxTimeMs=0 mEnergyUsed=0}
05-15 19:45:33.522 2442-2525/com.google.android.googlequicksearchbox:search E/ActivityThread: Failed to find provider info for com.google.android.apps.gsa.testing.ui.audio.recorded
05-15 19:45:36.785 1655-1669/system_process E/memtrack: Couldn't load memtrack module
05-15 19:45:42.787 1655-1769/system_process E/TaskPersister: File error accessing recents directory (directory doesn't exist?).

java代码是:

package steve.diabetescarbcounter;

import android.app.Activity;
import android.os.Bundle;

public class Help extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.help);
    }
}

xml是:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id = "@+id/helplinear1"
    style="@style/etool_linearlayout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <TableLayout
        android:id = "@+id/helptablelayout1"
        style="@style/etool_tablelayout"
        android:focusableInTouchMode="true"
        >
        <TableRow
            android:id = "@+id/helptablerow1"
            style="@style/etool_tablerow"
            >
       </TableRow>
    </TableLayout>
    <ScrollView
        android:id = "@+id/scroll_view_help"
        style="@style/etool_scrollview"
        >
        <LinearLayout
            android:id = "@+id/helplinear2"
            style="@style/etool_linearlayout"
            >
            <TextView
                android:id="@+id/helpText"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:text="@string/helpcrash"
                />
        </LinearLayout>
    </ScrollView>
</LinearLayout>

字符串 helpcrash 只是一个 32768 个字符的随机字符串,未显示:

<string name="helpcrash">then 32768 characters </string>

清单是:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="steve.diabetescarbcounter"
     xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <!-- If you change the version to 23 or higher then you will have to implement marshmallow permissions model -->
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/noTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".RecentActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/noTitleBar">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".SearchActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/noTitleBar">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".ItemActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/noTitleBar">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".Nutrients"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/noTitleBar"
            android:windowSoftInputMode="stateHidden">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".SettingsActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/noTitleBar"
            android:windowSoftInputMode="stateHidden">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".Help"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@style/noTitleBar"
            android:windowSoftInputMode="stateHidden">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>
     </application>
</manifest>

标签: androidtextview

解决方案


在没有修复的情况下尝试了 xml 中的 android:maxLength="60000" 之后,我尝试以编程方式在 Java 代码中添加大字符串,如下所示:

helpText = (TextView) findViewById(R.id.helpText);
String helpstring = getString(R.string.help1);  
helpText.setText(Html.fromHtml(helpstring));

当字符串资源 help1 超过 32767 个字符时,这再次失败。我的结论是从字符串资源中获取字符串被限制为小于或等于 32767 个字符。

我将字符串资源拆分为三个字符串,然后使用以下代码将它们连接起来:

helpText = (TextView) findViewById(R.id.helpText);
String helpstring = getString(R.string.help1) + getString(R.string.help2) + getString(R.string.help3);
helpText.setText(Html.fromHtml(helpstring));

这在每个字符串大约 20,000 个字符的情况下工作得很好。不幸的是 getString 从字符串中删除了所有 html 格式。我必须遍历所有字符串并将 \n 替换为 %lt;br> ,然后将 < 整体替换为 %lt; 从 getString 和此评论中“隐藏” html 格式。在 setText 中,我必须使用 Html.fromHtml() 恢复 html 格式。

总之,TextView 可以按预期处理大字符串,但是从字符串资源中获取字符串的过程比预期的要困难。这对我有用,因为字符串资源的大小基本上是固定的,我可以将它分成几部分。


推荐阅读