34

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

如果应用程序的 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应加载类时,应用程序只是关闭并返回主屏幕,而没有任何消息或用户对话框。

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

一些想法我可以做些什么来调试问题?也许我应该尝试创建一个Parcelable对象?

在模拟器中一切正常。

4

9 回答 9

64

根据我的经验(前一段时间),您可以在IPC中打包多达1MB的数据。Bundle如果在给定时间发生大量事务,则可以减少此限制。更多信息在这里

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

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

于 2012-09-19T14:40:34.870 回答
20

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

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

于 2016-05-05T15:48:10.393 回答
4

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

于 2013-09-01T02:49:09.693 回答
4

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

1MB是在特定时刻系统中执行的所有 binder 事务的总体限制。

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

于 2017-06-09T06:54:06.490 回答
3

我已经看到,通过写入和读取文件会降低性能。 然后我看到了这个解决方案:。所以我正在使用这个解决方案:

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");
}
于 2017-07-31T07:26:46.753 回答
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();
于 2014-12-20T21:03:38.067 回答
2

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

所以每次都尽量保持你的意图数据尽可能小。

于 2016-10-03T15:44:14.800 回答
1

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

public static String msg;

然后您可以使用 MainActivity 类中的静态字段 msg 如下

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

最后开始您的活动,无需额外投入

Intent intent = new Intent(MainActivity.this, ReadDataActivity.class);                  
startActivity(intent);
于 2016-07-25T09:00:22.510 回答
1

变量的使用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);

这个想法来自这里

于 2016-11-25T03:57:35.420 回答