WebViewFragment webView is null after doing a FragmentTransaction - android

I currently have my application set up with a ListFragment on the left and a DetailsFragment on the right (similar to the layout on the tablet below).
On the details fragment (fragment next to the list) I have a goto deal button, which when pressed should replace the detailsFragment with a WebViewFragment.
The problem I am having is that when trying to load a url in the webviewfragment the WebView is null.
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");
Below is my main layout which has the original two fragments defined.
<?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>
It seems that the webViewFragment is not being created fully as the WebView has not been initialised. I have looked online but there is very little information regarding the WebViewFragment.
Any ideas how to ensure WebView is initialised in the WebViewFragment?

With great help from Espiandev I have managed to get a working WebView. To ensure that links opened in the fragment and not in a web browser application I created a simple InnerWebView client which extends WebViewClinet.
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;
}
}
Hopefully this is useful to someone in the future.

EDIT: So I played around with this for a while and it seems that the WVF is a bit rubbish and designed to be overridden. However, there's no documentation on this at all! The problem stems from the fact you can call getWebView() before the Fragments view is loaded, hence your NullPointerException. Except there isn't any way to detect when the Fragment's view has been loaded, so you're kind of stuck!
Instead I overrode the class, adding bits and changing bits, so that now it will work fine.
Check this link for the code. Then instead of using:
WebViewFragment webViewFragment = new WebViewFragment();
to load your Fragment, use:
ImprovedWebViewFragment wvf = new ImprovedWebViewFragment("www.google.com");
This class also includes a convenience method for loading a url, that won't throw an Exception if there's no WebView.
So, no, I don't think there's a particularly simple way for using the built-in WebViewFragment, but it is pretty easy to make something that works instead. Hope it helps!

WebViewFragment as is is not that straightforward to use. Try this simple extension (You can copy/paste):
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;
}
}
Call where you need using the factory method:
WebViewFragment fragment = UrlWebViewFragment.newInstance("http://ur-url.com");

Fragments can only be replaced if they were initiallized in Java, not XML. I think so, I had the same problem and it solved it. Change your XML to this:
<?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>
and then in Java, your onCreate method:
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.my_container, new DealDetailsFragment());
transaction.commit();
or even better create whole method to just deal with Transactions.
Now Transaction from your question should work. :)

Related

navigateUp() and navigate(action_id) not working as expected

