문제는 회전 후의 성능입니다. WebView는 페이지를 다시로드해야하며 약간 지루할 수 있습니다.
매번 소스에서 페이지를 다시로드하지 않고 방향 변경을 처리하는 가장 좋은 방법은 무엇입니까?
문제는 회전 후의 성능입니다. WebView는 페이지를 다시로드해야하며 약간 지루할 수 있습니다.
매번 소스에서 페이지를 다시로드하지 않고 방향 변경을 처리하는 가장 좋은 방법은 무엇입니까?
답변:
오리엔테이션 변경시 WebView를 다시로드하지 않으려면 Activity 클래스에서 onConfigurationChanged를 대체하십시오.
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
그리고 매니페스트에서 android : configChanges 속성을 설정하십시오.
<activity android:name="..."
android:label="@string/appName"
android:configChanges="orientation|screenSize"
자세한 내용은 다음을 참조 하십시오 :
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
https://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges
configChanges
속성이 서브 클래스 활동에 추가됩니다. 2) 앱이 여러 프로젝트에 의존하는 경우 해당 configChanges
속성이 의존성 트리의 상단 (활동 클래스를 포함하는 프로젝트가 아닐 수도 있음).
onConfigurationChanged
메서드 재정의는 쓸모가 없습니다.
편집 :이 방법은 더 이상 문서에 명시된대로 작동하지 않습니다
원래 답변 :
이것은 onSaveInstanceState(Bundle outState)
활동 을 덮어 쓰고 saveState
웹뷰에서 호출하여 처리 할 수 있습니다 .
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
그런 다음 웹보기가 다시 팽창 된 후 onCreate에서 이것을 복구하십시오.
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blah);
if (savedInstanceState != null)
((WebView)findViewById(R.id.webview)).restoreState(savedInstanceState);
}
이에 대한 가장 좋은 대답은 여기에있는 Android 문서를 따르는 것입니다. 기본적으로 이것은 Webview가 다시로드되지 못하게합니다.
<activity android:name=".MyActivity"
android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection|uiMode"
android:label="@string/app_name">
선택적으로 , onConfigurationChanged
활동 을 재정 의하여 이상 현상을 수정 (있는 경우) 할 수 있습니다 .
@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();
}
}
내가 사용하려고했습니다 onRetainNonConfigurationInstance을 (복귀 웹보기를 다시 그것을 점점) getLastNonConfigurationInstance 시 에서 onCreate 하고 재 할당.
아직 작동하지 않는 것 같습니다. 나는 도울 수 없지만 내가 정말 가까이 있다고 생각합니다! 지금까지 빈 / 백색 배경 WebView를 얻었습니다. 를 . 누군가가 이것을 결승선을 지나서 밀어 낼 수 있기를 바랍니다.
어쩌면 WebView를 전달해서는 안됩니다 . 아마도 WebView 내에서 객체 입니까?
내가 좋아하는 것이 아닌 다른 방법은 활동에서 이것을 설정하는 것입니다.
android:configChanges="keyboardHidden|orientation"
... 그리고 여기서 거의 아무것도하지 않습니다.
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// We do nothing here. We're only handling this to keep orientation
// or keyboard hiding from causing the WebView activity to restart.
}
작동하지만 모범 사례 로 간주되지 않을 수 있습니다 .
한편, 회전에 따라 자동으로 업데이트하려는 단일 ImageView 도 있습니다 . 이것은 매우 쉬운 것으로 판명되었습니다. 내에서 res
폴더, 내가 가진 drawable-land
및 drawable-port
보류 가로 / 세로 변화에, 나는 사용 R.drawable.myimagename
에 대한 이미지 뷰 소스와 안드로이드의 "옳은 않습니다"- 야호!
... 구성 변경을 볼 때를 제외하고는 변경되지 않습니다. :(
그래서 나는 확률이 높습니다. onRetainNonConfigurationInstance를 사용 하면 ImageView 회전이 작동하지만 WebView 지속성이 작동 하지 않거나 onConfigurationChanged를 사용 하면 WebView 가 안정적으로 유지되지만 ImageView 는 업데이트되지 않습니다. 무엇을해야합니까?
마지막 참고 사항 : 제 경우에는 방향 강제 적용이 용납되지 않습니다. 우리는 실제로 회전을 정상적으로 지원하고 싶습니다. 안드로이드 브라우저 앱의 작동 방식을 좋아하십시오! ;)
방향 변경 및 회전시 WebView 다시로드 방지를 처리하는 가장 좋은 방법입니다.
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
이를 염두에두고 방향을 변경할 때마다 onCreate ()가 호출되지 않도록하려면 추가해야합니다. android:configChanges="orientation|screenSize" to the AndroidManifest.
또는 그냥 ..
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"`
조금 늦었지만 고맙지 만 솔루션을 개발할 때 사용한 답변입니다.
AndroidManifest.xml
<activity
android:name=".WebClient"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize" <--- "screenSize" important
android:label="@string/title_activity_web_client" >
</activity>
WebClient.java
public class WebClient extends Activity {
protected FrameLayout webViewPlaceholder;
protected WebView webView;
private String WEBCLIENT_URL;
private String WEBCLIENT_TITLE;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_client);
initUI();
}
@SuppressLint("SetJavaScriptEnabled")
protected void initUI(){
// Retrieve UI elements
webViewPlaceholder = ((FrameLayout)findViewById(R.id.webViewPlaceholder));
// Initialize the WebView if necessary
if (webView == null)
{
// Create the webview
webView = new WebView(this);
webView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
webView.setScrollbarFadingEnabled(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setPluginState(android.webkit.WebSettings.PluginState.ON);
webView.getSettings().setLoadsImagesAutomatically(true);
// Load the URLs inside the WebView, not in the external web browser
webView.setWebViewClient(new SetWebClient());
webView.setWebChromeClient(new WebChromeClient());
// Load a page
webView.loadUrl(WEBCLIENT_URL);
}
// Attach the WebView to its placeholder
webViewPlaceholder.addView(webView);
}
private class SetWebClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.web_client, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}else if(id == android.R.id.home){
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (webView.canGoBack()) {
webView.goBack();
return;
}
// Otherwise defer to system default behavior.
super.onBackPressed();
}
@Override
public void onConfigurationChanged(Configuration newConfig){
if (webView != null){
// Remove the WebView from the old placeholder
webViewPlaceholder.removeView(webView);
}
super.onConfigurationChanged(newConfig);
// Load the layout resource for the new configuration
setContentView(R.layout.activity_web_client);
// Reinitialize the UI
initUI();
}
@Override
protected void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
// Save the state of the WebView
webView.saveState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
// Restore the state of the WebView
webView.restoreState(savedInstanceState);
}
}
2015 년이며 많은 사람들이 아직도 Jellybean, KK 및 Lollipop 전화에서 작동하는 솔루션을 찾고 있습니다. 이후 많은 어려움을 겪고 난 당신이 방향을 변경 한 후 그대로 웹보기를 보존 할 수있는 방법을 발견했다. 내 전략은 기본적으로 웹보기를 다른 클래스의 별도 정적 변수에 저장하는 것입니다. 그런 다음 회전이 발생하면 활동에서 웹보기를 분리하고 방향이 끝날 때까지 기다렸다가 웹보기를 활동에 다시 연결하십시오. 예를 들어 ... 먼저 이것을 MANIFEST에 넣으십시오 (keyboardHidden 및 키보드는 선택 사항입니다).
<application
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:name="com.myapp.abc.app">
<activity
android:name=".myRotatingActivity"
android:configChanges="keyboard|keyboardHidden|orientation">
</activity>
SEPARATE APPLICATION CLASS에서 다음을 입력하십시오.
public class app extends Application {
public static WebView webview;
public static FrameLayout webviewPlaceholder;//will hold the webview
@Override
public void onCreate() {
super.onCreate();
//dont forget to put this on the manifest in order for this onCreate method to fire when the app starts: android:name="com.myapp.abc.app"
setFirstLaunch("true");
}
public static String isFirstLaunch(Context appContext, String s) {
try {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
return prefs.getString("booting", "false");
}catch (Exception e) {
return "false";
}
}
public static void setFirstLaunch(Context aContext,String s) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(aContext);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("booting", s);
editor.commit();
}
}
활동에서 다음을 입력하십시오.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(app.isFirstLaunch.equals("true"))) {
app.setFirstLaunch("false");
app.webview = new WebView(thisActivity);
initWebUI("www.mypage.url");
}
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
restoreWebview();
}
public void restoreWebview(){
app.webviewPlaceholder = (FrameLayout)thisActivity.findViewById(R.id.webviewplaceholder);
if(app.webviewPlaceholder.getParent()!=null&&((ViewGroup)app.webview.getParent())!=null) {
((ViewGroup) app.webview.getParent()).removeView(app.webview);
}
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT);
app.webview.setLayoutParams(params);
app.webviewPlaceholder.addView(app.webview);
app.needToRestoreWebview=false;
}
protected static void initWebUI(String url){
if(app.webviewPlaceholder==null);
app.webviewPlaceholder = (FrameLayout)thisActivity.findViewById(R.id.webviewplaceholder);
app.webview.getSettings().setJavaScriptEnabled(true); app.webview.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
app.webview.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
app.webview.getSettings().setSupportZoom(false);
app.webview.getSettings().setBuiltInZoomControls(true);
app.webview.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
app.webview.setScrollbarFadingEnabled(true);
app.webview.getSettings().setLoadsImagesAutomatically(true);
app.webview.loadUrl(url);
app.webview.setWebViewClient(new WebViewClient());
if((app.webview.getParent()!=null)){//&&(app.getBooting(thisActivity).equals("true"))) {
((ViewGroup) app.webview.getParent()).removeView(app.webview);
}
app.webviewPlaceholder.addView(app.webview);
}
마지막으로 간단한 XML :
<RelativeLayout 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=".myRotatingActivity">
<FrameLayout
android:id="@+id/webviewplaceholder"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
솔루션에서 개선 할 수있는 몇 가지 사항이 있지만 이미 많은 시간을 보냈습니다. 예 : SharedPreferences 스토리지를 사용하는 대신 처음으로 활동이 시작되었는지 확인하는 더 짧은 방법. 이 접근 방식은 URL에 반영되지 않은 그대로의 웹뷰 (afaik), 텍스트 상자, 레이블, UI, 자바 스크립트 변수 및 탐색 상태를 유지합니다.
업데이트 : 현재 전략은 분리 할 때 조각이 유지되지 않고 WebView 인스턴스를 응용 프로그램 클래스로 이동하고 Josh가 재개 할 때 다시 연결하는 것입니다. 응용 프로그램이 닫히지 않도록하려면 사용자가 응용 프로그램간에 전환 할 때 상태를 유지하려면 포 그라운드 서비스를 사용해야합니다.
프래그먼트를 사용하는 경우 WebView의 인스턴스 유지를 사용할 수 있습니다. 웹보기는 클래스의 인스턴스 멤버로 유지됩니다. 그러나 웹 컨테이너를 OnCreateView에 첨부하고 OnDestroyView 전에 분리하여 상위 컨테이너로 파괴되지 않도록해야합니다.
class MyFragment extends Fragment{
public MyFragment(){ setRetainInstance(true); }
private WebView webView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = ....
LinearLayout ll = (LinearLayout)v.findViewById(...);
if (webView == null) {
webView = new WebView(getActivity().getApplicationContext());
}
ll.removeAllViews();
ll.addView(webView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return v;
}
@Override
public void onDestroyView() {
if (getRetainInstance() && webView.getParent() instanceof ViewGroup) {
((ViewGroup) webView.getParent()).removeView(webView);
}
super.onDestroyView();
}
}
PS 크레딧은 kcoppock 답변으로
'SaveState ()'에 대해서는 공식 문서 에 따라 더 이상 작동하지 않습니다. .
이 방법은 더 이상이 WebView의 표시 데이터를 저장하지 않습니다. restoreState (Bundle)가 호출되지 않은 경우 이전 동작으로 인해 파일이 누출 될 수 있습니다.
setRetainInstance
Fragment를 유지 하면서 뷰 (및 WebView)는 여전히 파손됩니다.
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
}
이 방법은 모든 활동에서 재정의 될 수 있습니다. 기본적으로 활동을 만들거나 삭제할 때마다 화면 방향이 변경 될 때 활동이 파괴되고 백그라운드에서 다시 생성 될 때마다 기본적으로 값을 저장하고 복원 할 수 있으므로이 방법을 사용할 수 있습니다 변경하는 동안 임시 저장 / 복원 상태로
다음 두 가지 방법을 자세히 살펴보고 이것이 솔루션에 적합한 지 확인해야합니다.
http://developer.android.com/reference/android/app/Activity.html
이전 Activity
참조 를 누설 하지 않고 configChanges
.. 을 설정 하지 않고이 작업을 수행하는 가장 좋은 솔루션 은 MutableContextWrapper 를 사용하는 것 입니다.
나는 이것을 여기에 구현했다 : https://github.com/slightfoot/android-web-wrapper/blob/48cb3c48c457d889fc16b4e3eba1c9e925f42cfb/WebWrapper/src/com/example/webwrapper/BrowserActivity.java
이것은 나를 위해 일한 유일한 것입니다 (저장 인스턴스 상태를 사용 onCreateView
했지만 신뢰할 수는 없었습니다).
public class WebViewFragment extends Fragment
{
private enum WebViewStateHolder
{
INSTANCE;
private Bundle bundle;
public void saveWebViewState(WebView webView)
{
bundle = new Bundle();
webView.saveState(bundle);
}
public Bundle getBundle()
{
return bundle;
}
}
@Override
public void onPause()
{
WebViewStateHolder.INSTANCE.saveWebViewState(myWebView);
super.onPause();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
ButterKnife.inject(this, rootView);
if(WebViewStateHolder.INSTANCE.getBundle() == null)
{
StringBuilder stringBuilder = new StringBuilder();
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(getActivity().getAssets().open("start.html")));
String line = null;
while((line = br.readLine()) != null)
{
stringBuilder.append(line);
}
}
catch(IOException e)
{
Log.d(getClass().getName(), "Failed reading HTML.", e);
}
finally
{
if(br != null)
{
try
{
br.close();
}
catch(IOException e)
{
Log.d(getClass().getName(), "Kappa", e);
}
}
}
myWebView
.loadDataWithBaseURL("file:///android_asset/", stringBuilder.toString(), "text/html", "utf-8", null);
}
else
{
myWebView.restoreState(WebViewStateHolder.INSTANCE.getBundle());
}
return rootView;
}
}
WebView 상태에 대한 Singleton 홀더를 만들었습니다. 응용 프로그램 프로세스가 존재하는 한 상태가 유지됩니다.
편집 : loadDataWithBaseURL
필요하지 않았습니다, 그냥 잘 작동했습니다.
//in onCreate() for Activity, or in onCreateView() for Fragment
if(WebViewStateHolder.INSTANCE.getBundle() == null) {
webView.loadUrl("file:///android_asset/html/merged.html");
} else {
webView.restoreState(WebViewStateHolder.INSTANCE.getBundle());
}
비록 이것을 읽었지만 쿠키와 잘 작동하지는 않습니다.
이 시도
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
private WebView wv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wv = (WebView) findViewById(R.id.webView);
String url = "https://www.google.ps/";
if (savedInstanceState != null)
wv.restoreState(savedInstanceState);
else {
wv.setWebViewClient(new MyBrowser());
wv.getSettings().setLoadsImagesAutomatically(true);
wv.getSettings().setJavaScriptEnabled(true);
wv.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
wv.loadUrl(url);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
wv.saveState(outState);
}
@Override
public void onBackPressed() {
if (wv.canGoBack())
wv.goBack();
else
super.onBackPressed();
}
private class MyBrowser extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}
이 페이지는 내 문제를 해결하지만 처음에는 약간 변경해야합니다.
protected void onSaveInstanceState(Bundle outState) {
webView.saveState(outState);
}
이 부분은 나에게 약간의 문제가 있습니다. 두 번째 방향 변경시 응용 프로그램이 null 포인터로 종료되었습니다.
이것을 사용하여 그것은 나를 위해 일했다 :
@Override
protected void onSaveInstanceState(Bundle outState ){
((WebView) findViewById(R.id.webview)).saveState(outState);
}
이것을 시도해야합니다 :
onServiceConnected
방법, 웹보기를 얻고 호출 setContentView
하여 웹보기를 렌더링하는 방법.나는 그것을 테스트했고 XWalkView 또는 GeckoView와 같은 다른 WebViews에서는 작동하지 않습니다.
@Override
protected void onSaveInstanceState(Bundle outState )
{
super.onSaveInstanceState(outState);
webView.saveState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
webView.restoreState(savedInstanceState);
}
나는이 해결책을 좋아한다 http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/
그것에 따르면 우리는 동일한 WebView 인스턴스를 재사용합니다. 구성 변경시 탐색 기록 및 스크롤 위치를 저장할 수 있습니다.