Подтвердить что ты не робот

Максимальная длина метода putExtra Intent? (Закрыть)

Мне нужна помощь с отладкой моего приложения. Прежде всего: в эмуляторе и на некоторых других устройствах мое приложение работает нормально. На моем устройстве я получил принудительное закрытие (без сообщения принудительного закрытия).

"Сбой" происходит, если активность приложения изменяется.

Вот некоторый код класса MainActivity. Он просто читает контент HTML с веб-страницы через веб-просмотр. И нет, это невозможно сделать через HttpRequest потому что я не смог смоделировать почтовый запрос.

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<String, String> message = new HashMap<String, String>();*/
                    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");

}

Итак, в onConsoleMessage() я просто onConsoleMessage() HTML-код другому классу Activity, который читает, анализирует и отображает содержимое.

Проблема заключается в том, что в этот момент, когда класс ReadDataActivity должен быть загружен, приложение просто закроется и вернется на домашний экран без каких-либо сообщений или пользовательских диалогов.

Возможно ли, что HTML-код, который передается в виде строки в ReadDataActivity велик? Я также пытаюсь добавить HTML-код в виде строки в HashMap, но проблема та же.

Некоторые идеи, что я могу сделать, чтобы решить проблему? Может быть, я должен попытаться создать объект Parcelable?

В эмуляторе все работает нормально.

4b9b3361

Ответ 1

В соответствии с моим опытом (когда-то ранее) вы можете использовать 1 МБ данных в Bundle, заключенных внутри Intent. Я думаю, это ограничение было действительным до Froyo или GingerBread.

Однако, чтобы решить эту проблему, я предлагаю вам сохранить ваш контент в временном файле и передать путь /URI вашего временного файла во вторую активность. Затем во втором упражнении прочитайте содержимое из файла, выполните требуемую операцию и, наконец, удалите этот файл.

Если вы хотите, вы можете также включить Shared_Preferences для этой задачи - если вы считаете, что обработка файлов является громоздкой.

Ответ 2

Я провел некоторое исследование по максимальному объему данных, которые вы можете перенести, используя намерение. И кажется, что предел нигде не близок к 1 МБ или 90 КБ, он больше похож на 500 КБ (проверен на API 10, 16, 19 и 23).

Я написал сообщение в блоге об этой теме, вы можете найти его здесь: https://www.neotechsoftware.com/blog/android-intent-size-limit

Ответ 3

Предел размера Intent по-прежнему довольно низкий Jelly Bean, который несколько ниже 1 Мбайт (около 90 КБ), поэтому вы всегда должны быть осторожны в отношении длины своих данных, даже если ваше приложение предназначено только для последних версий Android.

Ответ 4

Фиксированный размер 1 МБ не ограничивается только намерениями. В качестве Intents, контент-провайдеры, Messenger, все системные сервисы, такие как телефон, вибратор и т.д., Используют провайдера инфраструктуры IPC от Binder. Более того, обратные вызовы жизненного цикла активности также используют эту инфраструктуру.

1 МБ - это общий лимит для всех операций связывания, выполняемых в системе в определенный момент.

Если при отправке намерения происходит много транзакций, он может потерпеть неудачу, даже если дополнительные данные невелики.
http://codetheory.in/an-overview-of-android-binder-framework/

Ответ 5

Немного поздно в игре, но я просто столкнулся с той же проблемой. Написание данных в файл на самом деле не имело смысла в моем случае, но я натолкнулся на это в поисках ответов:

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

Использование синглтона лучше для меня, так как нет необходимости в диске IO. Лучшая производительность, если данные не нуждаются в сохранении.

Вот пример реализации:

public class DataResult {

    private static DataResult instance;
    private List<SomeObject> data = null;

    protected DataResult() {

    }

    public static DataResult getInstance() { 
        if (instance == null) {
            instance = new DataResult();
        }
        return instance;
    }

    public List<SomeObject> getData() { return data; }
    public void setData(List<SomeObject> data) { this.data = data; }
}

Затем вы можете установить это с помощью одного действия:

DataResult.getInstance().setData(data);

И получить его в другом виде:

List<SomeObject> data = DataResult.getInstance().getData();

Ответ 6

Я видел, что запись и чтение из файла состоит из меньшей производительности. Затем я увидел это решение:. Поэтому я использую это решение:

public class ExtendedDataHolder {

    private static ExtendedDataHolder ourInstance = new ExtendedDataHolder();

    private final Map<String, Object> 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();
    }

}

Затем в MainActivity я назвал его следующим:

ExtendedDataHolder extras = ExtendedDataHolder.getInstance();
extras.putExtra("extra", new byte[1024 * 1024]);
extras.putExtra("other", "hello world");

startActivity(new Intent(MainActivity.this, DetailActivity.class));

и в DetailActivity

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

Ответ 7

Альтернативным решением для передачи больших данных между действиями является использование статического поля. В вашем случае добавьте эту строку в класс ReadDataActivity

public static String msg;

Затем вы можете использовать статическое поле msg в классе MainActivity следующим образом

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

И, наконец, начните свою деятельность без дополнительной установки

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

Ответ 8

Буфер транзакции Binder имеет ограниченный фиксированный размер - 1 Мб. Но проблема заключается в том, что буфер, разделяемый всеми транзакциями, выполняется для процесса.

Поэтому старайтесь всегда сохранять свои данные о намерениях как можно меньше.

Ответ 9

Использование переменной static String является хорошим. Если пользователю необходимо переходить между различными фрагментами HTML, вы также можете использовать LruCache следующим образом:

    static LruCache<String, String> 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<String, String>(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);

Затем на стороне ReadDataActivity

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

Эта идея пришла из здесь.