Using the Navigation framework, I navigate from a Homefragment to a WhsSearchWebDB and back to the Homefragment.
When coming back via navController.navigate(R.id.action_whsSearchWebDB_to_nav_home) or navController.navigateUp(), the screen is completely white and the toolbar is only partially updated: the name of the fragment is correctly set, but the navigation button shows a back arrow instead of the three-bar-home icon.
When coming back via the back button (navController.navigate(R.id.action_whsSearchWebDB_to_nav_home) and navController.navigateUp() commented, of course), everything works fine.
I need to come back programmatically, not through a user click on the back button. What must I change?
mobile_navigation.xml:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mobile_navigation"
app:startDestination="#id/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="be.ema.golfclubdataconversion.ui.home.HomeFragment"
android:label="#string/menu_home"
tools:layout="#layout/fragment_home" >
<action
android:id="#+id/action_nav_home_to_whsSearchWebDB"
app:destination="#id/whsSearchWebDB" />
</fragment>
<fragment
android:id="#+id/nav_gallery"
android:name="be.ema.golfclubdataconversion.ui.gallery.GalleryFragment"
android:label="#string/menu_gallery"
tools:layout="#layout/fragment_gallery" />
<fragment
android:id="#+id/nav_slideshow"
android:name="be.ema.golfclubdataconversion.ui.slideshow.SlideshowFragment"
android:label="#string/menu_slideshow"
tools:layout="#layout/fragment_slideshow" />
<fragment
android:id="#+id/whsSearchWebDB"
android:name="be.ema.golfclubdataconversion.ui.WhsSearchWebDB"
android:label="WhsSearchWebDB"
tools:layout="#layout/search_web_db">
<action
android:id="#+id/action_whsSearchWebDB_to_nav_home"
app:destination="#id/nav_home" />
</fragment>
home_fragment code:
public class HomeFragment extends Fragment {
public static View root = null;
private HomeViewModel homeViewModel;
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
#Override
public void onViewCreated(View root, Bundle savedInstanceState) {
// super.onViewCreated(root, savedInstanceState);
// homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
Button openUrlBtn = root.findViewById(R.id.openUrlBtn);
openUrlBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NavController navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
navController.navigate(R.id.action_nav_home_to_whsSearchWebDB);
}
});
}
}
WhsSearchWebDB code :
public class WhsSearchWebDB extends Fragment {
public static Activity activity;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.search_web_db, container, false);
return v;
}
#Override
public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState);
activity = getActivity();
String urlToBeOpened = "http://ncrdb.usga.org";
WebView webView = (WebView) root.findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url)
{
/* This call inject JavaScript into the page which just finished loading. */
webView.loadUrl("javascript:window.HTMLOUT.processHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");
}
});
webView.loadUrl(urlToBeOpened);
}
public static class MyJavaScriptInterface {
#JavascriptInterface
public void processHTML(String html) {
NavController navController = Navigation.findNavController(activity, R.id.nav_host_fragment);
// navController.navigate(R.id.action_whsSearchWebDB_to_nav_home);
// if (!navController.navigateUp()) {
// System.out.println("nooooooo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
// }
}
}
}
**** EDIT ****
This is the expected screen (picture taken before going to the WhsSearchWebDB fragment:
And this is the incorrect result after trying to come back:
The Navigation Action in the whsSearchWebDB Fragment is creating a new fragment not popping back to the original fragment.
<fragment
android:id="#+id/whsSearchWebDB"
android:name="be.ema.golfclubdataconversion.ui.WhsSearchWebDB"
android:label="WhsSearchWebDB"
tools:layout="#layout/search_web_db">
<action
android:id="#+id/action_whsSearchWebDB_to_nav_home"
// Change this
app:destination="#id/nav_home"
// To this to pop back
app:popUpTo="#id/nav_home" />
I didn't include popUpToInclusive.
PopUPToInclusive needs to be set to true, the popUpTo attribute will remove all destinations up to and including the given destination from the back stack.
Open the navigation graph
Select the action, you want
In the attributes pane, set popUptToInclusive the homeFragment, Select the popUpToInclusive check box to true.
For more details please check out the Navigation code lab.
https://developer.android.com/codelabs/android-navigation#6
I finally discovered that the processHTML method executes on a background thread, hence not allowed to manipulate UI widgets. I had preferred a crash/error instead of the unexpected behavior I have reported in my question.
I have fixed the issue by implementing a ViewModel, selecting the result in the processHTML method and observing it on the UI thread as follows:
#Override
public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState);
activity = getActivity();
String urlToBeOpened = "http://ncrdb.usga.org";
WebView webView = (WebView) root.findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url)
{
/* This call inject JavaScript into the page which just finished loading. */
webView.loadUrl("javascript:window.HTMLOUT.processHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");
}
});
webView.loadUrl(urlToBeOpened);
TeeboxViewModel teeboxViewModel = new ViewModelProvider((ViewModelStoreOwner) activity).get(TeeboxViewModel.class);
teeboxViewModel.getSelected().observe(getViewLifecycleOwner(), item -> {
...
NavController navController = Navigation.findNavController(activity, R.id.nav_host_fragment);
navController.navigate(R.id.action_whsSearchWebDB_to_nav_newResult);
});
}
public static class MyJavaScriptInterface {
public static Map<String, String> coursesList = new HashMap<>();
#JavascriptInterface
public void processHTML(String html) {
...
TeeboxViewModel model = new ViewModelProvider((ViewModelStoreOwner) activity).get(TeeboxViewModel.class);
model.select(teeboxesList);
}
}

Prevent WebView fragment from reloading page on screen rotation

