Please understand that I am using Google Translator because I do not understand English well.
I am currently working on an application that draws an EMG sensor value sent by Arduino via Bluetooth communication and a smartphone draws a graph based on that value.
Currently the application configuration has one activity and one fragment.
The Bluetooth function is in the activity and the graph is in the fragment.
I want to have the graph drawn only when the value comes in via Bluetooth communication. What should I do?
The code now depends on the fact that the fragment receives a value, even though the fragment is requesting a value.
Fragment
private void feedMultiple() {
if (thread != null)
thread.interrupt();
final Runnable runnable = new Runnable() {
#Override
public void run() {
addEntry();
}
};
thread = new Thread(new Runnable() {
#Override
public void run() {
while (loop) {
// Don't generate garbage runnables inside the loop
getActivity().runOnUiThread(runnable);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
break;
}
}
}
});
thread.start();
}
Activity
void beginListenForData() {
final Handler handler = new Handler();
readBufferPosition = 0;
readBuffer = new byte[1024];
mWorkerThread = new Thread(new Runnable()
{
#Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
try {
int byteAvailable = mInputStream.available();
if(byteAvailable > 0) {
byte[] packetBytes = new byte[byteAvailable];
mInputStream.read(packetBytes);
for(int i=0; i<byteAvailable; i++) {
byte b = packetBytes[i];
if(b == mCharDelimiter) {
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes,"UTF-8");
readBufferPosition = 0;
handler.post(new Runnable(){
#Override
public void run() {
//raw = data.split("#");
bundle.putString("yValue1", data);
}
});
}
else {
readBuffer[readBufferPosition++] = b;
}
}
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "데이터 수신 중 오류가 발생 했습니다.", Toast.LENGTH_LONG).show();
finish();
}
}
}
});
mWorkerThread.start();
}
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;
}
}
We have an main activity with a Text View which is requested to auto-retrieve data from TCP server in LAN.
We enabled AsyncTask in updateData() to call Connect to call Handler to update TextView named mTvVoc, and refresh connection by beginConnect().
The problem is the mTvVoc is not updated, it seems the AsyncTask does not function as expected?
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
updateData();
}
public void updateData(final String order) {
Connect(HOST, PORT, order);
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
System.out.println("get data from order--->" + order);
beginConnect(HOST, PORT, order);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}.execute();
}
public String Connect(final String HOST, final int PORT, final String OderType) {
new Thread(new Runnable() {
#Override
public void run() {
try {
socket = new Socket(HOST, PORT);
bufferedInputStream = new BufferedInputStream(socket.getInputStream());
System.out.println("bufferedInputStream--->" + bufferedInputStream);
printWriter = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
if (socket.isConnected()) {
if (!socket.isOutputShutdown()) {
printWriter.println(Integer.toHexString(Integer
.parseInt(OderType)));
}
}
while (true) {
if (!socket.isClosed() && socket.isConnected() && !socket.isInputShutdown()) {
int temp = 0;
byte[] buf = new byte[1024];
while ((temp = bufferedInputStream.read(buf)) != -1) {
isConn(socket);
Log.d("Data received", new String(buf, 0, temp));
acceptinfo = new String(buf, 0, temp);
System.out.println("Data received====》" + acceptinfo);
Message message = new Message();
message.what = 1;
message.obj = acceptinfo;
handler.sendMessage(message);
}
}
}
} catch (UnknownHostException e) {
System.out.println("UnknownHostException-->connection failed");
stopConnect();
e.printStackTrace();
} catch (IOException e) {
System.out.println("IOException-->connection failed");
stopConnect();
e.printStackTrace();
}
}
}).start();
return acceptinfo;
}
public String beginConnect(final String HOST, final int PORT, final String OderType) {
new Thread(new Runnable() {
#Override
public void run() {
try {
socket = new Socket(HOST, PORT);
bufferedInputStream = new BufferedInputStream(socket.getInputStream());
System.out.println("bufferedInputStream--->" + bufferedInputStream);
printWriter = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
if (socket.isConnected()) {
if (!socket.isOutputShutdown()) {
printWriter.println(Integer.toHexString(Integer.parseInt(OderType)));
}
}
} catch (UnknownHostException e) {
System.out.println("UnknownHostException-->connection failed");
stopConnect();
e.printStackTrace();
} catch (IOException e) {
System.out.println("IOException-->connection failed");
stopConnect();
e.printStackTrace();
}
}
}).start();
return acceptinfo;
}
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.i("message", msg.obj.toString());
if (msg.what == 0) {
mIvContent.setImageResource(R.drawable.wangluo_gray);
Toast.makeText(MainActivity.this, "Server connection failed", Toast.LENGTH_SHORT).show();
reGetData();
}
if (msg.what == 1) {
String info = msg.obj.toString();
if (info.length() != 18) {
mIvContent.setImageResource(R.drawable.wangluo_gray);
System.out.println("data verification failed");
reGetData();
return;
}
String iszeroupString = info.substring(1, 3);
String temperature = Integer.toString(Integer.parseInt(info.substring(3, 5), 16));
String vocValue = Integer.toString(Integer.parseInt(info.substring(7, 9), 16));
mTvVoc.setText(getVOC((Integer.valueOf(vocValue ) / 100.00)));
}
}
}
You cannot directly communicate from background thread to UI thread to
update any UI components.
Use this in your background thread to update textview from AsyncTask.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Log.d("UI thread", "I am the UI thread");
// update your text here
}
});
To update on UI, you need to run the codes in UIThread. See code below and put in your handler:
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i("message", msg.obj.toString());
if (msg.what == 0) {
mIvContent.setImageResource(R.drawable.wangluo_gray);
Toast.makeText(MainActivity.this, "Server connection failed", Toast.LENGTH_SHORT).show();
reGetData();
}
if (msg.what == 1) {
String info = msg.obj.toString();
if (info.length() != 18) {
mIvContent.setImageResource(R.drawable.wangluo_gray);
System.out.println("data verification failed");
reGetData();
return;
}
String iszeroupString = info.substring(1, 3);
String temperature = Integer.toString(Integer.parseInt(info.substring(3, 5), 16));
String vocValue = Integer.toString(Integer.parseInt(info.substring(7, 9), 16));
mTvVoc.setText(getVOC((Integer.valueOf(vocValue ) / 100.00)));
}
}
});
Pretty bad to code that handler to update the gui. Do away with it as AsyncTask provides already the functionality to do so.
You should have looked better at the many examples.
Use publishProgress() and onProgressUpdate() to update a progress bar and/or other gui elements.
And do not wrap your code in a thread if it has to be executed in doInBackground().
void beginListenForData() {
//final Handler handler = new Handler();
final Handler handler = new Handler(Looper.getMainLooper());
final byte delimiter = 10; //This is the ASCII code for a newline character
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[2048];
workerThread = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted() && !stopWorker) {
try {
int bytesAvailable = mmInputStream.available();
if (bytesAvailable > 0) {
byte[] packetBytes = new byte[bytesAvailable];
mmInputStream.read(packetBytes);
for (int i = 0; i < bytesAvailable; i++) {
byte b = packetBytes[i];
if (b == delimiter) {
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
final String data = new String(encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable() {
public void run() {
//myLabel.setText(data);
dataArray = new String []{data};
//Log.d("dataArray", data);
}
});
} else {
readBuffer[readBufferPosition++] = b;
}
}
}
} catch (IOException ex) {
stopWorker = true;
}
}
}
});
public class Bluetooth_dataDisplay extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
String MAC = getIntent().getStringExtra("MAC");
mAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice bluetoothDevice = mAdapter.getRemoteDevice(MAC);
// Initiate a connection request in a separate thread
ConnectingThread t = new ConnectingThread(bluetoothDevice);
t.start();
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerAdapter(dataArray);
recyclerView.setAdapter(adapter);
}
Begindata() is call in the connected thread. I trying to get the dataarray back to the Bluetooth_dataDisplay extends AppCompatActivity and call it in the oncreate. How do I senddataarray back to main activity? Please help any expert. I had look at post that talked about thread data send back to main UI. But I am very new to it, so it quite confusing. :( Help please.
Replace handler call under your beginListenForData() function
handler.post(new Runnable() {
public void run() {
//myLabel.setText(data);
dataArray = new String[]{data};
//Log.d("dataArray", data);
}
});
with runOnUiThread()
runOnUiThread(new Runnable() {
#Override
public void run() {
//myLabel.setText(data);
dataArray = new String[]{data};
//Log.d("dataArray", data);
}
});
Everything under runOnUiThread() runs on UI/Main thread.
Unfortunately I can't send a simple String message via UDP. The code is simple. I created a SendLocation class and I want send a location message with this. Everytime I try it, I've got the "can't send it" message. Any idea? Thanks a lot!
(messDelay, messCount, ip, port are EditTexts)
private class SendLocation extends Thread {
private String message = "";
private volatile boolean flag = true;
public SendLocation(String message) {
this.message = message;
}
#Override
public void run() {
while (flag) {
try {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Server.this, message, Toast.LENGTH_SHORT).show();
}
});
byte[] data = message.getBytes();
DatagramSocket socket = new DatagramSocket();
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(ip.getText().toString()),
Integer.valueOf(port.getText().toString()));
for (int i = 0; i < Integer.valueOf(messCount.getText().toString()); i++) {
socket.send(packet);
Thread.sleep(Integer.valueOf(messDelay.getText().toString()));
}
socket.close();
} catch (Exception e) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(Server.this, "Can't send it", Toast.LENGTH_SHORT).show();
}
});
}
flag = false;
}
}
}
In my code I have to send a message as long as my ToggleButton is checked. To prevent the UI Thread from freezing, I put the action in a seperate Thread.
My Problem is, that it still freezes, but I don't know why
This is the relevant code:
private ToggleButton.OnClickListener lightMirrorOnClickListener = new ToggleButton.OnClickListener() {
#Override
public void onClick(View v) {
if (lightMirrorBtn.isChecked()) {
lightThread = new LightThread();
lightThread.start();
} else if(!lightMirrorBtn.isChecked()) {
lightThread.interrupt();
}
}
};
class LightThread extends Thread {
Handler lightHandler = new Handler();
Runnable light = new Runnable() {
public void run() {
while (lightMirrorBtn.isChecked()) {
lightTxMsg.frameFormat = ConstantList.STANDARD_FRAME;
lightTxMsg.frameType = ConstantList.DATA_FRAME;
lightTxMsg.dataLength = (byte) 8;
lightTxMsg.messageID = 0x3C1;
int[] messageArray = AMBI_LIGHT;
for (int i = 0; i < lightTxMsg.dataLength; i++) {
lightTxMsg.data[i] = messageArray[i];
}
returnCode = demoController.transmitMessage(lightTxMsg,
ConstantList.BINARY_FORMAT);
}
}
};
public void run() {
while (!isInterrupted()) {
try {
Thread.sleep(60);
lightHandler.post(light);
} catch (InterruptedException e) {
break;
}
}
}
}
EDIT:
This was the solution for the problem:
private ToggleButton.OnCheckedChangeListener lightMirrorOnClickListener = new ToggleButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked == true) {
new Thread(new Runnable() {
public void run() {
lightTxMsg.frameFormat = ConstantList.STANDARD_FRAME;
lightTxMsg.frameType = ConstantList.DATA_FRAME;
lightTxMsg.dataLength = (byte) 8;
lightTxMsg.messageID = 0x3C1;
int[] messageArray = AMBI_LIGHT_ON;
for (int i = 0; i < lightTxMsg.dataLength; i++) {
lightTxMsg.data[i] = messageArray[i];
}
returnCode = demoController.transmitMessage(lightTxMsg,
ConstantList.BINARY_FORMAT);
}
}).start();
} else if (!isChecked) {
new Thread(new Runnable() {
public void run() {
lightTxMsg.frameFormat = ConstantList.STANDARD_FRAME;
lightTxMsg.frameType = ConstantList.DATA_FRAME;
lightTxMsg.dataLength = (byte) 8;
lightTxMsg.messageID = 0x3C1;
int[] messageArray = AMBI_LIGHT_OFF;
for (int i = 0; i < lightTxMsg.dataLength; i++) {
lightTxMsg.data[i] = messageArray[i];
}
returnCode = demoController.transmitMessage(lightTxMsg,
ConstantList.BINARY_FORMAT);
}
}).start();
}
}
};
Handler lightHandler = new Handler();
When you create your handler your thread has not yet started. It is just being created. So, according to the Handler's default constructor documentation this handler is associated "with the Looper for the current thread" ... which is currently the main(UI) thread. So you post your messages on the main thread.
You don't need a Handler to post your runnable on. You can either:
Create a Thread and specify it's actions in the run() method
or
Pass a Runnable to your thread that will be executed in your thread using the Thread(Runnable) constructor
Here are the basic articles about Threads:
Processes and threads
Keeping your app responsive
Specifying the Code to Run on a Thread