Changing fragments and saving web view states - going mad - android

Ive been trying to do this for the best part of a week and still have no luck.
I have an action bar with tabs (action bar sherlock) and Im switching through the tabs and changing fragments fine.
Each fragment has a webview and Im trying to save the state of the webview so the web page stays on the same page that the user left it on.
Here is my fragment code:
public class FragmentB extends SherlockFragment {
WebView myWebView;
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
myWebView.saveState(outState);
Log.w("///////", "onSaveInstanceState");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
myWebView.restoreState(savedInstanceState);
Log.w("///////", "onActivityCreated");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.w("///////", "onCreate");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View mainView = (View) inflater.inflate(R.layout.frag_b, container, false);
myWebView = (WebView) mainView.findViewById(R.id.webview);
Log.w("///////", "onCreateView");
if (savedInstanceState != null){
myWebView.restoreState(savedInstanceState);
Log.w("///////", "restore!");
}
else{
Log.w("///////", "ELSE!");
myWebView.setWebViewClient(new MyWebViewClient());
myWebView.getSettings().setPluginsEnabled(true);
myWebView.getSettings().setBuiltInZoomControls(false);
myWebView.getSettings().setSupportZoom(false);
myWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
myWebView.getSettings().setAllowFileAccess(true);
myWebView.getSettings().setDomStorageEnabled(true);
myWebView.loadUrl("http://www.google.com");
}
//return inflater.inflate(R.layout.frag_b, container, false);
return mainView;
}
public class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.endsWith(".mp4"))
{
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "video/*");
view.getContext().startActivity(intent);
return true;
}
else {
return super.shouldOverrideUrlLoading(view, url);
}
}
}
}
Any help would be great!

The onSaveInstanceState method of a fragment will only be called when the parent activity needs to save its state; an example of this is when the parent activity is being destroyed/recreated during an orientation change. As a result, this method won't be called when you are simply replacing fragments or switching between them as tabs.
As a workaround for your particular case, you can save the state of your webview in a bundle in the onPause method and restore it in the onActivityCreated method:
// Instance fields
private WebView webView;
private Bundle webViewBundle;
/**
* Save the state of the webview
*/
#Override
public void onPause()
{
super.onPause();
webViewBundle = new Bundle();
webView.saveState(webViewBundle);
}
/**
* Restore the state of the webview
*/
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
if (webViewBundle != null)
{
webView.restoreState(webViewBundle);
}
}
See here for more information as well:
How to save the state of a WebView inside a Fragment of an Action Bar

Related

WebView save and restore state issue with postUrl

I am using the following components in my application
Activity
Fragment
WebView
Goal - I don't want to reload the webview on orientation change.
Issue - Currently I see the following error on orientation change "Webpage was not available. The webpage at https://fakeurls.org could not be loaded because net::ERR_CACHE_MISS"
Steps to Reproduce
Application was opened in device portrait mode.
Content of given URL was loaded in webview successfully
Device was turned to landscape mode
Webview shows error
Code - Android application makes a post request in a webview to url https://fakeurls.org. Below is the code for MyActivity and MyFragment class
MyFragment.java
public class MyFragment extends Fragment {
private ProgressBar mProgressBar;
private WebView mWebView;
private String mUrl = null;
private String mPostData = null;
public MyFragment() {
// Required empty public constructor
}
public static MyFragment newInstance(#android.support.annotation.NonNull String url, String postData) {
MyFragment MyFragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("URL", url);
bundle.putString("POSTDATA", postData);
MyFragment.setArguments(bundle);
return MyFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.my_fragment, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
instantiateWebView(view);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
mWebView.restoreState(savedInstanceState);
} else {
Bundle args = getArguments();
if (args == null) {
return;
}
mUrl = args.getString("URL");
mPostData = args.getString("POSTDATA");
mWebView.postUrl("https://fakeurls.org/", EncodingUtils.getBytes(mPostData, "BASE64"));
}
}
#Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
if (mWebView != null) {
mWebView.saveState(outState);
}
}
#Override
public void onDestroy() {
super.onDestroy();
mWebView.destroy();
}
private void instantiateWebView(View view) {
mWebView = (WebView) view.findViewById(R.id.webView);
mWebView.setWebViewClient(new WebViewClient());
mWebView.getSettings().setJavaScriptEnabled(true);
}
}
MyActivity.java
public class MyActivity extends AppCompatActivity {
private MyFragment mMyFragment;
#NonNull
public static Intent createIntent(Context context, String url, String postData) {
return new Intent(context, MyActivity.class).putExtra("URL", url)
.putExtra("POSTDATA", postData);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_link_viewer);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
mMyFragment = (MyFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_frame);
if (mMyFragment == null) {
final String url = getIntent().getStringExtra("URL");
final String postData = getIntent().getStringExtra("POSTDATA");
mMyFragment = MyFragment.newInstance(url, postData);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_frame, mMyFragment)
.commitNow();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void finish() {
mMyFragment.cancelTasks();
super.finish();
}
}
Please let me know how to resolve the issue and not reload the webview but retain display on orientation change. Any help is appreciated.