I know this has been asked too many times and that SO is full of similar questions. I went through most of them and I've been researching this issue for a couple of days and I have yet to find the definitive solution.
I could easily avoid all this trouble adding configChanges="orientation|screenSize" to the activity containing the WebView; I've tested this and it worked as intended (the WebView didn't reload). But I really wanted to avoid this solution.
Here's my current WebView implementation:
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();
}
}
As for the MainActivity, there's nothing there besides setting the content view to the following layout file:
<?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>
Notice above that I'm retaining the fragment instance and I'm also saving the state of the WebView so I can late restore that same state. This is what the documentation has to say about the restoreState method:
Restores the state of this WebView from the given Bundle. This method
is intended for use in onRestoreInstanceState(Bundle) and should be
called to restore the state of this WebView. If it is called after
this WebView has had a chance to build state (load pages, create a
back/forward list, etc.) there may be undesirable side-effects. Please
note that this method no longer restores the display data for this
WebView.
Meaning, the display data will not be restored but things like the scroll position will (I also tested this and it's working nicely). That's why I am creating a new instance of the WebView, only if it's null during onCreateView and removing it from the parent view during onDestroyView. This was taken from this answer: https://stackoverflow.com/a/32801278/40480
This mechanism will make the rotate process a little bit more smooth (without it, a full blank page was shown) but won't prevent the WebView from still reloading the page.
Any ideas how can I possibly solve this problem?
I had a similar problem. It's a bit late but my workaround is similar than yours but adding the webview again to the layout in onCreateView:
create new WebView if instance is null (first time) and add it to layout (in my case parent is a FrameLayout, at position 0).
if already created (activity recreated) just add to frame and invalidate (important to redraw webview on rotation)
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();
}
As in your case I remove webview from frame in OnDestroyView() to be able to add it again in onCreateView:
#Override
public void onDestroyView() {
mFrame.removeView(mWebView);
super.onDestroyView();
}
NOTE: I don't save and store the webview state as it reloads the page (at least in my case). Furthermore, the scroll position does not normally match in portrait/landscape but same problem in Chrome as far as I've checked.
Regards.

onCreateView() never runs (Trying to use ViewPager for screen slides)

My goal is to use ViewPager (like here) to let user slide through 5 different pages (a tutorial) before my MainActivity starts...
I've downloaded Animations.zip from the link above and its almost what I need, except for supporting older versions (what I managed by changing android.app references to android.support.v4.app) and using totally different layouts instead of using the same view like in the example...
My code compiles and runs, but on the phone's screen I can't see the slides changing. The action bar appears, its buttons are working fine, and I can even see that blue glow when I reach the first/last page and try to slide again... I guess android is generating default layouts for some reason.
While debugging, I've noticed that onCreateView() inside the fragment never runs. Any idea why? My code is as below:
como_usar_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView style="?android:textAppearanceMedium"
android:id="#+id/texto_como_usar_fragment"
android:padding="16dp"
android:lineSpacingMultiplier="1.2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="aglaglalglaglalgalgalglag"
android:textColor="#color/branco"
/>
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="#drawable/logo"
/>
ComoUsarFragment.java
public class ComoUsarFragment extends Fragment {
/**
* The argument key for the page number this fragment represents.
*/
public static final String ARG_PAGE = "page";
/**
* The fragment's page number, which is set to the argument value for {#link #ARG_PAGE}.
*/
private int mPageNumber;
/**
* Factory method for this fragment class. Constructs a new fragment for the given page number.
*/
public static Fragment create(int pageNumber) {
Fragment fragment = new Fragment();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, pageNumber);
fragment.setArguments(args);
return fragment;
}
public ComoUsarFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPageNumber = getArguments().getInt(ARG_PAGE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
//this is an attempt to set different views for each page, you'll see I dont use this piece of code yet
int pagina;
switch (mPageNumber){
case 0: pagina = R.layout.como_usar0;
break;
case 1: pagina = R.layout.como_usar1;
break;
case 2: pagina = R.layout.como_usar2;
break;
default: pagina = R.layout.como_usar_fragment;
break;
}
// Inflate the layout containing a title and body text.
ViewGroup rootView = (ViewGroup) inflater
.inflate(R.layout.como_usar_fragment, container, false);
// Set the title view to show the page number.
((TextView) rootView.findViewById(android.R.id.text1)).setText("aaaaa "+mPageNumber);
return rootView;
}
/**
* Returns the page number represented by this fragment object.
*/
public int getPageNumber() {
return mPageNumber;
}
}
You are returning a standard fragment instead of your own subclass
public static Fragment create(int pageNumber) {
Fragment fragment = new Fragment();
...
should be
public static Fragment create(int pageNumber) {
Fragment fragment = new ComoUsarFragment();
...

Android Fragment is given a null container in onCreateView()

I am trying to use Android fragments in a very simple way, similar to the tutorial on the Android developer website.
I have an Activity (MediaInfoActivity) with the following code:
public class MediaInfoActivity extends FragmentActivity {
private final String TAG = "MediaInfoActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");
setContentView(R.layout.media_info_activity_layout);
}
}
Here is the code for the media_info_activity_layout.xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<fragment class="com.hawkforce.test.MediaInfoFragment"
android:id="#+id/mediaInfoFragment"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp" />
<FrameLayout android:id="#+id/mediaPlayerBarPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<fragment class="com.hawkforce.test.MediaPlayerBarFragment"
android:id="#+id/mediaPlayerBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
And finally here is the code for MediaInfoFragment:
public class MediaInfoFragment extends Fragment {
private final static String TAG = "MediaInfoFragment";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate()");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i(TAG, "onCreateView()");
if (container == null) {
Log.i(TAG, "onCreateView(): container = null");
}
return inflater.inflate(R.layout.media_info_fragment_layout, container, false);
}
}
Here is my problem : the container passed in the onCreateView() method of the MediaInfoFragment is null. As I understood, this should only be the case for non-UI Fragments. However, my Fragment has a UI, which is displayed OK on the screen when I launch MediaInfoActivity. It causes problems because no style declared in the xml layout file of the fragment is applied.
Here is my Log:
I/MediaInfoActivity: onCreate()
I/MediaInfoFragment: onCreate()
I/MediaInfoFragment: onCreateView()
I/MediaInfoFragment: onCreateView(): container = null
Am I missing anything obvious here ?
You just have to create a inflater like bellow in your fragment.
View rootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (rootView == null) {
rootView = inflater.inflate(R.layout.activity_my_cart, null);
} else {
((ViewGroup) container.getParent()).removeView(rootView);
}
return rootView;
}
I hope it will work as per your question.
I am not sure since I don't have the code of the SDK in front of me but I think that the life-cycle of calling Fragment "onCreateView" function is different between the two cases:
1. Static settings of fragment in layout
2. Loading pragmatically with FragmentManager.
In the first case the debugger get into Fragment.onCreateView() method immediately upon adding the content view to the parent activity as part of onCreate() code:
When calling: setContentView(R.layout.some_layoue);
You will see the debugger get into Fragment.onCreateView() before going to next line
In the second case the Fragment.onCreateView() is being invoked only after the onCreate() of the activity is finished.
This looks like design bug for me but possibly as design feature.
Anyway the container is null when adding fragment statically because the related object was not yet created.
In fact the difference between the two situations is much deeper. In the case of static fragments toggling between fragments will not create the view hierarchy correctly.
For example if you will add button-A to fragment A and button-B to Fragment-B and toggle the fragments with a code looks like this (highlighting only the relevant code):
public void turnOnFragment() {
FragmentManager manager = getFragmentManager();
if (manager != null) {
manager.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.attach(this)
.commit();
}
}
public void turnOffFragment() {
FragmentManager manager = getFragmentManager();
if (manager != null) {
manager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
manager.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.detach(this)
.commit();
}
}
You will see that in the case of static fragments the buttons from both fragments are presented although turning on and off. If however fragments are added programatically the toggle works fine and view hierarchy is cleaned and show only button from relevant fragment.
This is based of my experience with version 4.4.2

