I have an Android app, running a WebView that loads a certain page, also part of the app. I want to use the Android DatePicker to get a date from the user and set the value on an input inside the page in the WebView.
The DatePickerDialog opens when the user clicks the input, but when i get the return of the date selection, i can't run the loadUrl method to set the value in the input, it gives me an error and the app crashes.
A little bit of code (It's a test code, so don't mind if it is a bit out of context):
Class i provide to the WebView:
public class webViewInterface {
public void openDatePicker(){
showDialog(0);
}
}
Javascript function on the page, called on the click of the input:
function openDatePicker() {
if (objAndroid != null) objAndroid.openDatePicker();
}
Listener for the date selection
private DatePickerDialog.OnDateSetListener mDateSetListener =
new DatePickerDialog.OnDateSetListener() {
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
mWebView.loadUrl("javascript:setReturnDate();");
}
};
Javascript function that sets a value on the input
function setReturnDate() {
document.getElementById('txtAgency').value = '9999';
}
Any ideas?
Thanks in advance.
Thanks @CommonsWare for the comment, i tracked the error and got this:
"android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
Googled it and got this forum thread
So, in order to update a view in the UI at runtime and outside it's thread, you have to use a Handler, that receive messages and execute actions accordingly.
So i implemented a Handler for the Activity, that gets a message with an int identifier and the data i want to update into the webview:
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;
}
}
};
I had to change the openDatePicker method of the class to use the Handler, as well as create an input parameter, which is the id of the control in the page:
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);
}
Rewrote the DatePicker listener for the date selection, to get the data and send a message to the Handler:
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);
}
};
In the webpage, the js functions got out like this:
function openDatePicker(id) {
if (objAndroid != null) objAndroid.openDatePicker(id);
}
function setReturnDate(id, date) {
var obj = document.getElementById(id);
if (obj != null)
obj.value = date;
}
And finally, the input (TextBox), got like this:
TextBox obj = FindControl("txtDt") as TextBox;
if (obj != null)
{
obj.Attributes.Add("readonly", "readonly");
obj.Attributes.Add("OnClick", "javascript:openDatePicker(this.id)");
}