onSaveInstanceState is not working

The last link is not opening while returning from other tab
and also onPause() is not working .it shows null pointer exception and app closes automatically whilie clicking other tab except first one .
fragment tab code
public class FragmentTab extends Fragment {
protected WebView myWebView;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_layout, container, false);
WebView myWebView = (WebView) v.findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return false;
}
});
if(savedInstanceState != null)
myWebView.restoreState(savedInstanceState);
else
myWebView.loadUrl("http://www.example.com");
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
myWebView.saveState(outState);
}
}
And Here are the MainActivity
public class MainActivity extends FragmentActivity {
private FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);
mTabHost.addTab(
mTabHost.newTabSpec("tab1").setIndicator(null,ContextCompat.getDrawable(this,R.drawable.home)),
FragmentTab.class, null);
mTabHost.addTab(
mTabHost.newTabSpec("tab2").setIndicator(null,ContextCompat.getDrawable(this,R.drawable.deals_offers)),
FragmentTab.class, null);
mTabHost.addTab(
mTabHost.newTabSpec("tab3").setIndicator(null,ContextCompat.getDrawable(this,R.drawable.profile)),
FragmentTab.class, null);
mTabHost.addTab(
mTabHost.newTabSpec("tab4").setIndicator(null, ContextCompat.getDrawable(this, R.drawable.menu)),
FragmentTab.class, null);
}
}
Use This Library : https://github.com/frankiesardo/icepick
remove protected from WebView
#State
WebView myWebView; // This will be automatically saved and restored
Add Following Line In Your Activity Method Rest Will Be Handled.
In OnCreate Method
#Override public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Icepick.restoreInstanceState(this, savedInstanceState);
}
In onSaveInstanceState
#Override public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
Icepick.saveInstanceState(this, outState);
}
Look like myWebView always null in your code:
public class FragmentTab extends Fragment {
protected WebView myWebView;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_layout, container, false);
myWebView = (WebView) v.findViewById(R.id.webview);
// instead of WebView myWebView = (WebView) v.findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return false;
}
});
if(savedInstanceState != null)
myWebView.restoreState(savedInstanceState);
else
myWebView.loadUrl("http://www.example.com");
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
myWebView.saveState(outState);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
myWebView.saveState(savedInstanceState);
}
#Override
public void onRestoreInstanceState(Bundle outState) {
super.onRestoreInstanceState(outState);
myWebView.restoreState(outState);
}
According to source code.
/**
* Restores the state of this WebView from the given Bundle. This method is
* intended for use in {#link android.app.Activity#onRestoreInstanceState}
* 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.
*
* #param inState the incoming Bundle of state
* #return the restored back/forward list or null if restoreState failed
*/
public WebBackForwardList restoreState(Bundle inState) {
checkThread();
return mProvider.restoreState(inState);
}

