Chcę wiedzieć, że jeśli jest jakiś czas, zanim mogę uzyskać dostępu do obiektu
Tak, myślę, że to opóźnienie, ponieważ WebView.addJavascriptInterface
będzie działał w wewnętrzny gwint pracownikowi Webview za. Być może zastanawiałeś się nad tym i zdałeś sobie sprawę, że WebView musi utrzymywać co najmniej jeden wątek roboczy do wykonania asynchronicznej sieciowej operacji wejścia/wyjścia. Być może zauważyłeś te wątki w DDMS podczas korzystania z WebView.
Okazuje się, że używa wątku do pracy z wieloma innymi metodami publicznymi. Naprawdę chciałbym, aby dokumenty od Google uczyniły to jaśniejszym! Mam jednak nadzieję, że pomogę i pokażę ci, jak próbowałem to potwierdzić dla siebie.
Śledź mnie, gdy przyjrzę się źródłu dla WebView. Jest to dość czytelne, nawet jeśli nie możesz dokładnie śledzić tego, co się dzieje, możliwe jest prześledzenie odpowiedzi na kilka pytań dotyczących wątków.
Źródło systemu Android można pobrać za pomocą narzędzia menedżera SDK, ale jest ono również odzwierciedlone na Githubie, więc to jest to, do czego mam tutaj link. Zgadłem i wybrałem tag zbliżony do jakiejś wersji ICS. Nie trudno jest znaleźć . Właśnie szukałem w Google "strony WebView.java: github.com/android".
Sposób WebView.addJavascriptInterface
wysyła wiadomość do instancji WebViewCore
:
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
W WebViewCore.java
istnieje kilka przeciążonych metod zwanych sendMessage
, ale naprawdę nie trzeba wiedzieć, jakie dokładnie jest nazywany, ponieważ robią prawie to samo. Jest nawet miły komentarz, który daje nam wskazówkę, że jesteśmy we właściwym miejscu! Wszyscy oni delegują do instancji EventHub
, która jest wewnętrzną klasą. This method okazuje się być zsynchronizowane i wysyła wiadomość do instancji Handler
, co jest dobrym wskazaniem, że prawdopodobnie działa w innym wątku, ale dla kompletności, dowiedzmy się!
Utworzono Handler
w EventHub.transferMessages
, która jest wywoływana z WebViewCore.initialize
. Jest tu kilka dodatkowych przeskoków, ale w końcu dowiedziałem się, że jest to wywoływane z run
w WebCoreThread
(podklasa Runnable
), które jest tworzone wraz z nowym Thread
prawym here.
Co za przygoda! Tak więc, chociaż naprawdę nie mogę powiedzieć na pewno, co się dzieje z tymi ruchomymi częściami, jestem całkiem pewien, że mogę powiedzieć, że ta metoda nie jest synchroniczna i wysyła wiadomość do wątku roboczego WebView. Mam nadzieję, że ma to sens!
jeśli tak, to jak mogę się dowiedzieć, ile czasu powinienem czekać na telefon do mojego obiektu?
Niestety, nie znam odpowiedzi na to. Badałem dokładnie ten problem i znalazłem to pytanie w StackOverflow w trakcie mojego Googling. Myślę, że masz następujące opcje, z których niektóre są ładniejsze lub łatwiejsze niż inne:
1) Tylko Thread.sleep
przez 100 ms lub coś pomiędzy addJavascriptInterface
i loadUrl("javascript:...")
. Blech, nie podoba mi się to, ale jest to potencjalnie najłatwiejsze.
2) Inna możliwość polega na tym, że można zadzwonić pod numer WebView.loadUrl
z fragmentem kodu JavaScript, który dokładnie sprawdza, czy interfejs jest ustawiony, i przechwytuje wywołanie ReferenceError, jeśli nie jest jeszcze ustawione. Jednak, jak można się domyślić, ten rodzaj polega na dodaniu interfejsu JavaScript do WebView!
3) Zamiast tego należy zadzwonić pod numer WebView.setWebChromeClient
i zastąpić kod JavaScript w wersji alert()
lub console.log
. Z moich eksperymentów ta metoda jest synchroniczna, więc nie ma opóźnienia. (Potwierdziłem to w źródle, ale szczegóły pozostawiam jako ćwiczenie dla czytelnika) Powinieneś prawdopodobnie wymyślić specjalny ciąg, który zadzwonisz pod numer alert
i sprawdzisz go wewnątrz onJsAlert
, więc nie łapiesz po prostu wszystkich alert()
s.
Przepraszamy za długość tej odpowiedzi, mam nadzieję, że pomaga. Powodzenia!
dobra odpowiedź opracować odpowiednie referencje. –
fajne. miła odpowiedź. Ale sprawdzanie alertów i komunikatów konsoli jest tak samo złe, jak robienie Thread.sleep() :) – Akshat
Hej, ostrzegłem, że opcje są nieoptymalne: P – spacemanaki