Android - Preventing WebView reload on Rotate - java

When I rotate my screen, the WebView reloads the whole page. I can't have this since some of my content contains dynamic/random material. Currently when rotated the screen reloads the original URL from the loadUrl() method.
Any idea what's wrong with my code?
MainActivity.java
package com.mark.myapp;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends Activity {
WebView web;
String webURL = "http://www.google.co.uk/";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null)
((WebView)findViewById(R.id.web)).restoreState(savedInstanceState);
web = (WebView) findViewById(R.id.web);
web.getSettings().setJavaScriptEnabled(true);
web.loadUrl(webURL);
web.setPadding(0, 0, 0, 0);
web.getSettings().setLoadWithOverviewMode(true);
web.getSettings().setUseWideViewPort(true);
web.getSettings().setSupportZoom(true);
web.getSettings().setBuiltInZoomControls(true);
web.setWebViewClient(new HelloWebViewClient());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
private class HelloWebViewClient extends WebViewClient {
public boolean shouldOverrideUrlLoading(WebView web, String url) {
web.loadUrl(url);
return true;
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) {
web.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mark.myapp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

I think the main problem is that you call web.loadUrl(webURL); also when savedInstanceState != null
EDIT
Try:
if (savedInstanceState == null)
{
web.loadUrl(webURL);
}
EDIT2: You also need the onSaveInstanceState and onRestoreInstanceState override.
#Override
protected void onSaveInstanceState(Bundle outState )
{
super.onSaveInstanceState(outState);
web.saveState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
web.restoreState(savedInstanceState);
}
Note: Please also add in your AndroidManifest.xml in your Activity
android:configChanges="orientation|screenSize"
Thanks

EDIT: Found a more suitable solution.
NEW:
In AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.Example.WebviewSample">
<application
<activity android:name=".WebViewActivity"
<!-- ADD THIS -->
android:configChanges="orientation|screenSize">
</activity>
</application>
</manifest>
In WebViewActivity.java file add this to onCreate() method
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
wView = (WebView) findViewById(R.id.webView);
if (savedInstanceState == null) {
wView.loadUrl("https://google.com");
}
}
also update onSaveInstanceState
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
wView.saveState(outState);
}
and onRestoreInstanceState
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
wView.restoreState(savedInstanceState);
}
OLD:
No java coding needed.
use this in your manifest file.
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
like:
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.Example.WebviewSample.webviewsample"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

in tag (manifest)
android:configChanges="orientation|screenSize"

Adding android:configChanges="orientation|screenSize" in manifest works for me
<activity
android:name="com.example.HelloWorld.WebActivity"
android:label="#string/title_activity_web"
android:configChanges="orientation|screenSize" >
</activity>

I don't believe this will work anymore. In my case, restoring state using WebView.restore(Bundle savedInstanceState) still triggers a reload of the url.
Looking at the docs for restoreState() you'll see it says:
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.
and
Please note that this method no longer restores the display data for this WebView.
Props to #e4c5 for pointing me in the right direction in his answer
And of course, the extreme course of action would be to prevent orientation changes from triggering activity destruction/creation. Documentation for how to do this is here

Add this code in Manifest
<activity
...
android:configChanges="orientation|screenSize">

Try this in your manifest file:
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"

Place this in the Manifest.xml file activity:
android:configChanges="orientation|screenSize"
Here is an example:
<activity android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar"
android:configChanges="orientation|screenSize">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

Override the onConfigChange method to avoid reloading data on orientation change
on your activity in AndroidMainfest file.
android:configChanges="orientation|keyboardHidden"
and have these as well in your WebView settings
webview.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
webview.loadUrl("Your URL To Load");

As quoted here,
Caution: Beginning with Android 3.2 (API level 13), the "screen size"
also changes when the device switches between portrait and landscape
orientation. Thus, if you want to prevent runtime restarts due to
orientation change when developing for API level 13 or higher (as
declared by the minSdkVersion and targetSdkVersion attributes), you
must include the "screenSize" value in addition to the "orientation"
value. That is, you must decalare
android:configChanges="orientation|screenSize". However, if your
application targets API level 12 or lower, then your activity always
handles this configuration change itself (this configuration change
does not restart your activity, even when running on an Android 3.2 or
higher device).
setting android:configChanges="orientation|screenSize" on your activity will resolve this issue.
Also, take note of the following
Remember: When you declare your activity to handle a configuration
change, you are responsible for resetting any elements for which you
provide alternatives. If you declare your activity to handle the
orientation change and have images that should change between
landscape and portrait, you must re-assign each resource to each
element during onConfigurationChanged().

