我需要一些调试我的应用程序的帮助。首先:在模拟器和其他设备上,我的应用运行正常。在我的设备上,我关闭了一个力(没有强制关闭消息)。
如果更改了应用的活动,则会发生“崩溃”。
以下是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
对象?
在模拟器中一切正常。
答案 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。