web-dev-qa-db-ja.com

Intent putExtraメソッドの最大長は? (強制終了)

アプリケーションのデバッグに助けが必要です。まず第一に:エミュレーターや他のいくつかのデバイスでは、アプリは正常に動作しています。デバイスで、強制終了しました(強制終了メッセージなし)。

「クラッシュ」は、アプリのアクティビティが変更された場合に発生します。

MainActivityクラスのコードを次に示します。 WebViewを介してWebページから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()メソッドでは、コンテンツを読み取り、解析、表示する別のActivityクラスにhtmlコードを渡すだけです。

問題は、この時点でReadDataActivityクラスをロードするときに、アプリケーションを閉じて、メッセージやユーザーダイアログなしでホーム画面に戻ることです。

ReadDataActivityに文字列として渡されるHTMLコードが大きすぎる可能性はありますか? HashMapにHTMLコードを文字列として追加しようとしましたが、問題は同じです。

問題をデバッグするために私ができることはいくつかありますか? Parcelableオブジェクトを作成しようとする必要がありますか?

エミュレーターでは、すべてが正常に機能しています。

27
sk2212

私の経験によると(しばらく前)、Bundle内にカプセル化されたIntent1MBのデータを入れることができます。この制限はFroyoまたはGingerbreadまで有効だったと思います。

ただし、この問題を解決するには、コンテンツを一時ファイルに保存し、一時ファイルのpath/URIを渡すことをお勧めします2番目のアクティビティ。次に、2番目のアクティビティで、ファイルから内容を読み取り、目的の操作を実行して、最後にそのファイルを削除します。

必要に応じて、組み込むこともできます Shared_Preferences このタスクの場合-ファイルの処理が面倒だと思われる場合。

50
waqaslam

Intentを使用して転送できるデータの最大量について調査しました。そして、制限は1MBや90KBの近くにはないようで、500KB(API 10、16、19、23でテスト済み)に似ています。

このトピックに関するブログ記事を書きました。ここで見つけることができます: https://www.neotechsoftware.com/blog/Android-intent-size-limit

14
Rolf ツ

Intentのサイズ制限は Jelly bean でまだかなり低く、1MB(約90K)よりもやや低いため、アプリケーションが最新の= Androidバージョン。

4
NullNoname

1MBの固定サイズは、インテントに限定されません。インテント、コンテンツプロバイダー、メッセンジャー、電話、バイブレーターなどのすべてのシステムサービスとして、IPC Binderのインフラストラクチャプロバイダーを使用します。さらに、アクティビティライフサイクルコールバックもこのインフラストラクチャを使用します。

1MBは、特定の瞬間にシステムで実行されるすべてのバインダートランザクションの全体的な制限です。

インテントの送信時に多くのトランザクションが発生する場合、追加データが大きくなくても失敗する可能性があります。
http://codetheory.in/an-overview-of-Android-binder-framework/

4
Shinoo Goyal

ゲームに少し遅れましたが、同じ問題に出くわしました。私の場合、データをファイルに書き込むことは実際にはパフォーマンス的に意味がありませんでしたが、答えを探すときにこれに遭遇しました:

http://developer.Android.com/guide/faq/framework.html#

ディスクI/Oは必要ないので、シングルトンを使用する方が適しています。データを永続化する必要がない場合のパフォーマンスの向上。

以下に実装例を示します。

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; }
}

次に、これを使用して1つのアクティビティで設定できます。

DataResult.getInstance().setData(data);

そして、次のような他のアクティビティで取得します。

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

私は、ファイルの読み書きがパフォーマンスの低下につながることを見てきました。 その後、私はこの解決策を見ました: 。だから私はこのソリューションを使用しています:

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");
}
2

の用法 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);

このアイデアは here から生まれました。

1
rockhammer

バインダトランザクションバッファの制限サイズは1Mbです。しかし問題は、プロセスですべてのトランザクションで共有されるバッファーが進行中であることです。

そのため、毎回インテントのデータをできるだけ小さくするようにしてください。

1
Anatoliy Shuba

アクティビティ間で大きなデータを渡すための代替ソリューションは、静的フィールドを使用することです。あなたの場合、この行をReadDataActivityクラスに追加してください

public static String msg;

次に、MainActivityクラス内の静的フィールドmsgを次のように使用できます。

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

そして最後に余分なプットなしであなたの活動を開始します

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