This solution works well for me:
(1) In AndroidManifest.xml add this line
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
Like this (and like the answers above)
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
(2) Then in MainActivity.java verify savedInstanceState
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainContext = getApplicationContext();
----
myWebView = (WebView) findViewById(R.id.webView);
prepareWebView();
myWebView.addJavascriptInterface(myJavaScriptInterface, "WEB2Android");
if (savedInstanceState == null) {
myWebView.post(new Runnable() {
#Override
public void run() {
myWebView.loadUrl("http://www.appbiz.ro/foto_konta");
}
});
}
----
}
(3) and then:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
protected void onSaveInstanceState(Bundle outState )
{
super.onSaveInstanceState(outState);
myWebView.saveState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
myWebView.restoreState(savedInstanceState);
}

Add this in Androidmanifest.xml:
<activity android:name=".MyActivity"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
Now, when one of these configurations change, MyActivity does not restart. Instead, MyActivity receives a call to onConfigurationChanged().
Add this:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
}
else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}

Related

Trying to Make Pop-Up Window/Overlay in Android Studio (Java)

I am trying to create a pop-up window/overlay in Android Studio with 2 activities. When a certain button (the green plus button in the first picture below) is pressed, it will start a second activity at a smaller size with a different layout (.xml) file. When the second activity is declared in the AndroidManifest.xml, it uses a custom theme I have created to make the first activity appear under it, however, it is not working properly.
Here are pictures of both activites:
First Activity -
Second Activity -
Here is the code:
MainActivity -
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
Util.initScreenRes(this); // initializes screen resolution for later pop-up window sizing
}
public void ibAddOnClick(View view){
startActivity(new Intent(MainActivity.this, AddPopUpActivity.class));
}
}
AddPopUpActivity -
public class AddPopUpActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_popup_activity);
getWindow().setLayout((int) (Util.screenRes.x * 0.8), (int) (Util.screenRes.y * 0.5));
}
}
Util -
public class Util {
public static Point screenRes;
public static void initScreenRes(Activity a){
final DisplayMetrics dm = new DisplayMetrics();
a.getWindowManager().getDefaultDisplay().getMetrics(dm);
screenRes = new Point(dm.widthPixels, dm.heightPixels);
}
}
Lastly, here is the AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="App.ProgressTracker">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.ProgressTracker">
<activity
android:name="App.FrontEnd.MainActivity"
android:label="#string/app_name"
android:theme="#style/Theme.ProgressTracker.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="App.FrontEnd.AddPopUpActivity"
android:label="ProgressTracker"
android:theme="#style/Theme.ProgressTracker.PopUp">
</activity>
</application>
</manifest>
For reference, I have used this tutorial on YouTube for the way I went about this:
https://www.youtube.com/watch?v=fn5OlqQuOCk&ab_channel=FilipVujovic
I'd appreciate any help on this. Thank you in advance!
In the AndroidManifest.xml set the theme of the pop up activity to
android:theme="#android:style/Theme.Dialog"

How to implement search interface in android using searchView widget

I have completely followed the Docs on this regard.
I made searchable.xml file
added new activity to handle the query once search is made.
I updated the manifest file accordingly.
My problem is that the new activity is not being called at all as if there is something wrong with the manifest.
Here's the xml file:
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="#string/app_name"
android:hint="#string/search_hint" >
</searchable>
Here's the manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sultanraja.notes">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".SearchResultsActivity">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
<activity android:name=".NoteActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
And here's the new activity code meanwhile:
public class SearchResultsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_results);
handleIntent(getIntent());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
Toast.makeText(getApplicationContext(),"your Query is " + query, Toast.LENGTH_SHORT).show();
//use the query to search your data somehow
}
}
}
The Toast is never happening and a breakpoint in the onCreate method is never reached.
what is the problem?
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
if(list.contains(query)){
adapter.getFilter().filter(query);
}else{
Toast.makeText(MainActivity.this, "No Match found",Toast.LENGTH_LONG).show();
}
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
// adapter.getFilter().filter(newText);
return false;
}
});
I found the problem in the manifest file:
I added the following:
<meta-data
android:name="android.app.default_searchable"
android:value=".SearchResultsActivity" />
this part was added to mainActivity and that was not part of the documentation.
thanks.

