执行FragmentTransaction后,WebViewFragment webView为null

时间:2012-02-06 13:58:18

标签: android android-3.0-honeycomb android-webview android-fragments android-4.0-ice-cream-sandwich

我目前设置的应用程序左侧为ListFragment,右侧为DetailsFragment(类似于下方平板电脑的布局)。

layout

在详细信息片段(列表旁边的片段)上,我有一个转到交易按钮,按下该按钮时应将detailsFragment替换为WebViewFragment

我遇到的问题是,当尝试在webviewfragment中加载网址时,WebView为空。

WebViewFragment webViewFragment = new WebViewFragment();

FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.deal_details_fragment, webViewFragment);
transaction.addToBackStack(null);

// Commit the transaction
transaction.commit();

// Set the url
if (webViewFragment.getWebView()==null)
    Log.d("webviewfragment", "is null");
webViewFragment.getWebView().loadUrl("http://www.google.com");

下面是我的主要布局,其中定义了原始的两个片段。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/main_activity_layout"

    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

  <fragment
      android:name="com.bencallis.dealpad.DealListFragment"
      android:id="@+id/deal_list_fragment"
      android:layout_weight="1"
      android:layout_width="0px"
      android:layout_height="match_parent" >
      <!-- Preview: layout=@layout/deal_list_fragment -->
  </fragment>
  <fragment
      android:name="com.bencallis.dealpad.DealDetailsFragment"
      android:id="@+id/deal_details_fragment"
      android:layout_weight="2"
      android:layout_width="0px"
      android:layout_height="match_parent" >
      <!-- Preview: layout=@layout/deal_details_fragment -->
  </fragment>

</LinearLayout>

似乎没有完全创建webViewFragment,因为WebView尚未初始化。我已经在线查看,但关于WebViewFragment的信息非常少。

如何确保WebView初始化{?1}}?

4 个答案:

答案 0 :(得分:12)

在Espiandev的帮助下,我设法获得了一个有效的WebView。为了确保在片段中而不是在Web浏览器应用程序中打开链接,我创建了一个扩展WebViewClinet的简单InnerWebView客户端。

public class DealWebViewFragment extends Fragment {

    private WebView mWebView;
    private boolean mIsWebViewAvailable;
    private String mUrl = null;

    /**
     * Creates a new fragment which loads the supplied url as soon as it can
     * @param url the url to load once initialised
     */
    public DealWebViewFragment(String url) {
        super();
        mUrl = url;
    }

    /**
     * Called to instantiate the view. Creates and returns the WebView.
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        if (mWebView != null) {
            mWebView.destroy();
        }
        mWebView = new WebView(getActivity());
        mWebView.setOnKeyListener(new OnKeyListener(){


            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                  if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
                        mWebView.goBack();
                        return true;
                    }
                    return false;
            }

        });
        mWebView.setWebViewClient(new InnerWebViewClient()); // forces it to open in app
        mWebView.loadUrl(mUrl);
        mIsWebViewAvailable = true;
        WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        return mWebView;
    }

    /**
     * Convenience method for loading a url. Will fail if {@link View} is not initialised (but won't throw an {@link Exception})
     * @param url
     */
    public void loadUrl(String url) {
        if (mIsWebViewAvailable) getWebView().loadUrl(mUrl = url);
        else Log.w("ImprovedWebViewFragment", "WebView cannot be found. Check the view and fragment have been loaded.");
    }

    /**
     * Called when the fragment is visible to the user and actively running. Resumes the WebView.
     */
    @Override
    public void onPause() {
        super.onPause();
        mWebView.onPause();
    }

    /**
     * Called when the fragment is no longer resumed. Pauses the WebView.
     */
    @Override
    public void onResume() {
        mWebView.onResume();
        super.onResume();
    }

    /**
     * Called when the WebView has been detached from the fragment.
     * The WebView is no longer available after this time.
     */
    @Override
    public void onDestroyView() {
        mIsWebViewAvailable = false;
        super.onDestroyView();
    }

    /**
     * Called when the fragment is no longer in use. Destroys the internal state of the WebView.
     */
    @Override
    public void onDestroy() {
        if (mWebView != null) {
            mWebView.destroy();
            mWebView = null;
        }
        super.onDestroy();
    }

    /**
     * Gets the WebView.
     */
    public WebView getWebView() {
        return mIsWebViewAvailable ? mWebView : null;
    }

    /* To ensure links open within the application */
    private class InnerWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }


    }

希望这对将来的某些人有用。

答案 1 :(得分:7)

编辑:所以我玩了一段时间,似乎WVF有点垃圾,并且被设计为被覆盖。但是,根本没有关于此的文档!问题源于您可以在加载Fragment视图之前调用getWebView(),因此您的NullPointerException。除非没有任何方法可以检测片段的视图何时被加载,所以你有点卡住了!

相反,我覆盖了类,添加了位和更改位,所以现在它可以正常工作。 检查this link代码。然后而不是使用:

WebViewFragment webViewFragment = new WebViewFragment();

加载你的片段,使用:

ImprovedWebViewFragment wvf = new ImprovedWebViewFragment("www.google.com");

此课程还包括加载网址的便捷方法,如果没有Exception将>抛出WebView

所以,不,我不认为使用内置的WebViewFragment有一个特别简单的方法,但是很容易做出有用的东西。希望它有所帮助!

答案 2 :(得分:2)

WebViewFragment不是那么简单易用。试试这个简单的扩展(你可以复制/粘贴):

public class UrlWebViewFragment extends WebViewFragment{

    private String url;

    public static UrlWebViewFragment newInstance(String url) {
        UrlWebViewFragment fragment = new UrlWebViewFragment();
        fragment.url = url;
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        WebView webView = (WebView) super.onCreateView(inflater, container, savedInstanceState);
        webView.loadUrl(url);
        return webView;
    }         
  }

使用工厂方法调用所需位置:

WebViewFragment fragment = UrlWebViewFragment.newInstance("http://ur-url.com");

答案 3 :(得分:0)

只有在Java中初始化碎片时才能替换碎片,而不是XML。我想是的,我遇到了同样的问题而且解决了这个问题。将XML更改为:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/main_activity_layout"

    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

  <fragment
      android:name="com.bencallis.dealpad.DealListFragment"
      android:id="@+id/deal_list_fragment"
      android:layout_weight="1"
      android:layout_width="0px"
      android:layout_height="match_parent" >
      <!-- Preview: layout=@layout/deal_list_fragment -->
  </fragment>
  <View
      android:id="@+id/my_container"
      android:layout_weight="2"
      android:layout_width="0px"
      android:layout_height="match_parent" >
  </View>

</LinearLayout>

然后在Java中,你的onCreate方法:

FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.my_container, new DealDetailsFragment());
transaction.commit();

甚至更好地创建整个方法来处理Transaction s。

现在问题Transaction应该有效。 :)