Adding ProgressBar into WebView Fragment

i'm finishing my app, is a simple app that contains some WebView Fragments and a Navigation Drawer, everything is OK, but I don't know how to add a progress bar while the WebView is loading a page, all I got is a blank screen before the page loads.
Here is my code...
HomeFragment.java
public class HomeFragment extends Fragment {
private WebView webView;
public HomeFragment() {
// Required empty public constructor
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mainView = (View) inflater.inflate(R.layout.fragment_my_fragment1, container, false);
WebView webView = (WebView)mainView.findViewById(R.id.webview);
webView.setWebViewClient(new MantenerDominioWeb());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setBuiltInZoomControls(false);
webView.getSettings().setSupportZoom(false);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setDomStorageEnabled(true);
webView.canGoBack();
webView.goBack();
webView.loadUrl("http://www.lfcchile.com/");
return mainView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onDetach() {
super.onDetach();
}
}
My WebViewClient class
public class MantenerDominioWeb extends WebViewClient {
private WebView webView;
public ProgressBar progressBarT4;
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().endsWith("lfcchile.com") || (Uri.parse(url).getHost().endsWith("thisisanfield.com")) || (Uri.parse(url).getHost().endsWith("liverpoolecho.co.uk")) || (Uri.parse(url).getHost().endsWith("liverpoolfc.com"))) {
return false;
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
view.getContext().startActivity(intent);
return true;
}
}
And my Frame XML
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context="com.lfcchile.MyFragment1">
<!-- TODO: Update blank fragment layout -->
<TextView android:layout_width="match_parent" android:layout_height="match_parent"
android:gravity="center"
android:text="#string/homefrag" />
<WebView
android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<ProgressBar
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:id="#+id/progressBar1"/>
</FrameLayout>
Any ideas please? I tried to put the progressBar "in front" of the WebView, but when the page is loaded the icon doesn't dissapear...
I believe it is not possible to put a progressbar because each site has a certain size, it would be difficult to measure it before finalizing the download page.
But you can place a pre-loader (loading) while the page is loaded and after the end you remove access for the user.
Use ProgressDialog:
public class HomeFragment extends Fragment {
private ProgressDialog progress;
private WebView webView;
public HomeFragment() {
// Required empty public constructor
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mainView = (View) inflater.inflate(R.layout.fragment_my_fragment1, container, false);
WebView webView = (WebView)mainView.findViewById(R.id.webview);
webView.setWebViewClient(new MantenerDominioWeb());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setBuiltInZoomControls(false);
webView.getSettings().setSupportZoom(false);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setDomStorageEnabled(true);
webView.canGoBack();
webView.goBack();
webView.loadUrl("http://www.lfcchile.com/");
progress = ProgressDialog.show(this, "Aguarde...",
"Processando sua solicitação.", true);
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
if (progress != null)
progress.dismiss();
}
});
return mainView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onDetach() {
super.onDetach();
}
}
Set your ProgressBar to visibility="gone" to start
In your WebViewClient subclass, override onPageStarted() to set the visibility of the ProgressBar to VISIBLE
In your WebViewClient subclass, override onPageFinished() to set the visibility of the ProgressBar to GONE
Create a WebChromeClient subclass overriding onProgressChanged() to update the progress value of the ProgressBar
Add the WebChromeClient subclass to the WebView by calling WebView.setWebChromeClient()

Non-static method 'onResume' Android Studio

