Calling Method w/ Argument on Main Thread from Secondary Thread - java

Like the title suggest I have an android project with a MainActivity class that has a TextView that I want to set the text of after receiving a message. I also have a class that runs a ServerSocket on a separate thread that receives the string message I want to display.
Part of my MainActivity looks like this,
private Handler UIHandler = new Handler();
private RemoteControlServer remoteConnection;
public static final int controlPort = 9090;
public class MainActivity extends Activity implements SensorEventListener
{
...
remoteConnection = new RemoteControlServer(controlPort, UIHandler);
...
private class RemoteControlServer extends RemoteControl
{
RemoteControlServer(int port, Handler ui)
{
super(port, ui);
}
#Override
public void onReceive(String[] msg)
{
//updates messages textview
}
#Override
public void onNotify(String[] msg)
{
//updates notification textview
}
}
}
The RemoteControlServer implementation of code that calls the onReceive(String[] msg) and also handles receiving messages on the different thread looks like this,
...
public abstract void onReceive(String[] msg);
public abstract void onNotify(String[] msg);
...
controlListener = new Thread(new Runnable()
{
boolean running = true;
public void run()
{
String line = null;
while(running)
{
try
{
//Handle incoming messages
...
onReceive(messages);
}
catch (final Exception e)
{
UIHandler.post(new Runnable()
{
public void run()
{
onNotify("Wifi Receive Failed " + e.toString() + "\n");
}
});
}
}
}
});
...
I'm getting the error "Only the original thread that created a view hierarchy can touch its views." when onReceive() is called and throws the exception and calls onNotify() with the exception description. Why does the onNotify() work but the otherone does not? How can I correctly call the listener to the the TextView and update its text? Thanks

private class RemoteControlServer extends RemoteControl
{
...
public class BridgeThread implements Runnable
{
String[] msgArray = null;
public BridgeThread(String[] msg)
{
msgArray = msg;
}
public void run()
{
runOnUiThread(new Runnable()
{
#Override
public void run()
{
TextView zValue = (TextView) findViewById(R.id.connectionStatus);
zValue.setText(msgArray[0]);
}
});
}
}
#Override
public void onReceive(String[] msg)
{
BridgeThread bridgeTest = new BridgeThread(msg);
bridgeTest.run();
}
...
}

Related

Android HandlerThread update UI without UiHandler

this code works fine and update my "TextView" and also show "Toast"
and that is my Headache as I have tried to to pass A Runnable obj Without including my UiHandler on it as it suppose to be the bridge to update my UI Thread but my activity got updated with no single Error ?????
This not suppose to be as CustomHandlerThread should be A different thread
why this happen ?
My Activity
public class TestActivity extends BaseActivity {
Runnable task;
#BindView(R.id.send_test_message)
Button send_test_message;
private Handler mUiHandler = new Handler();
private MyWorkerThread mWorkerThread;
#Override
public void initViews() {
}
#Override
public void attachViewsListeners() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
ButterKnife.bind(this);
task = new Runnable() { ///this is normally work I have no problem with
///that
#Override
public void run() {
mUiHandler.post(new Runnable() {
#Override
public void run() {
send_test_message.setText("Change--->1");
}
});
}
};
}
#Override
protected void onStart() {
super.onStart();
mWorkerThread = new MyWorkerThread("myWorkerThread");
mWorkerThread.start();
mWorkerThread.prepareHandler();
mWorkerThread.postTask(task);
mWorkerThread.postTask(new Runnable() { /// why this task work with no
///error ?
#Override
public void run() {
send_test_message.setText("Change--->2");
}
});
}
#Override
protected void onDestroy() {
mWorkerThread.quit();
super.onDestroy();
}
my HandlerThread
//MyWorkerThread.java
public class MyWorkerThread extends HandlerThread {
Handler mWorkerHandler;
public MyWorkerThread(String name) {
super(name);
}
public void postTask(Runnable task) {
mWorkerHandler.post(task);
}
public void prepareHandler() {
mWorkerHandler = new Handler(getLooper());
Log.e("MyWorkerThread--->",Looper.myLooper().getThread().getName()); //-->main
Log.e("MyWorkerThread--->",getLooper().getThread().getName());//-->//myWorkerThread
Log.e("MyWorkerThread--->",Thread.currentThread().getName()); //-->main
}
}
I followed this link as A Referance
is My thread running on the MainThread or getLooper() intialize my
HandlerThread with MainThread Looper ,is those log message are true
please illuminate me
After fill day of debugging i Found out That if i post A Runnable to my
mWorkerThread with sleep() as here i got " Only the original thread that created a view hierarchy can touch its views."
as should be.. but until I know why it not works without it
I wish it would help some one.
try {
TimeUnit.SECONDS.sleep(2);
send_test_message.setText("Change--->");
} catch (Exception e) {
e.printStackTrace();
}

