2012-02-25 1 views
5

По каким-то причинам я должен использовать WebView в своем приложении для Android, а часть бизнес-логики содержится в JavaScript (я запускаю его с помощью addJavascriptInterface()). Проблема в том, что я не могу изменить компоненты пользовательского интерфейса моего приложения из объекта, привязанного к скрипту. Это объясняется в документации:Доступ к UI из JavaScript на Android

Примечание: Объект, который связан с вашей JavaScript работает в другом потоке, а не в потоке, в котором она была построена.

Мне интересно, есть ли способы обхода проблемы?

ответ

13

Вам необходимо передать экземпляр Handler на ваш JavaScript-интерфейс и использовать его для отправки runnables. Если этот обработчик будет создан в потоке пользовательского интерфейса, в потоке пользовательского интерфейса также будут задействованы исполняемые файлы posted there.

Handler mHandler = new Handler(); // must be created on UI thread, e.g. in Activity onCreate 

// from javascript interface... 
mHandler.post(new Runnable() { 
    @Override 
    public void run() { 
     // code here will run on UI thread 
    } 
}); 

Другим решением является использование метода Activity «s runOnUIThread

mActivity.runOnUIThread(new Runnable() { 
    @Override 
    public void run() { 
     // code here will run on UI thread 
    } 
}); 
+1

Спасибо, много! Это сделало трюк :) –

+0

Вы всегда можете использовать 'new Handler (Looper.getMainLooper())', чтобы обработчик использовал поток пользовательского интерфейса. – ImMathan

1

Предположим, что вы находитесь внутри фрагмента, и вы делаете getActrivity().runOnUIThread(...) в коде Javascript интерфейса. Возможно, что к моменту, когда WebViewCoreThread выполнит код интерфейса Javascript, фрагмент будет отделен от активности, а getActivity() вернет null, в результате чего будет выведено исключение NullPointerException. Безопасный способ сделать это - использовать обработчик, как в приведенном ниже примере. Кроме того, убедитесь, что интерфейс JavaScript использует WeakReferences для компонентов ui, поскольку они должны быть собраны в мусор, прежде чем выполняется интерфейс Javascript.

myWebView.addJavascriptInterface(new Object() { 
     private Handler handler = new Handler(); 
     private WeakReference<ProgressBar> progressBarRef = new WeakReference<ProgressBar>(
       myWebViewProgressBar); 
     private WeakReference<WebView> myWebViewRef = new WeakReference<WebView>(
       myWebView); 

     @SuppressWarnings("unused") 
     public void onFirstImageLoad() { 

      handler.post(new Runnable() { 
       @Override 
       public void run() { 
        ProgressBar progressBar = progressBarRef.get(); 
        WebView webView = myWebViewRef.get(); 
        if (progressBar != null) { 
         progressBar.setVisibility(View.GONE); 
        } 
        if (webView != null) { 
         webView .setVisibility(View.VISIBLE); 
        } 
       } 
      }); 
     } 
    }, "jsInterface"); 
Смежные вопросы