I want to use a WebView for Youtube. When I try to compile it, I get this error "non-static method onResume & onPause cannot be referenced from a static context".
I have tried to use a rootView, but it didn't work ='(
public class vod extends Fragment {
public static final String TAG = "vod";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.vod, container, false);
WebView wv = (WebView)rootView.findViewById(R.id.webView2);
wv.getSettings().setJavaScriptEnabled(true);
wv.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
}
});
wv.setWebViewClient(
new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return false;
}
});
wv.loadUrl("https://www.youtube.com/user/XX");
wv.addJavascriptInterface(new WebSocketFactory(wv), "WebSocketFactory");
return rootView;
}
#Override
public void onResume()
{
super.onResume();
WebView.onResume();
}
#Override
public void onPause()
{
super.onPause();
WebView.onPause();
}
}
I don't know how to resolve this. I need your help =)
Thank you =)
Make your wv variable as class member and use it then like this:
private WebView wv;
// onCreateView ...
#Override
public void onResume()
{
super.onResume();
wv.onResume();
}
And same with onPause...
You are trying to call the non-static methods onResume and onPause from WebView, but are accessing them in a static way. Either way, what you are doing makes no sense. Calling lifecycle methods manually is unnecessary and should be avoided. You can get rid of your onResume and onPause methods if you are only calling super.
If you want to call onResume and onPause from the Fragment, then use
wv.onResume and wv.onPause.
I modified your code below to solve your problem:
public class vod extends Fragment {
public static final String TAG = "vod";
private WebView wv;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.vod, container, false);
wv = (WebView)rootView.findViewById(R.id.webView2);
wv.getSettings().setJavaScriptEnabled(true);
wv.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
}
});
wv.setWebViewClient(
new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return false;
}
});
wv.loadUrl("https://www.youtube.com/user/XX");
wv.addJavascriptInterface(new WebSocketFactory(wv), "WebSocketFactory");
return rootView;
}
#Override
public void onResume()
{
super.onResume();
wv.onResume();
}
#Override
public void onPause()
{
super.onPause();
wv.onPause();
}
}
Also, class names should start with a capital letter, by convention. So call your Fragment Vod instead of vod.

WebView Becoming Null

I have a fragment which displays a WebView, in order to retain the website that is being shown I save the state like this:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/*Saves the currently displayed webpage and the browser history*/
webView.saveState(outState);
}
Then I restore it like this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_page_detail,
container, false);
webView = (WebView) rootView.findViewById(R.id.page_detail_webview);
progressBar = (ProgressBar) rootView.findViewById(R.id.op_progress);
webView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
progressBar.setVisibility(View.VISIBLE);
progressBar.setProgress(progress);
if (progress == 100) {
progressBar.setVisibility(View.GONE);
}
}
});
webView.setWebViewClient(new StockStreamWebViewClient());
webView.getSettings().setBuiltInZoomControls(true);
/*Restores the saved browser history if there is any*/
if (savedInstanceState != null) {
webView.restoreState(savedInstanceState);
} else if (mItem != null) {
webView.loadUrl(mItem.content);
}
return rootView;
}
To allow the user to go back in the WebView I have this code in my Activity:
#Override
public void onBackPressed() {
if (!clientFragment.onBackPressed()) {
super.onBackPressed();
}
}
}
And this code in my Fragment:
public boolean onBackPressed() {
if (webView != null && webView.canGoBack()) {
webView.goBack();
return true;
} else {
return false;
}
}
When I rotate my device the screen draws correctly and the WebView restores it's previous page, but when I press back the WebView is null.
Why is this happening?
Thanks,
ANkh
SimonVT in the #android-dev correctly suggested that I might be making calls to a null or new Fragment from my Activity.
So I added this code to my Activity to save the ID of the Fragment:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (clientFragment != null) {
outState.putInt(CLIENT_FRAGMENT_ID, clientFragment.getId());
}
}
And this code to restore the reference to the correct Fragment:
if (savedInstanceState != null
&& savedInstanceState.containsKey(CLIENT_FRAGMENT_ID)) {
clientFragment = (PageDetailFragment) getSupportFragmentManager()
.findFragmentById(savedInstanceState.getInt(CLIENT_FRAGMENT_ID));
}
PageDetailFragment is my extended Fragment.
Thanks,
ANkh

Categories

Resources