WebView所在Activity失去焦点触发onDestroy,如何让其保持存活?
解决WebView Activity切后台被销毁需重复登录的问题
问题原因
当应用退至后台时,系统会为前台运行的应用(如身份验证器)释放内存,优先级较低的后台Activity会被优先回收,你的代码没有做状态持久化,Activity重建后会重新走初始化逻辑,导致需要重复登录。
修复方案
1. 避免配置变更触发Activity销毁
在AndroidManifest.xml中为该Activity添加configChanges配置,普通配置变化(如屏幕旋转、输入法弹出、深色模式切换等)不会触发Activity销毁重建:
<activity android:name=".AGenericWebView" android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout|uiMode" />
2. 实现WebView状态保存与恢复
重写Activity的状态保存方法,就算Activity被系统强制销毁,重建时也可以直接恢复WebView的页面状态、登录态,不需要重新加载:
public class AGenericWebView extends AppCompatActivity { private WebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a_generic_web_view); webView = findViewById(R.id.mainWebView); ImageButton backButton = findViewById(R.id.backButton); backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }); webView.getSettings().setJavaScriptEnabled(true); TextView title = findViewById(R.id.title); webView.setWebViewClient(new WebViewClient()); WebSettings settings = webView.getSettings(); settings.setSaveFormData(true); settings.setDomStorageEnabled(true); CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true); // 恢复状态优先于加载新页面 if (savedInstanceState != null) { webView.restoreState(savedInstanceState); Bundle intentBundle = getIntent().getExtras(); title.setText(intentBundle.containsKey("title") ? intentBundle.getString("title") : getResources().getString(R.string.navigazione)); } else { // 原有加载url/html的逻辑 Bundle intentBundle = getIntent().getExtras(); title.setText(intentBundle.containsKey("title") ? intentBundle.getString("title") : getResources().getString(R.string.navigazione)); if (intentBundle.containsKey("cookie") && intentBundle.containsKey("url")) { final String cookie = intentBundle.getString("cookie"); final String url = intentBundle.getString("url"); CookieManager.getInstance().setCookie(url, cookie); webView.loadUrl(url); webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int progress) { setProgress(progress * 100); } }); webView.setWebViewClient(new WebViewClient()); } else if (intentBundle.containsKey("html")) { String htmlData = intentBundle.getString("html"); webView.loadData(htmlData, "text/html", "UTF-8"); } else if (intentBundle.containsKey("url")) { String url = intentBundle.getString("url"); if (intentBundle.containsKey("postdata")) { String postData = intentBundle.getString("postdata"); byte[] postDataBytes = EncodingUtils.getBytes(postData, "BASE64"); webView.postUrl(url, postDataBytes); } else { webView.loadUrl(url); } } } } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); // 保存WebView当前状态 webView.saveState(outState); } @Override protected void onPause() { super.onPause(); // 持久化Cookie到本地,避免进程被杀死后Cookie丢失 CookieManager.getInstance().flush(); } }
3. 修复原有代码的逻辑漏洞
- 删掉重复的
webView.getSettings().setSaveFormData(false)代码,避免表单数据无法保存 - 最后一个加载分支没有postData时,不要用
webView.postUrl(url, null),改成webView.loadUrl(url),避免不必要的POST请求导致登录态失效 - 不要依赖Intent传递的Cookie做单次设置,开启Cookie持久化后,CookieManager会自动携带对应域名的Cookie,不需要每次启动都手动设置
4. 降低进程被回收优先级
可以在AndroidManifest.xml的<application>标签中添加android:largeHeap="true"申请更大的内存空间,减少后台时被系统回收的概率,但注意不要滥用该配置,会导致应用运行时占用内存过高。
注意:不要尝试通过非法保活手段强行阻止系统销毁Activity,不符合Android系统设计规范,还会增加应用功耗,容易被应用商店、系统安全机制拦截。做好状态恢复即可让用户无感知,不需要强行保活Activity。
内容的提问来源于stack exchange,提问作者Lucasky
相关产品推荐
相关产品推荐