Send message to UI thread

I create a thread to listening the input stream of the serial port.
And when there is input data coming, I want to send a message to UI thread.
Before doing my task, I try to send message from the thread with interval 5000 ms, and send a message to UI thread and Toast it.
From the log, I know that the thread is created and running succefully, but the number is not toasted in the UI thread.
I think it may be due to fail to send a message from the thread to UI thread, or fail to handle the message in the MessageQueue of UI thread.
What's wrong with my code?
Many thanks!
MainActivity.java:
public class MainActivity extends Activity {
...
#Override
protected void onCreate(Bundle savedInstancesState) {
...
setMessageProcessor();
SerialPortListener.start();
}
private void setMessageProcessor() {
new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this,
"Message: " + msg.obj.toString(),
Toast.LENGTH_SHORT).show();
}
};
}
}
SerialPortListener.java:
public class SerialPortListener {
...
private static int testNumber = 1;
public static void start() {
...
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
Message msg = new Message();
msg.obj = testNumber++;
new Handler(Looper.getMainLooper()).sendMessage(msg);
Log.i("TEST", "TEST);
try {
Thread.sleep(5000);
} catche(Exception e) {
...
}
}
}
});
thread.start();
}
}
It's because you are creating a second Handler bound to the main thread from within your "reader thread". Don't use an anonymous object for the handler in the main thread, make it a member field. Then in your reader thread, send the Message to that specific Handler:
private void setMessageProcessor() {
mHandler = new Handler() {
...
}
}
public class SerialPortListener {
...
private static int testNumber = 1;
public static void start() {
...
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
Message msg = mHandler.obtainMessage();
msg.obj = testNumber++;
msg.sendToTarget();
Log.i("TEST", "TEST);
...
}
}
}

postDelayed() with messages Android

I want my main UI thread to effectively "sleep" for 1 second before sending an empty message to a worker thread to perform some operation.
Sleep() is a problem for me because I cannot quit() the threads properly while it is performing sleep(), so I want to change it to postDelayed(runnable r, long msDelay) but it takes runnable object, not Message. How can I change this code? I am just passing empty message from main UI thread to worker thread.
UI thread:
public class MainActivity extends Activity
{
static Worker w1, w2;
static Handler mainUIHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
String sender = msg.getData().getString("SENDER");
if (Objects.equals(sender, "CPU1"))
{
mInfoTextView.setText("worker 1 thinking...");
//how to change the following 2 lines to postDelayed()?
try{
Thread.sleep(1000);
} catch (Exception ignored) { }
w2.handler.sendMessage(w2.handler.obtainMessage());
}
}
};
...
}
and the worker thread
class Worker extends HandlerThread
{
...
Worker(String name)
{
super(name);
}
Handler handler= new Handler()
{
#Override
public void handleMessage(Message msg)
{
//perform work
Foo work = dowork();
//communicate work to the UI thread to update the display
Message message = MainActivity.mainUIHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("NAME", name);
bundle.putInt("work", work);
message.setData(bundle);
MainActivity.mainUIHandler.sendMessage(message);
}
};
#Override
public void run()
{
this.setName(WorkerThread.class.getName());
this.setPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
}
}
I tried creating a new Runnable() and passing it to postDelayed():
w2.handler.postDelayed(new Runnable()
{
#Override
public void run()
{
System.out.println("hello");
}
}, 1000);
but it's not triggering the handler in w2
You can delay a Message with Handler.sendMessageDelayed():
public class MainActivity extends Activity {
// ...
static Handler mainUIHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// ...
w2.handler.sendMessageDelayed(w2.handler.obtainMessage(), 1000);
}
}
}

How to implement handler in another class?

