android - studio - Qué hacer en TransactionTooLargeException
java lang runtime exception android (25)
Tengo una pista de error de una aplicación TransactionTooLargeException. No reproducible y nunca antes. En los documentos dice
La transacción de Binder falló porque era demasiado grande.
Durante una llamada a procedimiento remoto, los argumentos y el valor de retorno de la llamada se transfieren como objetos Parcel almacenados en el búfer de transacción Binder. Si los argumentos o el valor de retorno son demasiado grandes para caber en el búfer de transacción, la llamada fallará y se lanzará TransactionTooLargeException.
...
Hay dos resultados posibles cuando una llamada a procedimiento remoto arroja TransactionTooLargeException. O bien el cliente no pudo enviar su solicitud al servicio (muy probablemente si los argumentos eran demasiado grandes para caber en el búfer de transacción), o el servicio no pudo enviar su respuesta de vuelta al cliente (muy probablemente si el valor de retorno era demasiado grande para caber en el búfer de transacción).
...
Así que, de acuerdo, en algún lugar que estoy pasando o recibiendo argumentos que exceden algún límite desconocido. ¿Pero donde?
La stacktrace no muestra nada de mis archivos:
java.lang.RuntimeException: Adding window failed
at android.view.ViewRootImpl.setView(ViewRootImpl.java:548)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
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:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
... 16 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.view.IWindowSession$Stub$Proxy.add(IWindowSession.java:569)
at android.view.ViewRootImpl.setView(ViewRootImpl.java:538)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:406)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:320)
at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:152)
at android.view.Window$LocalWindowManager.addView(Window.java:557)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2897)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$600(ActivityThread.java:139)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:4977)
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:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(Native Method)
Parece estar relacionado con las vistas, porque todas las líneas de Ventana / Vista? ¿Cómo se relaciona esto con la llamada a procedimiento remoto? ¿Cómo puedo buscar el motivo de este error?
En la aplicación, estoy utilizando solo servicios web, no estoy utilizando la clase de servicio, ¿los servicios web son las "llamadas a procedimientos remotos" o qué más podría ser ...?
Gracias por adelantado...
PD Tal vez es importante: Versión de Android: 4.0.3, Dispositivo: HTC One X
¡La TransactionTooLargeException ha estado afectando por aproximadamente 4 meses, y finalmente hemos resuelto el problema!
Lo que sucedía era que estamos usando un FragmentStatePagerAdapter en una ViewPager . El usuario pasaría la página y crearía más de 100 fragmentos (es una aplicación de lectura).
Aunque administramos los fragmentos correctamente en destroyItem() , en la implementación Androids de FragmentStatePagerAdapter hay un error, donde guardaba una referencia a la siguiente lista:
private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
Y cuando el FragmentStatePagerAdapter de Android intente guardar el estado, llamará a la función
@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;
}
Como puede ver, incluso si gestiona adecuadamente los fragmentos en la subclase FragmentStatePagerAdapter , la clase base aún almacenará un Fragment.SavedState para cada uno de los fragmentos creados. La TransactionTooLargeException ocurriría cuando esa matriz se parcelableArray un parcelableArray y al sistema operativo no le gustaría más de 100 elementos.
Por lo tanto, la solución para nosotros era anular el método saveState() y no almacenar nada para "states" .
@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;
}
Asegúrese de no poner datos de objetos de Intención de gran tamaño. En mi caso, estaba agregando tamaño String 500k y luego comencé otra actividad. Siempre falló con esta excepción. Evité compartir datos entre actividades mediante el uso de variables estáticas de actividades: no tienes que enviarlos a Intención y luego extraer de ellos.
Lo que tuve:
String html = new String();//some string of 500K data.
Intent intent = new Intent(MainActivity.this, PageWebView.class);
//this is workaround - I just set static variable and then access it from another activity.
MainActivity.htmlBody = timelineDb.getHTMLBodyForTweet(tweet);
//This line was present and it actually failed with the same exception you had.
//intent.putExtra("com.gladimdim.offtie.webview", html);
Como Intents, Proveedores de contenido, Messenger, todos los servicios del sistema como Telephone, Vibrator, etc. utilizan el proveedor de infraestructura IPC de Binder. Además, las devoluciones de llamada del ciclo de vida de la actividad también usan esta infraestructura.
1 MB es el límite general de todas las transacciones de enlace ejecutadas en el sistema en un momento determinado.
En caso de que haya muchas transacciones que suceden cuando se envía el intento, puede fallar aunque los datos adicionales no sean grandes. http://codetheory.in/an-overview-of-android-binder-framework/
Con tantos lugares donde puede suceder TransactionTooLargeException - aquí hay uno más nuevo en Android 8 - un bloqueo cuando alguien simplemente comienza a escribir en un EditText si el contenido es demasiado grande.
Está relacionado con AutoFillManager (nuevo en API 26) y el following código en StartSessionLocked() :
mSessionId = mService.startSession(mContext.getActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
mCallback != null, flags, mContext.getOpPackageName());
Si entiendo correctamente, esto llama al servicio de autocompletar, pasando el AutofillManagerClient dentro del encuadernador. Y cuando EditText tiene mucho contenido, parece causar el TTLE.
Algunas cosas pueden mitigarlo (o lo hicieron como estaba probando de todos modos): agregue android:importantForAutofill="noExcludeDescendants" en la declaración de diseño xml de EditText. O en el código:
EditText et = myView.findViewById(R.id.scriptEditTextView);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
et.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
}
Una segunda y terrible solución también podría ser anular los performClick() y onWindowFocusChanged() para detectar el error en una subclase de TextEdit. Pero no creo que eso sea sabio realmente ...
Cuando trato con WebView en mi aplicación, sucede. Creo que está relacionado con los recursos addView y UI. En mi aplicación agrego algún código en WebViewActivity como este a continuación, luego se ejecuta correctamente:
@Override
protected void onDestroy() {
if (mWebView != null) {
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.removeAllViews();
mWebView.destroy();
}
super.onDestroy();
}
En mi caso, recibo TransactionTooLargeException como un bloqueo secundario después de que la biblioteca nativa se estrelló con SIGSEGV. El bloqueo de la biblioteca nativa no se informa, por lo que solo recibo TransactionTooLargeException.
Encontré este problema y descubrí que cuando se intercambiaba una gran cantidad de datos entre un servicio y una aplicación (esto implica transferir muchas miniaturas). En realidad, el tamaño de los datos fue de alrededor de 500 kb, y el tamaño del búfer de transacción de IPC está establecido en 1024 KB. No estoy seguro de por qué excedió el buffer de transacción.
Esto también puede ocurrir cuando pasas muchos datos a través de extras
Cuando obtenga esta excepción en su aplicación, analice su código.
- ¿Estás intercambiando muchos datos entre tus servicios y tu aplicación?
- Al utilizar intenciones para compartir datos enormes, (por ejemplo, el usuario selecciona una gran cantidad de archivos de la galería compartir compartir en la prensa, los URI de los archivos seleccionados se transferirán usando intenciones)
- recibir archivos de mapa de bits del servicio
- esperando a que Android responda con enormes datos (por ejemplo, getInstalledApplications () cuando el usuario instaló muchas aplicaciones)
- utilizando applyBatch () con muchas operaciones pendientes
Cómo manejar cuando obtienes esta excepción
Si es posible, divida la operación grande en fragmentos pequeños, por ejemplo, en lugar de llamar a applyBatch () con 1000 operaciones, llámelo con 100 cada uno.
No intercambie datos enormes (> 1 MB) entre los servicios y la aplicación
No sé cómo hacer esto, pero, no consulte con Android, que puede devolver datos enormes :-)
Encontré la causa raíz de esto (obtuvimos la "ventana de adición fallida" y la fuga del descriptor de archivo como dice mvds).
Hay un bug en BitmapFactory.decodeFileDescriptor() de Android 4.4. Solo se produce cuando inPurgeable y inInputShareable of BitmapOptions se establecen en true . Esto causa muchos problemas en muchos lugares para interactuar con los archivos.
Tenga en cuenta que el método también se llama desde MediaStore.Images.Thumbnails.getThumbnail() .
Universal Image Loader se ve afectado por este problema. Picasso y Glide parece que no se ven afectados. https://github.com/nostra13/Android-Universal-Image-Loader/issues/1020
Entonces para nosotros fue que intentamos enviar un objeto demasiado grande a través de nuestra interfaz AIDL a un servicio remoto. El tamaño de la transacción no puede exceder 1MB. La solicitud se divide en trozos separados de 512 KB y se envía de uno en uno a través de la interfaz. Una solución brutal que conozco pero bueno, es Android :(
Es importante comprender que el búfer de transacción está limitado a 1 MB, independientemente de las capacidades o aplicaciones del dispositivo. Este búfer se utiliza con cada llamada API que realice y se comparte entre todas las transacciones que se está ejecutando actualmente.
Creo que también contiene algunos objetos específicos, como parcelas y similares (Parcel.obtain()) , por lo que es importante que siempre coincida cada obtain() con un recycle() .
Este error puede ocurrir fácilmente en llamadas de API que devuelven una gran cantidad de datos, aunque los datos devueltos sean de menos de 1 MB (si otras transacciones aún se están ejecutando).
Por ejemplo, la llamada PackageManager.getInstalledApplication() devuelve una lista de todas las aplicaciones instaladas. Agregar banderas específicas permite recuperar una gran cantidad de datos adicionales. Si lo hace, es probable que falle, por lo que se recomienda no recuperar ningún dato adicional y recuperarlos por aplicación.
Sin embargo, la llamada aún puede fallar, por lo que es importante rodearlo con una catch y poder volver a intentarlo si es necesario.
Por lo que yo sé, no existe una solución alternativa a tal problema, excepto volver a intentar y asegurarse de recuperar la menor cantidad de información posible.
Esta única línea de código en el método writeToParcel (Parcel dest, int flags) me ayudó a deshacerme de TransactionTooLargeException.
dest=Parcel.obtain();
Después de este código solo estoy escribiendo todos los datos en el objeto del paquete, es decir, dest.writeInt (), etc.
Esta excepción generalmente se lanza cuando la aplicación se envía a segundo plano.
Por lo tanto, he decidido utilizar el método Fragment de datos para eludir por completo el ciclo de vida onSavedInstanceStae . Mi solución también maneja estados de instancia complejos y libera memoria lo antes posible.
Primero, creé un Fargment simple para almacenar los datos:
package info.peakapps.peaksdk.logic;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
/**
* A neat trick to avoid TransactionTooLargeException while saving our instance state
*/
public class SavedInstanceFragment extends Fragment {
private static final String TAG = "SavedInstanceFragment";
private Bundle mInstanceBundle = null;
public SavedInstanceFragment() { // This will only be called once be cause of setRetainInstance()
super();
setRetainInstance( true );
}
public SavedInstanceFragment pushData( Bundle instanceState )
{
if ( this.mInstanceBundle == null ) {
this.mInstanceBundle = instanceState;
}
else
{
this.mInstanceBundle.putAll( instanceState );
}
return this;
}
public Bundle popData()
{
Bundle out = this.mInstanceBundle;
this.mInstanceBundle = null;
return out;
}
public static final SavedInstanceFragment getInstance(FragmentManager fragmentManager )
{
SavedInstanceFragment out = (SavedInstanceFragment) fragmentManager.findFragmentByTag( TAG );
if ( out == null )
{
out = new SavedInstanceFragment();
fragmentManager.beginTransaction().add( out, TAG ).commit();
}
return out;
}
}
Luego, en mi Actividad principal elude por completo el ciclo de la instancia guardada y difiero la respoinsibilty a mi Fragmento de datos. No es necesario usar esto en los Fragmentos, ya que su estado se agrega automáticamente al estado de la Actividad):
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
SavedInstanceFragment.getInstance( getFragmentManager() ).pushData( (Bundle) outState.clone() );
outState.clear(); // We don''t want a TransactionTooLargeException, so we handle things via the SavedInstanceFragment
}
Lo que queda es simplemente abrir la instancia guardada:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(SavedInstanceFragment.getInstance(getFragmentManager()).popData());
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState( SavedInstanceFragment.getInstance( getFragmentManager() ).popData() );
}
Todos los detalles: http://www.devsbedevin.com/avoiding-transactiontoolargeexception-on-android-nougat-and-up/
Esta no es una respuesta definitiva, pero puede arrojar algo de luz sobre las causas de una TransactionTooLargeException y ayudar a identificar el problema.
Aunque la mayoría de las respuestas se refieren a grandes cantidades de datos transferidos, veo que esta excepción se lanza accidentalmente después de un desplazamiento pesado y un acercamiento y abriendo varias veces un menú giratorio ActionBar. El bloqueo ocurre al tocar la barra de acciones. (esta es una aplicación de mapeo personalizada)
Los únicos datos que se transmiten parecen ser toques del "Despachador de entrada" a la aplicación. Creo que esto no puede suponer razonablemente cerca de 1 mb en el "Buffer de transacción".
Mi aplicación se ejecuta en un dispositivo cuádruple de 1,6 GHz y utiliza 3 subprocesos para heavylifting, manteniendo un núcleo libre para el subproceso de interfaz de usuario. Además, la aplicación usa android: largeHeap, tiene 10 mb de montón sin usar a la izquierda y tiene 100 mb de espacio restante para hacer crecer el montón. Entonces no diría que es un problema de recursos.
El bloqueo siempre está precedido inmediatamente por estas líneas:
W/InputDispatcher( 2271): channel ~ Consumer closed input channel or an error occurred. events=0x9
E/InputDispatcher( 2271): channel ~ Channel is unrecoverably broken and will be disposed!
E/JavaBinder(28182): !!! FAILED BINDER TRANSACTION !!!
Que no necesariamente se imprimen en ese orden, pero (según comprobé) ocurren en el mismo milisegundo.
Y la pila se traza a sí misma, para mayor claridad, es la misma que en la pregunta:
E/AndroidRuntime(28182): java.lang.RuntimeException: Adding window failed
..
E/AndroidRuntime(28182): Caused by: android.os.TransactionTooLargeException
Profundizando en el código fuente de Android uno encuentra estas líneas:
frameworks / base / core / jni / android_util_Binder.cpp:
case FAILED_TRANSACTION:
ALOGE("!!! FAILED BINDER TRANSACTION !!!");
// TransactionTooLargeException is a checked exception, only throw from certain methods.
// FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
// but it is not the only one. The Binder driver can return BR_FAILED_REPLY
// for other reasons also, such as if the transaction is malformed or
// refers to an FD that has been closed. We should change the driver
// to enable us to distinguish these cases in the future.
jniThrowException(env, canThrowRemoteException
? "android/os/TransactionTooLargeException"
: "java/lang/RuntimeException", NULL);
Para mí, parece que estoy golpeando esta característica no documentada, donde la transacción falla por otras razones que una transacción sea demasiado grande. Deberían haberlo llamado TransactionTooLargeOrAnotherReasonException .
En este momento no resolví el problema, pero si encuentro algo útil, actualizaré esta respuesta.
actualización: resultó que mi código se filtró algunos descriptores de archivos, cuyo número se maximiza en Linux (por lo general, 1024), y esto parece haber desencadenado la excepción. Entonces, fue un problema de recursos después de todo. Lo verifiqué abriendo /dev/zero 1024 veces, lo que dio lugar a todo tipo de excepciones raras en las acciones relacionadas con la interfaz de usuario, incluida la excepción anterior e incluso algunos SIGSEGV. Aparentemente, la falla al abrir un archivo / socket no es algo que se maneje / informe de manera muy limpia en todo Android.
Intenta utilizar EventBus o ContentProvider como solución.
Si está en el mismo proceso (normalmente todas sus actividades serían), intente utilizar EventBus , porque en el proceso el intercambio de datos NO necesita un buffer, por lo que no debe preocuparse de que sus datos sean demasiado grandes. (Puede utilizar la llamada a método para pasar datos de hecho, y EventBus esconder las cosas feas) Aquí está el detalle:
// one side
startActivity(intentNotTooLarge);
EventBus.getDefault().post(new FooEvent(theHugeData));
// the other side
@Subscribe public void handleData(FooEvent event) { /* get and handle data */ }
Si los dos lados de Intent no están en el mismo proceso, pruebe un poco ContentProvider .
Consulte TransactionTooLargeException
La transacción de Binder falló porque era demasiado grande.
Durante una llamada a procedimiento remoto, los argumentos y el valor de retorno de la llamada se transfieren como objetos Parcel almacenados en el búfer de transacción Binder. Si los argumentos o el valor de retorno son demasiado grandes para caber en el búfer de transacción, la llamada fallará y se lanzará TransactionTooLargeException.
Lo obtuve en mi adaptador syncadapter al tratar de insertar de forma masiva un gran ContentValues []. Decidí arreglarlo de la siguiente manera:
try {
count = provider.bulkInsert(uri, contentValueses);
} catch (TransactionTooLarge e) {
int half = contentValueses.length/2;
count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, 0, half));
count += provider.bulkInsert(uri, Arrays.copyOfRange(contentValueses, half, contentValueses.length));
}
No hay una causa específica de este problema. Para mí, en mi clase Fragmento estaba haciendo esto:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.snacks_layout, container); //<-- notice the absence of the false argument
return rootView;
}
en lugar de esto:
View rootView = inflater.inflate(R.layout.softs_layout, container, false);
Otra posible causa:
¡Tenía una actividad que comenzaba en onResume() ! Esto da como resultado una tonelada de transacciones y hace que el teléfono (Galaxy S2) se congele por completo (sin ANR ni nada) y luego al restablecimiento completo, que es una especie de gran error en sí mismo.
Sería interesante ver qué sucede en otros teléfonos con este código:
class MyActivity extends Activity
{
// ...
@Override
void onResume()
{
super.onResume()
startActivity(new Intent(this, MyActivity.class));
}
}
Para aquellos que amargamente se decepcionaron en la búsqueda de respuestas sobre por qué aparece TransactionTooLargeException, intente verificar lo que guarda en el estado de la instancia.
En compile / targetSdkVersion <= 23 tenemos solo una advertencia interna sobre el tamaño grande del estado guardado, pero nada se colgó:
E/ActivityThread: App sent too much data in instance state, so it was ignored
android.os.TransactionTooLargeException: data parcel size 713856 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
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:6044)
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)
Pero en compile / targetSdkVersion> = 24 tenemos caída real de RuntimeException en este caso:
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 713860 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3737)
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:6044)
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 713860 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3604)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3729)
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:6044)
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)
¿Qué hacer?
Guarde los datos en la base de datos local y conserve solo los identificadores en el estado de la instancia que puede usar para recuperar estos datos.
Para mí también era el FragmentStatePagerAdapter , sin embargo, la anulación de saveState() no funcionó. Así es como lo arreglé:
Cuando llame al constructor FragmentStatePagerAdapter , mantenga una lista separada de fragmentos dentro de la clase y agregue un método para eliminar los fragmentos:
class PagerAdapter extends FragmentStatePagerAdapter {
ArrayList<Fragment> items;
PagerAdapter(ArrayList<Fragment> frags) {
super(getFragmentManager()); //or getChildFragmentManager() or getSupportFragmentManager()
this.items = new ArrayList<>();
this.items.addAll(frags);
}
public void removeFragments() {
Iterator<Fragment> iter = items.iterator();
while (iter.hasNext()) {
Fragment item = iter.next();
getFragmentManager().beginTransaction().remove(item).commit();
iter.remove();
}
notifyDataSetChanged();
}
}
//...getItem() and etc methods...
}
Luego, en la Activity , guarde la posición de ViewPager y llame a un dapter.removeFragments() en el método onSaveInstanceState() anulado:
private int pagerPosition;
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//save other view state here
pagerPosition = mViewPager.getCurrentItem();
adapter.removeFragments();
}
Por último, en el método onResume() reemplazado, vuelva a crear una instancia del adaptador si no es null . (Si es null , la Activity se abrirá por primera vez o después de que Android haya eliminado la aplicación, en la que onCreate realizará la creación del adaptador).
@Override
public void onResume() {
super.onResume();
if (adapter != null) {
adapter = new PagerAdapter(frags);
mViewPager.setAdapter(adapter);
mViewPager.setCurrentItem(currentTabPosition);
}
}
Para mí, TransactionTooLargeException se produjo cuando intenté enviar una imagen de mapa de bits grande de una actividad a otra a través de un intento. Resolví este problema usando las variables globales de la aplicación .
Por ejemplo, si desea enviar una imagen grande de mapa de bits de una actividad A a una actividad B , entonces almacene esa imagen de mapa de bits en una variable global
((Global) this.getApplication()).setBitmap(bitmap);
luego comienza la actividad B y lee de la variable global
Bitmap bitmap = ((Global) this.getApplication()).getBitmap();
Recientemente también me he encontrado con un caso interesante mientras trabajaba con el proveedor de contactos de Android.
Necesitaba cargar fotos de contactos desde la base de datos de contactos internos y de acuerdo con la arquitectura del sistema, todos estos datos son entregados por consultas al Proveedor de Contactos.
Como funciona como una aplicación separada, todos los tipos de transferencia de datos se realizan utilizando el mecanismo Binder y, por lo tanto, el búfer Binder entra en juego aquí.
Mi principal error fue que no cerré el Cursor con los datos de blobs obtenidos del Proveedor de Contactos, por lo que la memoria asignada para el proveedor aumentó y esto infló el búfer de Binder hasta que recibí toneladas de !!!FAILED BINDER TRANSACTION!!! mensajes en mi salida LogCat.
Por lo tanto, la idea principal es que cuando trabaje con proveedores de contenido externos y obtenga Cursor de ellos, siempre ciérrelo cuando termine de trabajar con ellos.
Si necesita investigar qué paquete está causando su falla, debería considerar probar TooLargeTool .
(Encontré esto como un comentario de @Max Spencer en la respuesta aceptada y fue útil en mi caso).
Tuve el mismo problema al transferir (enviar difusión) un objeto de mapa de bits a un receptor de difusión.
intent.putExtra("image", bitmapImage);
Entonces, en lugar de enviarlos como mapa de bits. Convertí el mapa de bits en matriz de bytes. ¡¡¡Para mi sorpresa, funcionó!!! Me pregunto por qué Android no permite transferir datos enormes con Bitmap, pero permite el mismo a través de matriz de bytes.
intent.putExtra("imageInByteArray", convertBitmapToByteArray(bitmapImage));
En el receptor, convertí la matriz de bytes a bitmap y esto resolvió mi problema.
Una solución sería que la aplicación escriba ArrayList (o cualquier objeto que esté causando el problema) en el sistema de archivos, luego pase una referencia a ese archivo (por ejemplo, nombre de archivo / ruta) a través del Intent a IntentService y luego deje que IntentService recuperar el contenido del archivo y convertirlo a una ArrayList.
Cuando IntentService ha terminado con el archivo, debe eliminarlo o pasar la instrucción a la aplicación a través de una Transmisión local para eliminar el archivo que creó (devolviendo la misma referencia de archivo que se le suministró).
Para obtener más información, consulte mi respuesta a este problema relacionado .
Yo también obtuve esta excepción en un Samsung S3. Sospecho que hay 2 causas raíz
- tienes mapas de bits que cargan y ocupan demasiada memoria, usa reducción de tamaño
- Le faltan algunos elementos extraíbles de las carpetas dibujables-_dpi, Android los busca en dibujables y los redimensiona, haciendo que su setContentView salte repentinamente y use mucha memoria.
Use DDMS y mire su montón mientras juega su aplicación, que le dará alguna indicación sobre qué setcontentview está creando el problema.
Copié todos los dibujables en todas las carpetas para deshacerme del problema 2.
Informaré en unos días lo que encuentre.