2016-12-21 1 views
2

HTML 조각을 WebView에 렌더링 한 다음 그 비트 맵을 가져오고 싶습니다.Android WebView 오프 스크린/비트 맵 렌더링 문제

"비트 맵"원래 만들어
final WebView view = new WebView(this); 
String summary = "<html><body>You scored <b>192</b> points.</body></html>"; 
view.loadData(summary, "text/html", null); 
Bitmap bitmap= Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888); 
Canvas offscreen = new Canvas(bitmap); 
view.draw(offscreen); 

그것은 투명하다 : 여기 (MainActivity.onCreate의 내부) 코드의 일부분이다. 'view.draw'호출 중에는 흰색 배경이 모두 제공되지만 HTML 요약 문자열은 렌더링되지 않습니다! 두 경우 모두

final WebView view = new WebView(this); 
String summary = "<html><body>You scored <b>192</b> points.</body></html>"; 
view.loadData(summary, "text/html", null); 
Picture picture = new Picture(); 
Canvas picCanvas = picture.beginRecording(400, 400); 
view.draw(picCanvas); 
picture.endRecording(); 
Bitmap bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888); 
Canvas offscreen = new Canvas(bitmap); 
offscreen.drawPicture(picture); 

는 기본 비트 맵은 모두 흰색 배경을 보여주기 위해 수정,하지만 아무것도 :

정확한 같은 효과는 다음에 의해 얻을 수 없다. 누가 이런 일이 일어나고 있는지에 대해 밝힐 수 있습니까? 이 문제가 발생하면 Android 6.0.1 API 23을 실행하는 Sony Experia Z3을 사용하고 있습니다.

답변

1

이 내용을 이해하는 데 다소 시간이 걸렸지 만 여기에 설명되어 있습니다. 문제는 WebView.loadData() 및 WebView.loadURL()이 비 차단이므로 작업 자체를 수행하지 않고 Runnable을 현재 Activity (즉 UI 스레드)에 게시하는 것입니다. 실행되면 실제로 HTML을로드하고 렌더링합니다. 따라서 Activity.onCreae() 내에서 WebView.loadData() 호출을 위와 같이 배치하면 onCreate()가 종료 될 때까지 loadData()에 대한 실제 작업이 수행되지 않으므로 작동하지 않을 수 있습니다. 따라서 빈 이미지.

제안 된 솔루션은 기본 Application 개체의 하위 클래스에서 구현됩니다.

'이'응용 프로그램 서브 클래스의 객체를 반환
public Bitmap renderHtml(final String html, int containerWidthDp, int containerHeightDp) { 
    final int containerWidthPx = dpToPx(containerWidthDp); 
    final int containerHeightPx = dpToPx(containerHeightDp); 

    final Bitmap bitmap = Bitmap.createBitmap(containerWidthPx, containerHeightPx, Bitmap.Config.ARGB_8888); 
    final CountDownLatch signal = new CountDownLatch(1); 
    final AtomicBoolean ready = new AtomicBoolean(false); 

    final Runnable renderer = new Runnable() { 
     @Override 
     public void run() { 
      final WebView webView = new WebView(getPane()); 
      webView.setWebChromeClient(new WebChromeClient() { 
       @Override 
       public void onProgressChanged(WebView v, int newProgress) { 
        super.onProgressChanged(v, newProgress); 
        if (newProgress==100) { 
         ready.set(true); 
        } 
       } 
      }); 
      webView.setPictureListener(new WebView.PictureListener() { 
       @Override 
       public void onNewPicture(WebView v, Picture picture) { 
        if (ready.get()) { 
         final Canvas c = new Canvas(bitmap); 
         v.draw(c); 
         v.setPictureListener(null); 
         signal.countDown(); 
        } 
       } 
      }); 
      webView.setWebViewClient(new WebViewClient() { 
       @Override 
       public void onPageFinished(WebView v, String url) { 
        super.onPageFinished(v, url); 
        ready.set(true); 
       } 
      }); 
      webView.layout(0, 0, containerWidthPx, containerHeightPx); 
      /* The next statement will cause a new task to be queued up 
       behind this one on the UI thread. This new task shall 
       trigger onNewPicture(), and only then shall we release 
       the lock. */ 
      webView.loadData(html, "text/html; charset=utf-8", null); 
     } 
    }; 

    runOnUiThread(renderer); 
    try { 
     signal.await(1000, TimeUnit.MILLISECONDS); 
    } catch (InterruptedException e) { 
    } 

    return bitmap; 
} 

및 getPane()가 현재 실행 활동을 반환합니다 : 그것은 내 자신의 아이디어를 Internets를 통해 터벅 터벅 걷고 및 시도의 누적 결과입니다. UI 스레드에서 루틴을 실행하면 안됩니다 (또는 위에서 설명한 것과 동일한 교착 상태가 발생합니다). 여기서 중요한 점은 (1) loadData() 호출을 포함하는 runOnUIThread Runnable이 완료된 후 (2) loadData() 호출로 생성 된 Runnable도 완료되는 동안 기다리기 위해 잠금을 사용하는 것입니다 (onNewPicture() 훅이 호출됩니다. onNewPicture() 내부에서 완성 된 그림을 비트 맵에 렌더링 한 다음 실행을 계속할 수 있도록 잠금을 해제합니다.

올바르게 구현 된 비트 맵이 대부분 반환된다는 점에서이 구현이 "안정적"인 것으로 나타났습니다. 아직 어떤 이벤트가 loadData/loadURL에 의해 해제되는지 완전히 이해하지 못합니다. 이것에 대해 일관성이없는 것처럼 보입니다. 어쨌든 signal.await() 호출에는 1 초의 시간 제한이 있으므로 전달 진행이 보장됩니다.