Intent putExtra方法的最大长度? (强制关闭)

时间:2012-09-19 14:18:20

标签: java android android-intent android-activity

我需要一些调试我的应用程序的帮助。首先:在模拟器和其他设备上,我的应用运行正常。在我的设备上,我关闭了一个力(没有强制关闭消息)。

如果更改了应用的活动,则会发生“崩溃”。

以下是MainActivity类的一些代码。它只是通过webview从网页上读取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()方法中,我只是将html代码传递给另一个读取,解析和显示内容的Activity类。

现在的问题是,此时应加载ReadDataActivity类,应用程序只需关闭并返回主屏幕,无需任何消息或用户对话框。

作为字符串传递给ReadDataActivity的html代码是否可能很大?我也尝试将html代码作为字符串添加到HashMap中,但问题是一样的。

我可以采取哪些措施来调试问题?也许我应该尝试创建一个Parcelable对象?

在模拟器中一切正常。

9 个答案:

答案 0 :(得分:49)

根据我的经验(前一段时间),您可以在Bundle封装在Intent内的数据中添加 1MB 数据。我认为,此限制在 Froyo GingerBread 之前有效。

但是,为了解决这个问题,我建议您将内容保存在临时文件中,并将临时文件的路径/ URI 传递给第二个活动。然后在第二个活动中,从文件中读出内容,执行所需的操作,最后删除该文件。

如果您愿意,您还可以为此任务合并 Shared_Preferences - 如果您认为处理文件很麻烦。

答案 1 :(得分:14)

我对使用Intent传输的最大数据量做了一些研究。并且似乎限制不到1MB或90KB,它更像是 500KB (在API 10,16,19和23上测试)。

我写了一篇关于这个主题的博客文章,你可以在这里找到它:https://www.neotechsoftware.com/blog/android-intent-size-limit

答案 2 :(得分:4)

Jelly Bean中Intent的大小限制仍然很低,略低于1MB(大约90K),因此即使您的应用程序仅针对最新的Android版本,您也应始终对数据长度保持谨慎

答案 3 :(得分:4)

1MB的固定大小不仅限于意图。作为Intent,内容提供商,Messenger,所有系统服务,如电话,振动器等,都使用Binder的IPC基础设施提供商。此外,活动生命周期回调也使用此基础结构。

1MB 是系统在特定时刻执行的所有活页夹交易的总体限制。

如果发送意图时发生了大量事务,即使额外数据不大,也可能会失败。
http://codetheory.in/an-overview-of-android-binder-framework/

答案 4 :(得分:2)

游戏稍晚,但我遇到了同样的问题。在我的案例中,将数据写入文件并没有真正有效,但我在寻找答案时遇到了这个问题:

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();

答案 5 :(得分:2)

我已经看到,通过写入和从文件中读取包含较少的性能。 Then I have seen this solution :。所以我正在使用这个解决方案:

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

答案 6 :(得分:1)

在活动之间传递大数据的另一种解决方案是使用静态字段。在您的情况下,将此行添加到ReadDataActivity类

public static String msg;

然后您可以在MainActivity类中使用静态字段msg,如下所示

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

最后开始你的活动而不需要额外的支付

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

答案 7 :(得分:1)

Binder事务缓冲区的固定大小有限 - 1Mb。 但问题是该进程正在进行的所有事务共享的缓冲区。

因此,每次都尽量保持意图的数据尽可能小。

答案 8 :(得分:1)

使用static String变量很好。如果用户需要返回&amp;在不同的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