Android WebView获取部分网站(如Instagram)源码时应用崩溃的问题咨询
Android WebView获取部分网站(如Instagram)源码时应用崩溃的问题咨询
嘿,我仔细看了你的问题、代码和Logcat日志,马上就找到崩溃的原因了!
问题根源:TransactionTooLargeException
从Logcat里的错误信息可以看到:
android.os.TransactionTooLargeException: data parcel size 771000 bytes
Android的Binder事务有一个默认的大小限制(通常在1MB左右),当你通过Intent.putExtra传递大型网站(比如Instagram)的HTML源码时,数据量超过了这个限制,就会触发这个异常,导致应用崩溃。而像example.com这类小型网站的源码体积较小,刚好在限制范围内,所以不会出问题。
你的代码里就是直接把整个HTML源码通过Intent传递给SourceActivity,这在处理大型网站时肯定会出问题。
解决方案:避免用Intent传递大体积数据
我们可以改用两种更安全的方式来传递或存储大体积的源码:
方案1:通过自定义Application类共享数据
这种方式适合中等大小的源码,操作简单:
- 首先创建一个自定义的Application类:
package com.example.pokuswebview2; import android.app.Application; public class MyApp extends Application { private String pageSource; public String getPageSource() { return pageSource; } public void setPageSource(String pageSource) { this.pageSource = pageSource; } }
- 在
AndroidManifest.xml里注册这个Application:
<application android:name=".MyApp" <!-- 其他原有配置 --> > <!-- 原有Activity配置 --> </application>
- 修改MainActivity的点击事件逻辑,把源码存入Application:
btnShowSource.setOnClickListener(v -> { webView.evaluateJavascript("(function() { return document.documentElement.outerHTML; })()", html -> { if (html != null) { // 将源码存入自定义Application ((MyApp) getApplication()).setPageSource(html); Intent intent = new Intent(MainActivity.this, SourceActivity.class); startActivity(intent); } else { Toast.makeText(MainActivity.this, "Chyba při získávání zdrojového kódu", Toast.LENGTH_SHORT).show(); } }); });
- 修改SourceActivity从Application读取源码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_source); tvSourceCode = findViewById(R.id.tvSourceCode); // 从自定义Application获取源码 String pageSource = ((MyApp) getApplication()).getPageSource(); if (pageSource != null) { tvSourceCode.setText(pageSource); // 用完后清空,避免占用内存 ((MyApp) getApplication()).setPageSource(null); } }
方案2:写入本地临时文件
如果网站源码特别庞大(比如超过几MB),用Application可能会占用过多内存,这时候可以写入本地缓存文件:
- 修改MainActivity的点击事件,把源码写入临时文件:
btnShowSource.setOnClickListener(v -> { webView.evaluateJavascript("(function() { return document.documentElement.outerHTML; })()", html -> { if (html != null) { try { // 在缓存目录创建临时文件 File tempFile = File.createTempFile("page_source", ".html", getCacheDir()); FileWriter writer = new FileWriter(tempFile); writer.write(html); writer.close(); // 传递临时文件路径给SourceActivity Intent intent = new Intent(MainActivity.this, SourceActivity.class); intent.putExtra("SOURCE_FILE_PATH", tempFile.getAbsolutePath()); startActivity(intent); } catch (IOException e) { e.printStackTrace(); Toast.makeText(MainActivity.this, "Chyba při ukládání zdrojového kódu", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(MainActivity.this, "Chyba při získávání zdrojového kódu", Toast.LENGTH_SHORT).show(); } }); });
- 修改SourceActivity读取临时文件并显示:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_source); tvSourceCode = findViewById(R.id.tvSourceCode); String filePath = getIntent().getStringExtra("SOURCE_FILE_PATH"); if (filePath != null) { try { File file = new File(filePath); BufferedReader reader = new BufferedReader(new FileReader(file)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line).append("\n"); } reader.close(); tvSourceCode.setText(sb.toString()); // 读取完成后删除临时文件,避免占用存储空间 file.delete(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "Chyba při čtení zdrojového kódu", Toast.LENGTH_SHORT).show(); } } }
额外注意事项
- 转义字符处理:
evaluateJavascript返回的HTML字符串会被转义(比如包含\"这类转义符),如果想要更清晰的源码显示,可以额外做转义还原处理,比如用html = html.replace("\\", "").substring(1, html.length() - 1);来去掉前后的引号和多余转义。 - 内存管理:大型网站的源码体积很大,用完后记得及时清空或删除,避免内存泄漏或存储空间占用。
备注:内容来源于stack exchange,提问作者Mirek6
相关产品推荐
相关产品推荐

