Vla*_*vić 71 android android-7.0-nougat
我将Nexus 5X更新为Android N,现在当我在其上安装应用程序(调试或发布)时,我在每个具有附加功能的Bundle的屏幕转换上都会收到TransactionTooLargeException.该应用正在处理所有其他设备.PlayStore上的旧应用程序和大多数相同的代码正在使用Nexus 5X.有人有同样的问题吗?
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 592196 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3752)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: android.os.TransactionTooLargeException: data parcel size 592196 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3606)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3744)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Run Code Online (Sandbox Code Playgroud)
Bri*_*cho 26
每当你看到TransactionTooLargeException
一个Activity
正在停止的过程中发生时,这意味着它Activity
试图将其保存的状态发送Bundles
到系统操作系统,以便以后安全保存(在配置更改或进程死亡之后),但是一个或多个Bundles
发送的太大了.对于同时发生的所有此类交易,最大限制大约为1MB,即使没有Bundle
超过该限制,也可以达到该限制.
这里的主要罪魁祸首通常是在onSaveInstanceState
其中托管的Activity
任何内容中保存太多数据.通常,这会在保存像a这样特别大的东西时发生,但在发送大量较小数据(如对象列表)时也会发生这种情况.Android团队在很多场合都非常明确地表示只应保存少量与视图相关的数据.但是,开发人员经常保存网络数据页面,以便通过不必再次重新获取相同数据来使配置更改显得尽可能平滑.从Google I/O 2017开始,Android团队已经明确表示Android应用程序的首选架构可以节省网络数据Fragments
Activity
Bitmap
Parcelable
onSavedInstanceState
他们的新ViewModel
框架和Room
持久性库旨在帮助开发人员适应这种模式.如果您的问题是保存过多的数据onSaveInstanceState
,使用这些工具更新到这样的架构应该可以解决您的问题.
就个人而言,在更新到新模式之前,我想采用我现有的应用程序,并TransactionTooLargeException
在此期间解决问题.我写了一个快速库来做到这一点:https://github.com/livefront/bridge.它使用了相同的一般想法,即从内存中恢复配置更改中的状态,以及在进程死亡后从磁盘恢复状态,而不是将所有状态发送到操作系统onSaveInstanceState
,但需要对现有代码进行非常小的更改才能使用.任何符合这两个目标的策略应该可以帮助您避免异常,同时不会牺牲您保存状态的能力.
最后请注意:你在Nougat +上看到这个的唯一原因是,如果超过了绑定器事务限制,那么将保存状态发送到操作系统的过程将无声地失败,只有在Logcat中出现此错误:
!失败的粘合剂交易!
在Nougat,这种沉默的失败升级为严重的崩溃.值得赞扬的是,这是开发团队在Nougat的发行说明中记录的内容:
许多平台API现在已经开始检查通过Binder事务发送的大型有效负载,系统现在将TransactionTooLargeExceptions重新抛出为RuntimeExceptions,而不是静默记录或抑制它们.一个常见示例是在Activity.onSaveInstanceState()中存储过多数据,这会导致ActivityThread.StopInfo在您的应用针对Android 7.0时抛出RuntimeException.
Vla*_*vić 25
最后,我的问题是保存在SaveInstance上的事情,而不是发送到下一个活动的事情.我删除了无法控制对象大小的所有保存(网络响应),现在它正在工作.
更新:
为了保留大块数据,Google建议使用保留实例的Fragment来实现.想法是创建空片段而不包含所有必需字段的视图,否则将保存在Bundle中.添加setRetainInstance(true);
到Fragment的onCreate方法.然后将数据保存在Activity的onDestroy上的Fragment中并将它们加载到onCreate上.以下是活动的示例:
public class MyActivity extends Activity {
private DataFragment dataFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// create the fragment and data the first time
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}
// the data is available in dataFragment.getData()
...
}
@Override
public void onDestroy() {
super.onDestroy();
// store the data in the fragment
dataFragment.setData(collectMyLoadedData());
}
}
Run Code Online (Sandbox Code Playgroud)
片段的例子:
public class DataFragment extends Fragment {
// data object we want to retain
private MyDataObject data;
// this method is only called once for this fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
Run Code Online (Sandbox Code Playgroud)
更多关于它,你可以在这里阅读.
小智 18
TransactionTooLargeException一直困扰着我们大约4个月,我们终于解决了这个问题!
发生的事情是我们在ViewPager中使用FragmentStatePagerAdapter.用户可以翻阅并创建100多个片段(它是一个阅读应用程序).
虽然我们在destroyItem()中正确管理了片段,但是在FragmentStatePagerAdapter的Androids实现中有一个bug,它保留了对以下列表的引用:
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
Run Code Online (Sandbox Code Playgroud)
当Android的FragmentStatePagerAdapter尝试保存状态时,它将调用该函数
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
for (int i=0; i<mFragments.size(); i++) {
Fragment f = mFragments.get(i);
if (f != null && f.isAdded()) {
if (state == null) {
state = new Bundle();
}
String key = "f" + i;
mFragmentManager.putFragment(state, key, f);
}
}
return state;
}
Run Code Online (Sandbox Code Playgroud)
如您所见,即使您正确管理FragmentStatePagerAdapter子类中的片段,基类仍将为创建的每个片段存储Fragment.SavedState.当该数组被转储到parcelableArray并且操作系统不喜欢100多个项目时,就会发生TransactionTooLargeException.
因此,我们的修复是覆盖saveState()方法而不是为"状态"存储任何内容.
@Override
public Parcelable saveState() {
Bundle bundle = (Bundle) super.saveState();
bundle.putParcelableArray("states", null); // Never maintain any states from the base class, just null it out
return bundle;
}
Run Code Online (Sandbox Code Playgroud)
Raj*_*dav 15
受到了打击和审判,最后这解决了我的问题.将此添加到您的Activity
@Override
protected void onSaveInstanceState(Bundle oldInstanceState) {
super.onSaveInstanceState(oldInstanceState);
oldInstanceState.clear();
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*ung 11
我在Nougat设备上也遇到了这个问题.我的应用程序使用带有视图寻呼机的片段,其中包含4个片段.我将一些大的构造参数传递给造成问题的4个碎片.
我在TooLargeToolBundle
的帮助下追踪了导致这个问题的大小.
最后,我决定它使用putSerializable
它实现了一个POJO对象上Serializable
,而不是通过大量的原始String
使用putString
片段在初始化过程中.这减小Bundle
了一半,并没有抛出TransactionTooLargeException
.因此,请确保您没有传递巨大的参数Fragment
.
Google问题跟踪器中与PS相关的问题:https://issuetracker.google.com/issues/37103380
我面临类似的问题.问题和情况略有不同,我通过以下方式解决它.请检查方案和解决方案.
场景: 我在Google Nexus 6P设备(7操作系统)中遇到了一个奇怪的错误,因为我的应用程序将在工作4小时后崩溃.后来我发现它正在抛出类似的(android.os.TransactionTooLargeException :)异常.
解决方案: 日志没有指向应用程序中的任何特定类,后来我发现这是因为保留了后端堆栈的碎片.在我的例子中,借助自动屏幕移动动画,将4个片段重复添加到后栈.所以我重写onBackstackChanged()如下所述.
@Override
public void onBackStackChanged() {
try {
int count = mFragmentMngr.getBackStackEntryCount();
if (count > 0) {
if (count > 30) {
mFragmentMngr.popBackStack(1, FragmentManager.POP_BACK_STACK_INCLUSIVE);
count = mFragmentMngr.getBackStackEntryCount();
}
FragmentManager.BackStackEntry entry = mFragmentMngr.getBackStackEntryAt(count - 1);
mCurrentlyLoadedFragment = Integer.parseInt(entry.getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
如果堆栈超出限制,它将自动弹出到初始片段.我希望有人会帮助这个答案,因为异常和堆栈跟踪日志是相同的.因此,无论何时发生此问题,请检查后台堆栈计数,如果您正在使用碎片和后台堆栈.
小智 6
在我的情况下,我在一个片段中得到了这个异常,因为它的一个参数是一个非常大的字符串,我忘了删除它(我只在onViewCreated()方法中使用了那个大字符串).所以,为了解决这个问题,我简单地删除了这个论点.在您的情况下,您必须在调用onPause()之前清除或取消任何可疑字段.
活动代码
Fragment fragment = new Fragment();
Bundle args = new Bundle();
args.putString("extremely large string", data.getValue());
fragment.setArguments(args);
Run Code Online (Sandbox Code Playgroud)
片段代码
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
String largeString = arguments.get("extremely large string");
//Do Something with the large string
arguments.clear() //I forgot to execute this
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
39351 次 |
最近记录: |