https://hantoluvcoding.tistory.com/86
[Android] WebView Url 여러개 띄우기(feat.Java)
한 웹뷰에 여러 url을 띄우는 작업을 하게 되었는데 onPagedFinish에 다음 url로드를 달아 놓고 닫기 버튼을 누르니scripts may close only the windows that were opened by them. 라는 로그가 뜨며 window.close()가 작동
hantoluvcoding.tistory.com
전편에 이어서..
새로운 요구 사항이 생겼는데 바로 웹뷰에 레디우스를 적용하는 것이었다. xml에서 아무리 수정해도 적용이 되지 않고 있었다. 결론부터 말하자면 webview 클래스를 상속받은 후 onDraw를 오버라이드하여 처리하였다.
CustomWebView 클래스 - 하드웨어 가속화 해제
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.webkit.WebView;
public class CustomWebView extends WebView {
private Path path = new Path();
private float cornerRadius = 50f; // 라운드 코너 반지름 (원하는 값으로 조정)
public CustomWebView(Context context) {
super(context);
init();
}
public CustomWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setLayerType(LAYER_TYPE_SOFTWARE, null);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
path.reset();
RectF rect = new RectF(0, 0, w, h);
path.addRoundRect(rect, cornerRadius, cornerRadius, Path.Direction.CW);
path.close();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.clipPath(path);
super.onDraw(canvas);
}
}
onDraw가 호출되기 위해서는 하드웨어 가속을 비활성해야한다. 하드웨어 가속이란 GPU(Graphics Processing Unit)을 사용하여 뷰를 그리는 과정을 가속화하는 기술이다. 복잡한 그래픽 과정이 더빠르고 효율적으로 처리된다. 이것이 활성화 되면 뷰 그리기 작업이 GPU로 위임되는데 이경우에 onDraw가 호출되지 않고 직접 GPU가 뷰를 그려준다. 특히 clipPath와 같은 복잡한 그리기 작업은 가속에서 지원되지 않을 수 있따. 그래서 onDraw의 호출을 보장하기 위해서 이를 비활성화 하는 것이다.
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); << 이 코드가 바로 그 코드이다.
하지만, 이는 성능 저하가 발생할 수 있으므로, 가능한 경우에는 ViewOutLineProvider를 사용하는 것이 좋다.
CustomWebView 클래스 - ViewOutLineProvider
import android.content.Context;
import android.graphics.Outline;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.webkit.WebView;
import android.os.Build;
public class CustomWebView extends WebView {
private float cornerRadius = 10f; // 라운드 코너 반지름 (원하는 값으로 조정)
public CustomWebView(Context context) {
super(context);
init();
}
public CustomWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), cornerRadius);
}
});
setClipToOutline(true);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
invalidateOutline();
}
}
이는 하드웨어 가속을 유지하면서 효율적이고 간단한 방법이다. 하지만 안드로이드 API 레벨 21이상에서 사용할 수 있으다. 하지만 성능저하에 아무런 영향을 주지 않으며 코드가 간결하고 유지보수가 쉽다는 장점이 있다.
두 방법의 차이점
항목하드웨어 가속화 해제ViewOutlineProvider
동작 방식 | CPU에서 그리기 작업 처리 | GPU에서 외곽선 및 클리핑 처리 |
성능 | 성능 저하 가능성 (CPU 사용) | 성능 우수 (GPU 사용) |
API 지원 | 모든 안드로이드 버전 지원 | API 레벨 21 이상만 지원 |
사용 편의성 | onDraw()에서 커스텀 그리기 필요 | 간단한 외곽선 설정만으로 적용 가능 |
그림자 효과 | 별도 구현 필요 | 외곽선과 함께 그림자 효과 적용 가능 |
복잡한 그리기 작업 | 가능 (예: clipPath()) | 제한적 (단순한 라운드 코너에 적합) |
어떤 방법을 사용하는 것이 합리적인가?
- ViewOutlineProvider를 사용하는 경우:
- API 레벨 21 이상을 타겟으로 하는 경우.
- 성능이 중요한 경우 (예: 애니메이션이 많거나 복잡한 UI).
- 간단한 라운드 코너와 그림자 효과를 적용하려는 경우.
- 코드의 간결성과 유지보수를 우선시하는 경우.
- 하드웨어 가속화 해제를 사용하는 경우:
- 하위 버전(API 레벨 21 미만)을 지원해야 하는 경우.
- 복잡한 그리기 작업(예: 비균일한 라운드 코너, 커스텀 경로)이 필요한 경우.
- 성능 저하를 감수하더라도 모든 안드로이드 버전에서 동일한 동작을 보장해야 하는 경우.
>> 하지만 현재 API 레벨 21(안드로이드 5.0, 롤리팝) 이상의 기기가 대부분을 차지하고 있지 때문에 걱정할 필요는 없을 것 같다. (전체 기기의 1% 미만)
CustomWebView 사용(fragment 예시)
@SuppressLint("SetJavaScriptEnabled")
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, "onViewCreated()");
// CustomWebView 생성
CustomWebView webView = new CustomWebView(requireContext());
webView.setWebViewClient(new WebViewClient());
webView.setWebChromeClient(new CustomWebChromeClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setSupportMultipleWindows(true);
// WebView를 컨테이너에 추가
webViewContainer.addView(webView);
currentWebView = webView;
loadNextUrl();
}
'Android' 카테고리의 다른 글
[Android] Intent (0) | 2025.02.28 |
---|---|
[Android] Layout은 어떻게 그릴까 (0) | 2025.02.26 |
[Android] WebView Url 여러개 띄우기(feat.Java) (0) | 2025.02.25 |
[Android] Firebase Push Token (feat. WebView) (0) | 2025.02.19 |
[Android] 발행 - 구독 패턴 (브로드캐스트, 이벤트버스) (1) | 2025.02.18 |