Android-How to use a fragment to display a webview

Im updating some of my older projects and using fragments to update the look of things. I tried to use a fragment to launch a webview but when I try to run it I get the following error in my logcat.
E/Web Console(22464): Uncaught TypeError: Cannot read property 'addEventListener' of null at
http://m.yahoo.com/?.tsrc=yahoo&mobile_view_default=true:1
The way I used to use a webview was to just create a class that was its own activity that took place in a webview but I would like to have a small view within a fragment and then when I wanted to use the class I would launch it via intent and pass anything I needed to the webview like a url and other parameters in extras within the intent. I tried just setting up a webview within a fragment but I havent gotten it to work yet. This is the code Im using for the moment.
public class WebViewer extends Fragment {
WebView Wv;
String url = "http://www.yahoo.com";
Activity act;
public WebViewer(){}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.act = activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View mView = inflater.inflate(R.layout.webview, container);
Wv = (WebView) mView.findViewById(R.id.webview1);
Wv.getSettings().setJavaScriptEnabled(true);
Wv.getSettings().setRenderPriority(RenderPriority.HIGH);
Wv.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
Wv.getSettings().setDomStorageEnabled(true);
Wv.setWebViewClient(new HelloWebViewClient());
Wv.getSettings().setBuiltInZoomControls(true);
Wv.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress)
{
act.setTitle("Loading...");
act.setProgress(progress * 100);
if(progress == 100)
getActivity().setTitle(R.string.app_name);
}
});
Wv.loadUrl(url);
return mView;
}
}
And then this is the layout for the activity that uses this fragment.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#drawable/bggreydotted"
>
<fragment
android:id="#+id/webFragment"
android:layout_width="150dip"
android:layout_height="match_parent"
android:name="my.proj.WebViewer"></fragment>
</LinearLayout>
So how can I get a webview to open inside a fragment I can use in a view.
Have you thought about just extending WebViewFragment?

Categories

Resources