What is the Message in WebView.requestFocusNodeHref (Message hrefMsg)? - android

I am trying to get the url of the image touched by a user in a WebView.
I use getHitTestResult() but I need to handle cases where getHitTestResult() return UNKNOWN_TYPE.
The documentation suggests requestFocusNodeHref (Message hrefMsg) but I don't understand what the Message should be.
Thank you for any idea.

Answering my own question here.
So this is how it works. The message in question must be sent to a Handler that will handle the request.
/*
* Used to get the result of requestFocusNodeHref(msg)
*/
class MyHandler extends Handler{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String src = msg.getData().getString("src");
launchImageSaveAs(src);
}
}
Then, somewhere in your code, for example in OnLongClickListener you create a new message and set the handler as a target and finally call requestFocusNodeHref
if(result.getType() == HitTestResult.UNKNOWN_TYPE){
Message msg = new Message();
msg.setTarget(new MyHandler());
webview.requestFocusNodeHref(msg);
}

Related

Android : Message sent from seperate thread has obj set to null

I have a UI created in an activity which creates a handler for receiving messages.
I then launch a second thread for network communication. This second thread sends messages back to the UI thread via the UI threads handler.
All works OK as long as I send integer values.
However, if I set the objvalue to an object such as a string, when it arrives in the handler it has been set back to null.
The handler is declared like this :
private static class MsgHandler extends Handler
{
private CommsActivity m_parent;
public MsgHandler(CommsActivity parent)
{
m_parent = parent;
}
#Override
public void handleMessage(Message msg)
{
switch(msg.what)
{
case R.integer.msg_progress :
m_parent.ShowProgress(msg.arg1);
break;
case R.integer.msg_error :
m_parent.ShowError(msg.arg1, (String)msg.obj);
break;
}
}
}
When I need to send a message from the second thread, I call it in this manner :
msg = m_hMsgHandler.obtainMessage();
msg.what = m_iNormalMsgId;
msg.arg1 = R.integer.activation_lockout;
msg.obj = new String(strResponse);
msg.sendToTarget();
The MsgHandlerinstance is passed into the thread runnable as a parameter and stored for later use.
I have also tried using a Bundle instance, but this also is set to NULL.
Note that I am working with Android 4.4.
What do I need to do to overcome this limitation ?
try to send message using handler.
hope it helps
msg = m_hMsgHandler.obtainMessage();
msg.what = m_iNormalMsgId;
msg.arg1 = R.integer.activation_lockout;
msg.obj = new String(strResponse);
m_hMsgHandler.sendMessage(msg);
and check, that you process exactly this message (I see in yuor samples set msg.what = m_iNormalMsgId but in switch process case R.integer.msg_progress like msg.arg1 = R.integer.activation_lockout;)
This is how I'd try it:
m_hMsgHandler.sendMessage(
m_hMsgHandler.obtainMessage(
m_iNormalMsgId,
R.integer.activation_lockout,
0,
new String(strResponse)
);

How do I receive a message using Handlers?

I've tried many ways to use handlers to receive messages on a background thread, I have not been successful.
Is there a sure fire way to test this? Is there a sample code I can use to see how it is done?
Yes, try the answer by #FoamyGuy. In the sample code he has sent back an empty message. I'm extending his code to pass strings. If you want to send some message back to the handler(eg: string), you can send some string or something else as follows:
Handler h = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 1){
//Success
String msg = (String)msg.obj;
Log.d("", "Msg is:"+msg);
}else{
//Failure
String msg = (String)msg.obj;
Log.d("", "Msg is:"+msg);
}
}
};
Thread t = new Thread() {
#Override
public void run(){
doSomeWork();
if(succeed){
//we can't update the UI from here so we'll signal our handler. and it will do it for us.
Message m = h.obtainMessage(1, "Success message string");
m.sendToTarget();
}else{
Message m = h.obtainMessage(0, "Your Failed!");
m.sendToTarget();
}
}
}
On a non-UI thread? All you need to do is create a Looper on that thread, then create the handler on it. That will automatically cause that Handler to be associated with that Looper. Then run Looper.loop
So
Looper.prepare();
Handler myHandler = new Handler();
Looper.loop()
and myHandler will be on the thread.

Sending message from service to UI-Thread - Messages delayed in service's handler