In my app I have three buttons and when one button is clicked it calls a thread to start thing is i want to be able to input in edittext string in to the threads and the do some work to it then have it returned to the UI Thread where i can display it or put it into an opengl to display an Object. I've read up on Handles and im not sure i fully understand them and maybe if anyone knows a way to make my own handler code. Also I've read up on Async and I dont think it would benifit my app.(personal opion if it would benifit my app let me know) My question is how would i get the info from UI edittext when enter is pressed to the line thread in DrawingUtils class then work is done to it then it comes back to the UI to be ethier displayed or inputed in an openGl program?
Here is MainActivity class:
public class MainActivity extends Activity implements OnClickListener {
EditText cl;
TextView info;
Button enter;
Button line;
Button arc;
Line callLine = new DrawingUtils.Line();
Enter callEnter = new DrawingUtils.Enter();
Arc callArc = new DrawingUtils.Arc();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView) findViewById(R.id.info);
enter = (Button) findViewById(R.id.enter);
line = (Button) findViewById(R.id.line);
arc = (Button) findViewById(R.id.arc);
Handler UIhandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
String string = bundle.getString("myKey");
}
};
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.enter:
callEnter.start();
break;
case R.id.line:
callLine.start();
break;
case R.id.arc:
callArc.start();
break;
}
};
}
Here is DrawingUtils class:
public class DrawingUtils {
MainActivity handle = new MainActivity();
// Thread classes for buttons
public static class Enter extends Thread {
Thread enter = new Thread() {
public void run() {
}
};
public static class Line extends Thread {
Thread line = new Thread() {
public void run() {
}
};
}
public static class Arc extends Thread {
Thread arc = new Thread() {
public void run() {
}
};
}
}
}
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstance) {
// ....
Handler myHandler = new Handler() {
#Override
public void handleMessage (Message msg) {
doCoolStuffWhenMessageReceived();
}
}
MySecondClass secondClass = new MySecondClass(myHandler);
// ....
}
}
public class MySecondClass {
private handler;
public MySecondClass(Handler handler){
this.handler = handler;
}
private void someMethodToCallActivity() {
handler.sendEmptyMessage(0);
}
}

cant connect to facebook with a network thread

I need to connect to facebook so I use a Tread when using the network. but I have a problem:
Thread t = new Thread(new Runnable() {
#Override
public void run() {
FacebookConnectTask task = new FacebookConnectTask("facebookId", "token", "email", facebookGender,0, 0);
task.setOnPreExecuteListener(this);
task.setOnDoneListener(this);
task.execute();
}
});
t.start();
}
I cant do
task.setOnPreExecuteListener(this);
task.setOnDoneListener(this);
eclipse gives me this error: "The method setOnDoneListener(Task.OnDoneListener) in the type Task is not applicable for the arguments (new Runnable(){})"
How can i fix this?
Thanks!
You've changed context's by being in a Thread your in an Annoyomous class, this is now your annonomous class and not the outer class.
Try this (pun intended):
task.setOnPreExecuteListener(YourOuterClass.this);
task.setOnDoneListener(YourOuterClass.this);
i.e.
public class YourClass implements OnDoneListener {
public doFacebook(){
new Thread(new Runnable(){
#Override
public void run(){
task.setOnDoneListener(YourClass.this);
}
}.start();
}
#Override
public void onDone(){
}
}
or alternatively pull your Threaded class out:
public class DoSomething implements Runnable {
private final OnDoneListener listener;
public DoSomething(OnDoneListener listener){
this.listener = listener;
}
#Override
public void run(){
FacebookConnectTask task = ... ;
task.setOnDoneListener(listener);
}
}
public class YourActivity extends Activity implements OnDoneListener {
public void onCreate(Bundle b){
new Thread(new DoSomething(this)).start();
}
#Override
public void onDone(){
// Tada
}
}
A further step if you wanted to be cooler is create your own interface and keep all the Facebook stuff in the runnable class:
public class DoSomething implements Runnable, OnDoneListener {
public interface OnFacebookFinished {
void onFacebookFinished();
}
private final OnFacebookFinished listener;
public DoSomething(OnFacebookFinished listener){
this.listener = listener;
}
#Override
public void run(){
FacebookConnectTask task = ... ;
task.setOnDoneListener(this);
}
#Override
public void onDone(){
if(listener != null){
listener.onFacebookFinished();
}
}
}
public class YourActivity extends Activity implements OnFacebookFinished {
#Override
public void onCreate(Bundle b){
new Thread(new DoSomething(this)).start();
}
#Override
public void onFacebookFinished(){
// Tada
}
}

Categories

Resources