Внедрение Javascript в Webview вне события onPageFinished (использование DatePicker для установки даты на входе WebView)

У меня есть приложение для Android, в котором запущен WebView, который загружает определенную страницу, также являющуюся частью приложения. Я хочу использовать Android DatePicker, чтобы получить дату от пользователя и установить значение для ввода внутри страницы в WebView.

DatePickerDialog открывается, когда пользователь щелкает ввод, но когда я получаю возврат выбора даты, я не могу запустить метод loadUrl, чтобы установить значение во вводе, это дает мне ошибку, и приложение аварийно завершает работу.

Немного кода (это тестовый код, так что не обращайте внимания, если он немного вырван из контекста):

Класс, который я предоставляю WebView:

public class webViewInterface {
    public void openDatePicker(){
        showDialog(0);
    }
}

Функция JavaScript на странице, вызываемая по щелчку ввода:

function openDatePicker() {
        if (objAndroid != null) objAndroid.openDatePicker();
    }

Прослушиватель для выбора даты

private DatePickerDialog.OnDateSetListener mDateSetListener =
    new DatePickerDialog.OnDateSetListener() {

        public void onDateSet(DatePicker view, int year, 
                              int monthOfYear, int dayOfMonth) {

            mWebView.loadUrl("javascript:setReturnDate();");
        }
    };

Функция JavaScript, которая устанавливает значение на входе

function setReturnDate() {
        document.getElementById('txtAgency').value = '9999';
    }

Любые идеи?

Заранее спасибо.


person Marcelo Vitoria    schedule 08.02.2011    source источник
comment
Используйте adb logcat, DDMS или перспективу DDMS в Eclipse, чтобы изучить LogCat и просмотреть трассировку стека, связанную с вашей ошибкой.   -  person CommonsWare    schedule 08.02.2011


Ответы (1)


Спасибо @CommonsWare за комментарий, я отследил ошибку и получил это:

"android.view.ViewRoot$CalledFromWrongThreadException: только исходный поток, создавший иерархию представлений, может касаться своих представлений".

Погуглил и получил эту ветку форума

Таким образом, чтобы обновить представление в пользовательском интерфейсе во время выполнения и вне его потока, вы должны использовать обработчик, который получает сообщения и выполняет действия соответственно.

Поэтому я реализовал обработчик для действия, который получает сообщение с идентификатором int и данными, которые я хочу обновить в веб-просмотре:

final Handler handler = new Handler() {
    public void handleMessage(Message msg) {

        int cod = msg.getData().getInt("messageType");
        switch(cod){
            case 1:
                String date = msg.getData().getString("datePickerValue");
                mWebView.loadUrl("javascript:setReturnDate('" + mId + "', '" + date + "');");
                break;
            case 2:
                showDialog(0);
                break;
        }

    }
};

Мне пришлось изменить метод openDatePicker класса, чтобы использовать обработчик, а также создать входной параметр, который является идентификатором элемента управления на странице:

public void openDatePicker(String id){

        mId = id; //mId is a string declared in the Activity scope, so it can be used anywhere
        Message msg = new Message();
        Bundle b = new Bundle();
        b.putInt("messageType", 2);

        msg.setData(b);
        handler.sendMessage(msg);
    }

Переписал прослушиватель DatePicker для выбора даты, чтобы получить данные и отправить сообщение обработчику:

private DatePickerDialog.OnDateSetListener mDateSetListener =
    new DatePickerDialog.OnDateSetListener() {

        public void onDateSet(DatePicker view, int year, 
                              int monthOfYear, int dayOfMonth) {

            Message msg = new Message();
            Bundle b = new Bundle();
            b.putInt("messageType", 1);
            b.putString("datePickerValue", 
                    String.format("%02d", dayOfMonth) + "/" + 
                    String.format("%02d", (monthOfYear + 1)) + "/" + 
                    String.valueOf(year));
            msg.setData(b);
            handler.sendMessage(msg);
        }
    };

На веб-странице функции js выглядят следующим образом:

function openDatePicker(id) {
        if (objAndroid != null) objAndroid.openDatePicker(id);
    }

    function setReturnDate(id, date) {
        var obj = document.getElementById(id);
        if (obj != null)
            obj.value = date;
    }

И, наконец, ввод (TextBox) стал таким:

TextBox obj = FindControl("txtDt") as TextBox;

            if (obj != null)
            {
                obj.Attributes.Add("readonly", "readonly");
                obj.Attributes.Add("OnClick", "javascript:openDatePicker(this.id)");
            }
person Marcelo Vitoria    schedule 10.02.2011