Longitud máxima del método de intención PutExtra? (Fuerza cerca)

Necesito ayuda para depurar mi aplicación. Antes que nada: en el emulador y en algunos otros dispositivos, mi aplicación funciona bien. En mi dispositivo obtuve una fuerza cercana (sin un mensaje de cierre de fuerza).

El “locking” ocurre si se cambia la Actividad de la aplicación.

Aquí hay un código de la clase MainActivity . Simplemente lee el contenido html de una página web a través de la vista web. Y no, NO es posible hacer esto a través de HttpRequest porque no pude simular la solicitud de publicación.

 public class MainActivity extends Activity { public final static String EXTRA_HTML = "com.example.com.test.HTML"; private WebView mWebView; private ProgressDialog mDialog; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R.id.webView1); CookieSyncManager.createInstance(this); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.removeAllCookie(); mWebView.setBackgroundColor(0); mWebView.setWebChromeClient(new WebChromeClient() { public boolean onConsoleMessage(ConsoleMessage cmsg) { if (cmsg.message().startsWith("MAGIC")) { mDialog.cancel(); /*HashMap message = new HashMap();*/ String msg = cmsg.message().substring(5); Intent intent = new Intent(MainActivity.this, ReadDataActivity.class); /*message.put("message", msg);*/ /*intent.putExtra(EXTRA_HTML, message);*/ intent.putExtra(EXTRA_HTML, msg); startActivity(intent); } return false; } }); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setPluginState(PluginState.OFF); mWebView.getSettings().setLoadsImagesAutomatically(false); mWebView.getSettings().setBlockNetworkImage(true); mWebView.getSettings().setAppCacheEnabled(true); mWebView.getSettings().setSavePassword(true); mWebView.getSettings() .setCacheMode(WebSettings.LOAD_NORMAL); mWebView.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String address) { if (address.indexOf("mySession") != -1) { view.loadUrl("javascript:console.log('MAGIC'+document.getElementsByTagName('html')[0].innerHTML);"); } }); mWebView.loadUrl("http://www.myurl.de"); } 

Entonces, en el método onConsoleMessage() simplemente paso el código html a otra clase Activity que lee, analiza y muestra el contenido.

El problema ahora es que en este punto cuando se debe cargar la clase ReadDataActivity , la aplicación se cierra y vuelve a la pantalla de inicio sin ningún mensaje o diálogo de usuario.

¿Es posible que el código html que se pasa como una cadena a ReadDataActivity sea ​​grande? También trato de agregar el código html como una cadena en un HashMap pero el problema es el mismo.

Algunas ideas, ¿qué puedo hacer para solucionar el problema? Tal vez debería intentar crear un objeto Parcelable ?

En el emulador todo funciona bien.

Saludos, Sandro

Según mi experiencia (hace algún tiempo), puedes poner hasta 1MB de datos en un Bundle encapsulado dentro de Intent . Creo que esta restricción fue válida hasta Froyo o GingerBread .

Sin embargo, para superar este problema, le sugiero que guarde su contenido en un archivo temporal y pase la ruta / URI de su archivo temporal a su segunda actividad. Luego, en su segunda actividad, lea los contenidos del archivo, realice su operación deseada y finalmente elimine ese archivo.

Si lo desea, también puede incorporar Shared_Preferences para esta tarea, si cree que manejar archivos es engorroso.

Investigué un poco sobre la cantidad máxima de datos que puede transferir usando un Intento. Y parece que el límite no está cerca de 1MB o 90KB, es más como 500KB (probado en API 10, 16, 19 y 23).

Escribí una publicación de blog sobre este tema, puedes encontrarla aquí: https://www.neotechsoftware.com/blog/android-intent-size-limit

El límite de tamaño de Intent es aún bastante bajo en Jelly Bean , que es algo inferior a 1MB (alrededor de 90K), por lo que siempre debe tener cuidado con la longitud de los datos, incluso si su aplicación solo apunta a las últimas versiones de Android.

El tamaño fijo de 1MB no solo se limita a los bashs. Como Intents, Content Providers, 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 bash, puede fallar aunque los datos adicionales no sean grandes. http://codetheory.in/an-overview-of-android-binder-framework/

