我制作了一个Fragment,其中包含一个WebView,我想定义一个onKeyDown()以从一个网页返回到上一个网页。我做到了,但是对我来说最奇怪的部分是将WebView类中的Fragment变量共享给Activity类,因为我无法在onKeyDown()中定义Fragment。因此,我只定义了一个get方法并将其设为静态。但是我想知道这是否是一个真正的错误,并且在某些情况下我的应用程序可能会严重崩溃。

我的Fragment代码:

public class BrowserFragment extends Fragment {
    private static WebView webView;

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

    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){
        View v = inflater.inflate(R.layout.fragment_activity, parent, false);

        getActivity().setTitle(R.string.title_rus);

        webView = (WebView) v.findViewById(R.id.webView);
        webView.setWebViewClient(new SwingBrowserClient());
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        Uri data = Uri.parse("http://www.swinginmoscow.ru/m/");
        webView.loadUrl(data.toString());

        return v;
    }

    public static WebView getWebView() {
        return webView;
    }
}

和我的Activity代码:
public class MainBrowserActivity extends SingleFragmentActivity {

    @Override
    protected Fragment createFragment() {
        return new BrowserFragment();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && BrowserFragment.getWebView().canGoBack()) {
            BrowserFragment.getWebView().goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

最佳答案

它可能有效,但这不是一个好主意。如果您没有正确处理Fragment或在代码中的某个地方对其生命周期有些粗心,则很可能导致崩溃。但是有一个简单的方法可以解决此问题。代替使用静态方法,将实例和调用方法保存在实例本身上。这样,您可以检查实例是否为空,如果不是,那么Fragment可以处理对goBack()canGoBack()本身的调用:

public class MainBrowserActivity extends SingleFragmentActivity {

    BrowserFragment browserFragment = null;

    @Override
    protected Fragment createFragment() {
        this.browserFragment = BrowserFragment.newInstance();
        return this.browserFragment;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && this.browserFragment != null && this.browserFragment.canGoBack()) {
            this.browserFragment.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

如您所见,保存了BrowserFragment实例,然后在goBack()本身上调用了canGoBack()BrowserFragment之类的方法。当然,您必须在BrowserFragment中实现这些方法,但这应该不是问题:
public class BrowserFragment extends Fragment {

    public static BrowserFragment newInstance() {
        BrowserFragment fragment = new BrowserFragment();
        return fragment;
    }

    private WebView webView;

    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){
        View v = inflater.inflate(R.layout.fragment_activity, parent, false);

        getActivity().setTitle(R.string.title_rus);

        webView = (WebView) v.findViewById(R.id.webView);
        webView.setWebViewClient(new SwingBrowserClient());
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        Uri data = Uri.parse("http://www.swinginmoscow.ru/m/");
        webView.loadUrl(data.toString());
        return v;
    }

    public boolean canGoBack() {
        return this.webView != null && this.webView.canGoBack();
    }

    public void goBack() {
        if(this.webView != null) {
            this.webView.goBack();
        }
    }
}

我对您的代码做了一些额外的改进。首先,我添加了null检查以防止任何可能的NullPointerExceptions,其次,建议始终使用静态工厂方法来创建Fragments的新实例。这就是我添加到newInstance()中的静态BrowserFragment方法。这样做的好处是您可以实现一个方法,该方法可以为您设置BrowserFragment,而无论您在何处使用它。您可以向newInstance()方法添加参数以将一些值传递给BrowserFragment或添加一些必需的监听器等,但是由于您没有将任何值传递给BrowserFragment,因此newInstance()方法仍然是空的。尽管如此,最佳实践是始终使用此类工厂方法,即使它们仅调用new BrowserFragment()

通常,这种方法要好得多。特别是从体系结构的角度来看,因为您没有直接与WebView中的Activity进行交互。 WebViewActivity没有任何关系,它是BrowserFragment的实现的一部分,因此Activity甚至不应该知道WebView。对goBack()而言,如何实现对canGoBack()Activity的调用或其确切执行的操作是无关紧要的。 Activity只是告诉BrowserFragment“我想回去”,而BrowserFragment可以完成工作。这样可以更好地分隔职责,并使代码更易读,更清晰和更可维护。

编辑:

我也不知道SingleFragmentActivity,但是通常任何Activity都实现onBackPressed()方法。您不必重写onKeyDown()即可捕获返回键事件。您可以执行以下操作:
@Override
public void onBackPressed() {
    if (this.browserFragment != null && this.browserFragment.canGoBack()) {
        this.browserFragment.goBack();
    } else {
        // The back key event only counts if we execute super.onBackPressed();
        super.onBackPressed();
    }
}

如果您还有其他疑问,请随时提问!

09-12 06:03