I have a service which is pulling data from the server. And I have activity as gui which needs to get updated.
So on different occassions, e.g. the information was pulled from the server successfully, the server must signal the activity that there is new information.
For this I implemented this function:
/**
* ServerService.class
*
* Sends a message to the observer that there is a new status message to be
* pulled from the service#
*
* #param pMessage
* the message to be set to the public status
*/
private void signalNewStatus(String pMessage) {
//check if there is a message at all to be signaled as new
if (pMessage != null) {
Log.v(tag, "signalNewStatus:" + pMessage);
// set the message
vStatus = pMessage;
// start the new callback via the handler
myMessageHandler.sendEmptyMessage(I_STATUS_UPDATE_SIGNAL);
}
}
To handle the messages, I have the message handler:
private final Handler myMessageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.i(tag, "handleMessage: "+msg.what);
switch (msg.what) {
case I_STATUS_UPDATE_SIGNAL: {
// Broadcast to all clients the new value.
final int N = myCallbackList.beginBroadcast();
for (int i = 0; i < N; i++) {
try {
myCallbackList.getBroadcastItem(i).sendUpdateStatusSignal(true);
} catch (RemoteException e) {
}
}
myCallbackList.finishBroadcast();
}
break;
The first function is called quite often, and I can see in the logging that this works right on time.
But the logging for the message handling does not get called right away. It is delayed and gets called most often at the end. Somehow as bulk.
I cannot figure out why this is the case. The rest works well, the message gets to the UI thread without a problem once the message was handled.
Any suggestions?
Thanks a lot!
I can't be sure without more code, but it sounds like a threading issue.
Try putting your handler code in a separate HandlerThread, retrieve the handler in the service and send the message to it.

Android, quick question from my book

I am a noob learning Android via a book, i have a quick question. My book code is pretty simple and looks like this:
My handler:
Handler handler=new Handler() {
#Override
public void handleMessage(Message msg) {
bar.incrementProgressBy(5);
}
};
My thread:
Thread background=new Thread(new Runnable() {
public void run() {
try {
for (int i=0;i<20 && isRunning.get();i++) {
Thread.sleep(1000);
handler.sendMessage(handler.obtainMessage());
}
}
catch (Throwable t) {
// just end the background thread
}
}
});
My question is here:
handler.sendMessage(handler.obtainMessage());
What the heck is "handler.obtainMessage()" ?
Doing a mouse over in Eclipse gives me a message that sounds like gibberish.
What message is it trying to "obtain"?
As described in the docs, it obtains a message from the message pool instead of creating a new one. (you need to send a message to the handler anyway):
Returns a new Message from the global message pool. More efficient
than creating and allocating new instances. The retrieved message has
its handler set to this instance (Message.target == this). If you
don't want that facility, just call Message.obtain() instead.
I'll try to elaborate:
You send a message to the handler. The message is added to the handler's thread queue and processed on the original thread. You need to send it a message, though you have nothing specific in the message that it uses (according to your handler code) so you just send an empty message, but instead of allocating a memory for a new message, the message is taken from the message pool, which is faster.
Hope this makes things clearer.
Regarding how to set a message with an int:
Message m = new Message();
Bundle b = new Bundle();
b.putInt("what", 5); // for example
m.setData(b);
handler.sendMessage(m);

android service callback

I have made an application based on the android API's remote service application wich uses callbacks to notify the main activity for changes, the app works fine passing just a single int value from the remote service back to the activity.
The problem is that I would like to pass some Strings and not an int back in order to update the activiti's UI, how can I do that? I have thought of returning an object but there is lack of documentation and don't know how or if it is possible.
Ok just figure it out, I am posting the solution in order to help others with similar problem.
1.you need to make a separate aidl file that only contains the parcable object(see the link in the comments above).
Second in the callback interface import that interface and then add it as a parameter.
when you implement the method from the callback interface in your activity class add the returned object (this would be the parsable object) as the Message object and send that message.
in the handler just unmarshall the object and use it.
This is a sample code:
The Parcable's object interface:
package sap.max;
parcelable ParcableInfo;
The Callback interface:
package sap.max;
import sap.max.ParcableInfo;
/**
* A callback interface used by IMonitorService to send
* synchronous notifications back to its clients. Note that this is a
* one-way interface so the server does not block waiting for the client.
*/
oneway interface IRemoteServiceCallback {
/**
* Called when the service has a new value for you.
*/
void valueChanged(in ParcableInfo info);
}
The service's actions (note this is only what the service will call not complete code):
private final Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
switch (msg.what) {
// It is time to bump the value!
case REPORT_MSG: {
// Up it goes.
int value = ++mValue;
// Broadcast to all clients the new value.
final int N = mCallbacks.beginBroadcast();
for (int i=0; i<N; i++) {
try {
ParcableInfo parceInfo = new ParcableInfo(telephonyManager.getSubscriberId() );
parceInfo.setID(telephonyManager.getSubscriberId());
mCallbacks.getBroadcastItem(i).valueChanged(parceInfo);
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mCallbacks.finishBroadcast();
// Repeat every 3 second.
sendMessageDelayed(obtainMessage(REPORT_MSG), 1*3000);
} break;
default:
super.handleMessage(msg);
}
}
};
And finally the Activities part:
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
#Override
public void valueChanged(ParcableInfo info) throws RemoteException {
CellInfo cellInfo = new CellInfo(null, null, null, null, null, null, null);
cellInfo.setDeviceId(info.ID);
Message msg = mHandler.obtainMessage(BUMP_MSG, info);
mHandler.sendMessage(msg);
}
And the message is handled by:
//this is the handler for the service...
private Handler mHandler = new Handler() {
#Override public void handleMessage(Message msg) {
switch (msg.what) {
case BUMP_MSG:
ParcableInfo info = (ParcableInfo) msg.obj;
configView.setText(info.ID);
Toast.makeText(AntiTheft.this, "Received from service: " + info.ID,
Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
};
Hope this helps others, thanks for the help fedj.
You can pass Strings by default and you should take a look to Parcelable objects (there is no lack of documentation)
I created the simple "ParcableInfo.aidl" file containing :
package my.package.name;
parcelable ParcableInfo;
However, when I build the project the "ParcableInfo.java" isn't generated in the "gen" folder.

Categories

Resources