How do i check Rotate Your Device programmatically?

I want to load one url into my webview, Its a Casino game. But when i open the app it show "Please Rotate Your Device" in a black screen.
How i can check that message programmatically and set the screen orientation landscape instead of user rotating their device ?
My MainActivity Code :
package com.mob.wunderin.oapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebSettings;
import android.content.pm.ActivityInfo;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
WebView webView = findViewById(R.id.myWebview);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.loadUrl("http://deuceswildcards.site/wildcards.php?app=fun&Gtype=poker#/main");
getSupportActionBar().setDisplayShowTitleEnabled(false);
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mob.wunderin.oapp">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
The Output :
Click here for Output Image
Please help me to check the "Rotate your device" message and set the screen orientation to landscape programatically ?
Just add
android:screenOrientation="sensorLandscape"
to your Activity tag. It will force the device into landscape while that Activity is displayed, while allowing either landscape orientation (based on the device's sensor readings).
<activity android:name=".MainActivity"
android:screenOrientation="sensorLandscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
EDIT
Remove this line from your Activity as well:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
There is a way to do this programmatically in Java. In your onCreate method, try this:
#Override
public void onCreate(Bundle savedInstanceState) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
Or, you can do it through your Manifest file like this:
<activity android:name=".MainActivity"
android:label="#string/app_name"
android:screenOrientation="landscape">
To check the current screen orientation: do the following:
int orientation = MainActivity.getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
//The orientation is in portrait so it will set it to landscape
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}else {
//The orientation is now landscape which is what you want.
}

How can I stop my Android webview app from refreshing when I rotate my phone?

I am trying to complete my org's first app (we lost our dev due to health issues) and it seems to be working except that when the phone is rotated it refreshes back to the login screen. I realize that this question was answered previously here but this information is 4 years old and I get some compiling errors.
Here is our code - I really hope that someone can help as I am completely new to this and not really a dev myself, but I feel like what we have is close to a solution.
Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ca.ruffarc.flytest">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/Theme.AppCompat.NoActionBar">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Main Activity:
package ca.ruffarc.flytest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webview);
webView.setWebViewClient(new MyBrowser());
webView.getSettings().setLoadsImagesAutomatically(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.loadUrl("https://flyapp.ca/en/authentication");
}
private class MyBrowser extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
else
{
finish();
}
return super.onKeyDown(keyCode, event);
}
}
If you look at the AndroidManifest.xml from the link you gave you will see that <activity> has property android:configChanges="orientation|keyboardHidden".
So you need to do the same for your activity in the manifest with small difference:
android:configChanges="orientation|screenSize|keyboardHidden".
Here's a full example of Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ca.ruffarc.flytest">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/Theme.AppCompat.NoActionBar">
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

Launcher activity not found

So I am redoing my app so that there will be an animation on the start screen of the app. The only problem is it seems you cannot start an app with a view class. At least I'm not really sure if you can. Here is my code. With this code i get a launcher activity not found in the console?
public class SplashLaunch extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.splashlaunch);
final Main d = new Main(this);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
setContentView(d);
}
}, 5000);
}
}
Here is the manifest file. I have a feeling that I'm going to need to change this.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.Tripps.thesimplegame"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="12"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".SplashLaunch"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.SPLASHLAUNCH" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".YouFailed"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.YOUFAILED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
Likely somewhere in your launcher activity you have an onCreate method:
public class YourActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.foobar);
}
}
Just change the setContentView to your custom view:
public class YourActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
MyCustomView view = new MyCustomView(this);
setContentView(view);
}
}
The Activity that you want to start when the app first starts MUST have the following Intent filter:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

Categories