防止WebView片段在屏幕旋转时重新加载页面

时间:2016-04-22 18:14:47

标签: android android-fragments webview page-refresh

我知道这已经被问了太多次,并且SO充满了类似的问题。我经历了大部分时间,并且我已经研究了这个问题几天了,我还没有找到明确的解决方案。

我可以轻松避免将configChanges="orientation|screenSize"添加到包含WebView的活动中的所有麻烦;我已对此进行了测试,并且按预期工作(WebView没有重新加载)。 但我真的想避免这种解决方案。

这是我当前的WebView实现:

public class BrowserFragment extends Fragment {

    private WebView mWebView;

    public BrowserFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setRetainInstance(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (mWebView == null) {
            mWebView = new WebView(getActivity());
        }

        return mWebView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mWebView.setWebViewClient(new WebViewClient() {

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                return super.shouldOverrideUrlLoading(view, url);
            }

        });

        mWebView.getSettings().setAllowFileAccess(true);
        mWebView.getSettings().setBuiltInZoomControls(false);
        mWebView.getSettings().setDomStorageEnabled(true);
        mWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.getSettings().setSupportZoom(false);

        if (savedInstanceState == null) {
            mWebView.loadUrl("http://developer.android.com/");
        } else {
            mWebView.restoreState(savedInstanceState);
        }
    }

    @Override
    public void onResume() {
        mWebView.onResume();

        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();

        mWebView.onPause();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        mWebView.saveState(outState);
    }

    @Override
    public void onDestroyView() {
        if (getRetainInstance() && mWebView.getParent() instanceof ViewGroup) {
            ((ViewGroup) mWebView.getParent()).removeView(mWebView);
        }

        super.onDestroyView();
    }

}

对于MainActivity,除了将内容视图设置为以下布局文件之外,没有任何其他内容:

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

    <fragment
        android:id="@+id/fragment_browser"
        android:name="com.example.app.BrowserFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</merge>

请注意,我保留了片段实例,并且还保存了WebView的状态,因此我可以延迟恢复相同的状态。这是文档对restoreState方法所说的内容:

  

从给定的Bundle恢复此WebView的状态。这种方法   旨在用于onRestoreInstanceState(Bundle),应该是   调用以恢复此WebView的状态。如果是之后的话   这个WebView有机会构建状态(加载页面,创建一个   后退/前进列表等)可能存在不良副作用。 请   请注意,此方法不再为此恢复显示数据   web视图。

意思是,显示数据不会被恢复,但滚动位置之类的东西会(我也测试了这个并且它运行得很好)。这就是为什么我创建WebView的新实例的原因,只有在null期间它onCreateView onDestroyView并在import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; import android.widget.ListView; import android.widget.Toast; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class ExDownloaderActivity extends AsyncTask<Void, Integer, String> { Context context; String address; ListView expenseListView; ProgressDialog progressDialog; public ExDownloaderActivity(Context context, String address, ListView exCategoryListView) { this.context = context; this.address = address; this.expenseListView = exCategoryListView; } //B4 JOB STARTS @Override protected void onPreExecute() { super.onPreExecute(); progressDialog = new ProgressDialog(context); progressDialog.setTitle("Fetch Data"); progressDialog.setMessage("Fetching Data...Please wait"); progressDialog.show(); } @Override protected String doInBackground(Void... params) { String data = downloadData(); return data; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } @Override protected void onPostExecute(String string) { super.onPostExecute(string); progressDialog.dismiss(); if(string != null) { ExParserActivity parser = new ExParserActivity(context, string, expenseListView); parser.execute(); } else { Toast.makeText(context, "Unable to download data",Toast.LENGTH_LONG).show(); } } private String downloadData() { //connect and get a stream of data InputStream inputStream = null; //to store each line String line = null; try { URL url = new URL(address); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); inputStream = new BufferedInputStream(httpURLConnection.getInputStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); StringBuffer stringBuffer = new StringBuffer(); if(bufferedReader!= null) { while ((line = bufferedReader.readLine()) != null) { stringBuffer.append(line + "\n"); } } else { return null; } return stringBuffer.toString(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } } 期间从父视图中删除它。这取自这个答案:https://stackoverflow.com/a/32801278/40480

此机制将使旋转过程更加平滑(没有它,显示完整的空白页面),但不会阻止WebView重新加载页面。

任何想法我怎么可能解决这个问题?

1 个答案:

答案 0 :(得分:1)

我有类似的问题。这有点晚了但是我的解决方法与你的相似,但是再次将webview添加到onCreateView的布局中:

  • 如果实例为null(第一次),则创建新的WebView并将其添加到布局(在我的情况下,父级是FrameLayout,位置0)。
  • 如果已经创建(重新创建活动),只需添加到框架并使其无效(对于在旋转时重绘webview很重要)

    mFrame = (FrameLayout) mView.findViewById(R.id.dq_fragment_browser_common_frame);
    
    if (mWebView == null){
        mWebView = new CommonWebView(getContext());
        mFrame.addView(mWebView,0);
    } else {
        mFrame.addView(mWebView,0);
        mWebView.invalidate();
    }
    

在您的情况下,我在OnDestroyView()中从框架中删除webview,以便能够在onCreateView中再次添加它:

@Override
public void onDestroyView() {
    mFrame.removeView(mWebView);
    super.onDestroyView();
}

注意:我不会在重新加载页面时保存并存储webview状态(至少在我的情况下)。此外,滚动位置通常在纵向/横向上不匹配,但在我检查过的情况下Chrome中的问题也相同。

问候。