Un poco tarde para el juego, pero me encontré con el mismo problema. En mi caso, redactar los datos en un archivo no tenía sentido en términos de rendimiento, pero me encontré con esto en mi búsqueda de respuestas:

http://developer.android.com/guide/faq/framework.html#3

Usar un singleton es mejor para mí ya que no hay necesidad de disco IO. Mejor rendimiento si los datos no necesitan persistir.

Aquí hay una implementación de ejemplo:

 public class DataResult { private static DataResult instance; private List data = null; protected DataResult() { } public static DataResult getInstance() { if (instance == null) { instance = new DataResult(); } return instance; } public List getData() { return data; } public void setData(List data) { this.data = data; } } 

Luego puedes configurar esto en una actividad:

 DataResult.getInstance().setData(data); 

Y consíguelo en la otra actividad como esta:

 List data = DataResult.getInstance().getData(); 

Una solución alternativa para pasar datos grandes entre actividades es usar un campo estático. En su caso, agregue esta línea a la clase ReadDataActivity

 public static String msg; 

Luego puede usar el mensaje de campo estático dentro de la clase MainActivity de la siguiente manera

 ReadDataActivity.msg = cmsg.message().substring(5); 

Y finalmente comienza tu actividad sin poner más

 Intent intent = new Intent(MainActivity.this, ReadDataActivity.class); startActivity(intent); 

El búfer de transacción de Binder tiene un tamaño fijo limitado: 1Mb. Pero el problema es ese buffer compartido por todas las transacciones en progreso para el proceso.

Intente mantener los datos de su intención lo más pequeños posible cada vez.

Lo he visto escribiendo y leyendo desde un archivo consiste en menos rendimiento. Entonces he visto esta solución: Entonces estoy usando esta solución:

 public class ExtendedDataHolder { private static ExtendedDataHolder ourInstance = new ExtendedDataHolder(); private final Map extras = new HashMap<>(); private ExtendedDataHolder() { } public static ExtendedDataHolder getInstance() { return ourInstance; } public void putExtra(String name, Object object) { extras.put(name, object); } public Object getExtra(String name) { return extras.get(name); } public boolean hasExtra(String name) { return extras.containsKey(name); } public void clear() { extras.clear(); } } 

Luego en MainActivity lo he llamado así:

 ExtendedDataHolder extras = ExtendedDataHolder.getInstance(); extras.putExtra("extra", new byte[1024 * 1024]); extras.putExtra("other", "hello world"); startActivity(new Intent(MainActivity.this, DetailActivity.class)); 

y en DetailActivity

 ExtendedDataHolder extras = ExtendedDataHolder.getInstance(); if (extras.hasExtra("other")) { String other = (String) extras.getExtra("other"); } 

El uso de static String variable de static String es buena. Si existe la necesidad de que el usuario vaya y vuelva entre diferentes partes de HTML, también puede usar LruCache esta manera:

  static LruCache mMemoryCache; final int kiloByte = 1024; . . final int maxMemoryKB = (int) (Runtime.getRuntime().maxMemory() / kiloByte); // then choose how much you want to allocate for cache final int cacheSizeKB = maxMemoryKB / 8; . . mMemoryCache = new LruCache(cacheSizeKB) { //@Override protected int sizeOf(String key, String value) { try { byte[] bytesUtf8 = value.getBytes("UTF-8"); return bytesUtf8.length / kiloByte; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return -1; } }; . . String cacheKey = generateUniqueString(key); if (mMemoryCache.get(key) == null) { mMemoryCache.put(cacheKey, yourContent); } Intent intent = new Intent(getApplicationContext(), ReadDataActivity.class); intent.putExtra(EXTRA_HTML, cacheKey); startActivity(intent); 

Luego, en el lado de ReadDataActivity

 Intent intent = getIntent(); String cacheKey = intent.getStringExtra(EXTRA_HTML); String contentString = MainActivity.mMemoryCache.get(cacheKey); doSomethingWith(contentString); 

Esta idea vino de aquí .