I want to know how to use switch-case when using handleMessage interface. as shown below in the code, in the run() method I am sending different messages while
I have only one handler with handleMessage() interface, I want to know how to use switch-case to handle different messages sent
in onCreate:
private void initObjs() {
Log.w(TAG, CSubTag.bullet("initObjs"));
this.mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
..
..
}
};
}
in run():
public void run() {
//initiating connection
BluetoothSocket rfcSocket = mSPPCtrl.rfcConnect();
if (rfcSocket.isConnected()) {
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("CONNECTED", "RFC-SOCKET CONNECTED");
msg.setData(b);
mHandler.sendMessage(msg);
//assigning stream variables
try {
this.mRFCOS = rfcSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
this.mRFCIS = rfcSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Message msg = mHandler.obtainMessage();
Bundle b = new Bundle();
b.putString("DISCONNECTED", "RFC-SOCKET NOT CONNECTED");
msg.setData(b);
mHandler.sendMessage(msg);
}
before sendMessage(msg),give msg.what a int value,like 0,1,2...
in handleMessage(),use swith case;
Define message constants like
public static final int STATE_CONNECTED = 1;
public static final int STATE_DISCONNECTED = 2;
Handler :
#Override
public void handleMessage(Message msg) {
switch(msg.what) {
case STATE_CONNECTED:
//do your stuff
break;
case STATE_DISCONNECTED:
//do your stuff
break;
default :
//default condition
break;
}
}
And in run()
public void run() {
...
if (rfcSocket.isConnected()) {
Message msg = mHandler.obtainMessage(STATE_CONNECTED);
...
} else {
Message msg = mHandler.obtainMessage(STATE_DISCONNECTED);
...
}
}
Related
I'm work on crate server and android client
but thread doesn't interrupted by android client
My android Client has request for the RoomList from server
and Server receive, Client Accept
and fill in my ListView used the Adapter
here's problem if Click backButton,
than RoomListAcitivity was close and thread was stop
but thread dosen't stop just alive in my app
first Enter has work on sucessfully
but Press BackButton on and re-Enter this Activity
MyApp just White, No Action
how can i stop this thread?
(and sorry for my English skill...)
i tried .interrupt() method , and handler.removeMessages(0)
but failed thread keep alive
upload this full java code just in case...
ListView roomList;
RoomAdapter roomAdapter;
Socketservice ss;
String msg,rtitle;
String msgs[];
String list[];
Thread listthread,EnterRoomThread,removeV;
boolean staterun = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_room);
roomList = findViewById(R.id.roomList);
roomAdapter = new RoomAdapter();
listthread = new Thread() {
public void run(){
ss.out.println("163|");
ss.out.println("100|");
try {
while (staterun == true) {
msg = ss.in.readLine();
handler.post(new Runnable() {
public void run() {
msgs = msg.split("\\|");
String protocol = msgs[0];
switch (protocol) {
case "163":
list = msgs[1].split(",");
for (int i = 0; i < list.length; i++) {
String list1[] = list[i].split("-");
String listT = list1[0];
int listC = Integer.parseInt(list1[1]);
int listI = Integer.parseInt(list1[2]);
roomAdapter.CreateRoom(listI, listT, listC);
}
roomList.setAdapter(roomAdapter);
msg = "";
msgs = null;
break;
case "200":
Intent i = new Intent(getApplicationContext(), GameWaitingActivity.class);
i.putExtra("tname", rtitle);
staterun = !staterun;
Toast.makeText(getApplicationContext(),""+listthread.isAlive(),Toast.LENGTH_SHORT).show();
startActivity(i);
finish();
break;
case "201":
Toast.makeText(getApplicationContext(), "방이 꽉 찼습니다.", Toast.LENGTH_SHORT).show();
break;
}
}
});
}
} catch (IOException e) {
}
}
};
listthread.start();
roomList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Room item = (Room) roomList.getItemAtPosition(position);
rtitle=item.getTitle();
EnterRoomThread = new Thread() {
public void run() {
ss.out.println("200|" + rtitle);
EnterRoomThread.interrupt();
}
};
EnterRoomThread.start();
}
});
}
Handler handler = new Handler();
#Override
public void onBackPressed() {
removeV = new Thread() {
public void run(){
ss.out.println("101|");
removeV.interrupt();
}
};
removeV.start();
handler.removeMessages(0);
staterun = false;
listthread.interrupt();
Toast.makeText(getApplicationContext(),""+listthread.isAlive(),Toast.LENGTH_SHORT).show();
finish();
}
}
Go ahead with this, write this inside run() method
//use this boolean value to keep track.
boolean shouldRunFlag = true;
while (shouldRunFlag) {
try {
Thread.sleep(10);
//Do your work............
} catch (Exception e) {
e.printStackTrace();
Log.v(TAG, "Interrupted Exception caught");
// change the flag, so that while loop can be broken.
shouldRunFlag = false;
Log.v(TAG, "run: breaking the loop");
break;
}
}
and this is how you interrupt and clean the thread
private void interrupt(Thread currentThread) {
Log.i(TAG, "interrupt");
if (currentThread != null) {
Thread dummyThread = currentThread;
dummyThread.interrupt();
currentThread = null;
}
}
I have two threads, two handlers. From thread i check a random number and send result to handle to update ui. But i am getting the error "only the original thread that created a view hierarchy can touch its views.". I searched some articles, they tell to use handler. I am doing that, yet can not avoid the errors.
After some checking, I found that it crashes when A sends the result. In case of B, it works
Also, can i use one handler for two thread?
public class MainActivity extends Activity implements View.OnClickListener{
Button start;
TextView status_B, status_A;
Boolean isRunning;
Thread Athread, Bthread;
int a, b;
Handler a_Handler, b_Handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Initialize variables
start = (Button) findViewById(R.id.button);
start.setOnClickListener(this);
status_B = (TextView) findViewById(R.id.textView);
status_A = (TextView) findViewById(R.id.textView1);
a_Handler = new Handler() {
public void handleMessage(Message msg)
{
int number = msg.getData().getInt("number");
String winner = msg.getData().getString("winner");
start.setEnabled(true);
isRunning = false;
status_A.setText(winner + number);
}
};
b_Handler = new Handler() {
public void handleMessage(Message msg)
{
int number = msg.getData().getInt("number");
String winner = msg.getData().getString("winner");
start.setEnabled(true);
isRunning = false;
status_B.setText(winner + number);
}
};
}
#Override
protected void onStart() {
super.onStart();
isRunning = false;
}
#Override
public void onClick(View v) {
start.setEnabled(false);
status_B.setText("Guessing...");
if (!isRunning)
{
Athread = new Thread(new Runnable() {
#Override
public void run() {
while (isRunning)
{
try
{
Athread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
a = (int) (Math.random()*1000);
System.out.println("a "+ a);
if(a%7 == 0) {
isRunning = false;
Bundle bundle = new Bundle();
bundle.putString("winner", "A");
bundle.putInt("number", a);
Message msg = a_Handler.obtainMessage();
msg.setData(bundle);
a_Handler.handleMessage(msg);
}
}
}
});
Bthread = new Thread(new Runnable() {
#Override
public void run() {
while(isRunning)
{
try
{
Bthread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
b = (int) (Math.random()*1000);
System.out.println("b "+ b);
if(b%7 == 0) {
isRunning = false;
Bundle bundle = new Bundle();
bundle.putString("winner", "B");
bundle.putInt("number", b);
Message msg = b_Handler.obtainMessage();
msg.setData(bundle);
b_Handler.sendMessage(msg);
}
}
}
});
isRunning = true;
Athread.start();
Bthread.start();
}
}
}
You need put your code to modify views on UI thread:
a_Handler = new Handler() {
public void handleMessage(Message msg)
{
final int number = msg.getData().getInt("number");
final String winner = msg.getData().getString("winner");
runOnUiThread(new Runnable() {
#Override
public void run() {
start.setEnabled(true);
status_A.setText(winner + number);
}
});
isRunning = false;
}
};
b_Handler = new Handler() {
public void handleMessage(Message msg)
{
final int number = msg.getData().getInt("number");
final String winner = msg.getData().getString("winner");
runOnUiThread(new Runnable() {
#Override
public void run() {
start.setEnabled(true);
status_B.setText(winner + number);
}
});
isRunning = false;
}
};
I have a ball that keeps moving from start. I want to stop ball on button click. When I clicked on button it show the Toast, but the ball keep on moving. It doesn't stop.
Please guide me how to stop ball on button click. My code for Activity is there.
#SuppressLint("HandlerLeak")
public class BounceActivity extends Activity {
private static final int GAME_START = 500;
private static final int GAME_STOP = 600;
Thread myRefreshThread = null;
BounceView myBounceView = null;
int width = 0;
int height = 0;
Handler myGUIUpdateHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case BounceActivity.GAME_START:
myBounceView.invalidate();
break;
case BounceActivity.GAME_STOP:
Log.d("BounceView", "Game state: " + BounceView.game_state);
Toast.makeText(BounceActivity.this, "Game stopped", Toast.LENGTH_SHORT).show();
myRefreshThread = null;
break;
}
super.handleMessage(msg);
}
};
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
this.myBounceView = new BounceView(this, dm.widthPixels, dm.heightPixels);
this.setContentView(myBounceView);
myRefreshThread = new Thread(new RefreshRunner());
myRefreshThread.start();
}
class RefreshRunner implements Runnable {
#Override
public void run() {
while (myRefreshThread != null) {
if(BounceView.game_state == 0) {
Message msg = Message.obtain();
msg.what = BounceActivity.GAME_START;
myGUIUpdateHandler.sendMessage(msg);
} else if (BounceView.game_state == 1) {
Message msg = Message.obtain();
msg.what = BounceActivity.GAME_STOP;
myGUIUpdateHandler.sendMessage(msg);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}}
You are accessing and setting myRefreshThread on different threads, which can be problematic.
Instead of checking if myRefreshThread is null in your while loop, you can add a "running" flag to RefreshRunner, and a stop method that sets it to false.
Than check that flag in the while loop.
Hold a reference to your RefreshRunner (the one you pass to myRefreshThread), and call stop() when you want the animation to stop.
class RefreshRunner implements Runnable {
private void mRunning = true;
public void stop () {
mRunning = false;
}
#Override
public void run() {
while (mRunning) {
if(BounceView.game_state == 0) {
Message msg = Message.obtain();
msg.what = BounceActivity.GAME_START;
myGUIUpdateHandler.sendMessage(msg);
} else if (BounceView.game_state == 1) {
Message msg = Message.obtain();
msg.what = BounceActivity.GAME_STOP;
myGUIUpdateHandler.sendMessage(msg);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}}
I am building a music player that uses a service for playback. I have an Activity UI that controls (play, pause, next, ...) the service.
I want to update the UI from my service when the next or previous button is pressed. I thought of passing an integer value. Here is my code:
I have used a messenger for communication. The code in my service looks like:
enum Event {
NextSongChanged, CurrentPlayingSong
};
public synchronized void registerHandler(Messenger m) {
clients.add(m);
}
private void emit(Event e) {
for (Messenger m : clients) {
try {
m.send(Message.obtain(null, e.ordinal()));
} catch (RemoteException exception) {
/* The client must've died */
clients.remove(m);
}
}
}
My method that I am calling on click of next button:
public synchronized void playnext() {
reset();
if(songIndex < (songsList.size() - 1)) {
songIndex += 1;
playSong(songIndex);
} else {
songIndex = 0;
playSong(songIndex);
}
emit(Event.NextSongChanged);
}
As soon as I fire the NextSongChanged event I want to pass the "songIndex" variable into my activity. Any idea on how to achieve this?
My Activity code to handle the event:
private Messenger playerMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (MyService.Event.values()[msg.what]) {
case NextSongChanged:
//String songTitle = songsList.get(currentSongIndex+1).get("songTitle");
//currentSongIndex += 1;
//songTitleLabel.setText(songTitle);
//updatePlaying();
break;
case CurrentPlayingSong:
break;
}
}
});
Sample code hope will help others
1. Set Handler (to receive message) and Messenger (to communicate) MainActivity.java
Messenger msgService;
boolean isBound;
ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) { isBound = false; }
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
isBound = true;
msgService = new Messenger(service);
}
};
public void sendMessage(View view) {
if (isBound) {
try {
Message message = Message.obtain(null, MessangerService.MESSAGE, 1, 1);
message.replyTo = replyMessenger;
Bundle bundle = new Bundle();
bundle.putString("rec", "Hi, you hear me");
message.setData(bundle);
msgService.send(message); //sending message to service
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
//setting reply messenger and handler
Messenger replyMessenger = new Messenger(new HandlerReplyMsg());
class HandlerReplyMsg extends Handler {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String recdMessage = msg.obj.toString(); //msg received from service
toast(recdMessage);
}
}
2. Setup service class MessengerService.java
Messenger replyMessanger;
final static int MESSAGE = 1;
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE) {
Bundle bundle = msg.getData();
toast(bundle.getString("rec"));//message received
replyMessanger = msg.replyTo; //init reply messenger
doSomething();
}
}
}
private void doSomething() {
// do stuff
if (replyMessanger != null)
try {
Message message = new Message();
message.obj = "Yes loud and clear";
replyMessanger.send(message);//replying / sending msg to activity
} catch (RemoteException e) {
e.printStackTrace();
}
}
Messenger messenger = new Messenger(new IncomingHandler());
#Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
Make sure you declared Service in manifest and binding/unbinding Service in activity.
I need to send data from a class to the main UI Activity and i am trying to do this with message passing.
Unfortunately my handler didn't receive the message sent inside a loop. I show you my code so far:
In the UI Activity
private final Handler mIncomingHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
tedit.setText("Received " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}
};
private final Messenger mMessenger = new Messenger(mIncomingHandler);
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mTransferServiceBound = true;
Message msg = Message.obtain(null, TransferService.MSG_REG_CLIENT);
msg.replyTo = mMessenger;
mTransferService = new Messenger(service);
try {
mTransferService.send(msg);
} catch (RemoteException e) {
Log.e(TAG, "Unable to register client");
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
mTransferService = null;
mTransferServiceBound = false;
}
};
In the service
private class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REG_CLIENT:
Log.d(TAG, "Activity client registered");
mClient = msg.replyTo;
waitCommunication();
break;
case MSG_UNREG_CLIENT:
mClient = null;
stopSelf();
break;
default:
super.handleMessage(msg);
}
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
private void waitCommunication() {
int i = 0;
while(true) {
try {
mClient.send(Message.obtain(null, MainActivity.Message_READ, i++, -1));
} catch (RemoteException e) {
Log.e(TAG, "Unable to send Message", e);
}
}
}
When i try to send the message without the while(true) it works fine, but like i described above i simply didn't receive any message on the handler.
Can someone help me with this issue ?
I think the service is running on the UI thread. Thus if you have an endless loop running, the Activity will never get any CPU time to respond to the message.
Instead of doing while (true) {...}, allocate a Handler. You can use its various post methods to do things repeatedly at timed intervals, or even as fast as possible, without totally blocking all other activity on the UI thread.