I would like to ask a question about my code in Wifi client communication. I am communicating with a Raspberry Pi as server.
The architecture of my code is:
Main Activity: I have the Handler class and I launch in the OnCreat the first Thread (Thread1) that takes care of establishing the wifi connection.
public class MainActivity extends AppCompatActivity {
public int serverPort = 40000;
public String serverIP = "10.177.86.212";
public WiFiConnector wifiConnection;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextWE = (EditText) findViewById(R.id.editText_WE);
wifiConnection = new WiFiConnector(serverIP, serverPort);
Handler mHandler = new MyHandler();
WiFiConnector.Thread1 = new Thread(new WiFiConnector.Thread1(mHandler,true));
WiFiConnector.Thread1.start();
}
private class MyHandler extends Handler {
private byte[] bytes = null;
#Override
public void handleMessage(Message msg) {
bytes = msg.getData().getByteArray("KEY");
if(bytes!= null){
for (int i = 0; i < bytes.length; i++){
Log.d("Data received", "value " + (0xFF & bytes[i]) );
}
for (int i=0; i<bytes.length; i++) {
editTextWE.setText(editTextWE.getText()+ "Server says: " + bytes.length + " "+ (0xFF & bytes[i]) + "\n");
}
}
}
}
}
WifiConnector class: Thread1 and Thread2 are sharing the handler coming from the Main Activity. Thread1 send a command to Raspberry Pi to let it start sending data. Thread2 is dedicated to read data received from the server.
public class WiFiConnector {
static String serverIP;
static int serverPort;
public static Thread Thread1 = null;
//Constructor
public WiFiConnector(String IP, int port) {
serverIP = IP;
serverPort = port;
}
public static class Thread1 extends Thread implements Runnable {
private Handler handler1;
boolean firsttime = false;
OutputStream out ;
public Thread1(Handler handler_1, boolean firsttime) {
this.handler1 = handler_1;
this.firsttime = firsttime;
}
public void run() {
Socket socket = null;
try {
//Writing to a Socket
InetAddress serverAddress = InetAddress.getByName(serverIP);
socket = new Socket(serverAddress, serverPort);
out = new DataOutputStream(socket.getOutputStream());
if(firsttime){
//I send "B" to Raspberry to let him start sending data
out.write("B".getBytes());
this.fisrttime = false;
}
Thread2 comThread = new Thread2(socket, handler1);
new Thread(comThread).start();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static class Thread2 implements Runnable {
public Socket clientSocket;
private Handler handler_2;
public DataInputStream in;
public byte[] bytes = new byte[13];
public Message msg;
public Thread2(Socket clientSocket, Handler handler2) {
this.clientSocket = clientSocket;
this.handler_2 = handler2;
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
if (Looper.myLooper() == null) {
Looper.prepare();
}
this.in = new DataInputStream(clientSocket.getInputStream());
in.readFully(bytes);
if (in != null) {
for (int i = 0; i < bytes.length; i++){
Log.d("Data received", "valuewifi " + (0xFF & bytes[i]) );
}
msg = new Message();
Bundle b = new Bundle();
b.putByteArray("KEY", bytes);
msg.setData(b);
handler_2.sendMessage(msg);
} else {
Thread1 = new Thread(new Thread1(handler_2,false));
Thread1.start();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
Looper.loop();
}
}
}
NOW THE PROBLEM IS:
I am receiving correctly my data (package of 13 bytes each) from Raspberry Pi, indeed:
Log.d("Data received", "valuewifi " + (0xFF & bytes[i]) );
prints correctly my values. Then I create the message to be sent to the handler in MainActivity. the Bundle contains (I have verified) the same values of the input stream received, but the message printed in the Handler of the MainActivity:
Log.d("Data received", "value " + (0xFF & bytes[i]) );
substitutes the first byte value of each message (I am trying to get 2 package each communications with the RPi) with 66 that actually is the ASCII code of "B" that I sent to start the data sending from Raspberry Pi.
PLEASE DO YOU HAVE ANY IDEA ON WHY THIS IS HAPPENING?
Many thanks for your help in advance!:)
Well, I have found that in Thread2 if I put
public byte[] bytes = new byte[13];
inside the run{..} before
in.readFully(bytes);
The exchange of message happens perfectly. Otherwise I only get in MainActivity the last package of byte received from the server.
Any suggestion on why does it happen?
Thanks!
Related
I try to build an app, that vibrates with a certain pattern depending on the value of a variable that comes constantly with a stream from a video game.
I managed to display telemetry data on the TextView continiously. What I want is the phone to vibrate for a certain lenght in ms or pattern, depending on the value of gforce in Thread2. What I would like to achieve is, the following sequence. Read the stream, display ias, gforce and vertical on the TextView, check gforce value, if value>=2, vibrate(choose length or pattern by gforce value), pause 500ms, repeat.
I know about the lack of connection security in my code, but that is something for later.
I do have the problem of thread management here, that I cant solve. The stream comes from a Java server socket and has an output of around one line per ms.
This the code I try to make that work with.
public class MainActivity extends AppCompatActivity {
Thread Thread1 = null;
EditText etIP, etPort;
TextView tvMessages;
String SERVER_IP;
int SERVER_PORT;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etIP = findViewById(R.id.etIP);
etPort = findViewById(R.id.etPort);
etIP.setText("192.168.178.61");
etPort.setText("31091");
tvMessages = findViewById(R.id.tvMessages);
Button btnConnect = findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onClick(View v) {
tvMessages.setText("");
SERVER_IP = etIP.getText().toString().trim();
SERVER_PORT = Integer.parseInt(etPort.getText().toString().trim());
Thread1 = new Thread(new Thread1());
Thread1.start();
}
});
}
PrintStream output;
BufferedReader input;
Socket socket;
String message;
class Thread1 implements Runnable {
#Override
public void run() {
try {
socket = new Socket(SERVER_IP, SERVER_PORT);
socket.setTcpNoDelay(true);
output = new PrintStream(socket.getOutputStream(), true);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
runOnUiThread(new Runnable() {
#Override
public void run() {
tvMessages.setText("Connected\n");
}
});
new Thread(new Thread2()).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Thread2 implements Runnable {
private double ias;
private double gforce;
private double vertical;
#Override
public void run() {
while (!(socket.isClosed())) {
try {
message = input.readLine();
if (message != null && message.contains("IAS")) {
ias = Double.parseDouble(message.substring(5, (message.indexOf(" ", 5))));
gforce = Double.parseDouble(message.substring(message.indexOf("Gy:") + 4, message.indexOf("Gz:") - 1));
vertical = Double.parseDouble(message.substring(message.indexOf("vertical:") + 10, message.indexOf("Gx:") - 1));
}
if (message != null && !(message.equals("exit"))) {
runOnUiThread(new Runnable() {
#Override
public void run() {
System.out.println(message);
tvMessages.setText("IAS: " + ias + "\n" +
"G: " + gforce + "\n" +
"Vertical: " + vertical + "\n");
}
});
//do trigger Vibration handler and make the phone vibrate in a pattern relative to gforce
new VibrationHandler((int)gforce).start();
//at this point sleep for n ms
} else {
Thread1 = new Thread(new Thread1());
Thread1.start();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class VibrationHandler extends Thread{
int pattern;
public VibrationHandler(int pattern){
this.pattern=pattern;
}
public void run(){
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
// Vibrate for 500 milliseconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(pattern*50, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
//deprecated in API 26
v.vibrate(pattern*50);
}
}
}
}
Thank you a lot for your help.
Hello I use android thing on raspberry pi 3, I have a problem my app use UsbToSerial and then my app can Tx but cannot Rx data when app run longtime but in first period of work my app can Rx data and app can Tx alway times
How can I fix the problem?
And this is my code
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UartService uart_api = new UartService();
uart_api.UartInit("USB1-1.2:1.0", 9600);
}
UartService.java
public class UartService extends Activity {
private static final String TAG = "LoopbackActivity";
// UART Configuration Parameters
private static final int DATA_BITS = 8;
private static final int STOP_BITS = 1;
private static final int CHUNK_SIZE = 512;
private UartDevice mLoopbackDevice;
private void openUart(String name, int baudRate) throws IOException {
mLoopbackDevice = PeripheralManager.getInstance().openUartDevice(name);
// Configure the UART
mLoopbackDevice.setBaudrate(baudRate);
mLoopbackDevice.setDataSize(DATA_BITS);
mLoopbackDevice.setParity(UartDevice.PARITY_NONE);
mLoopbackDevice.setStopBits(STOP_BITS);
}
public void UartInit(String UartName, int baudrate){
PeripheralManager manager = PeripheralManager.getInstance();
List<String> deviceList = manager.getUartDeviceList();
if (deviceList.isEmpty()) {
Log.i(TAG, "No UART port available on this device.");
} else {
Log.i(TAG, "List of available devices: " + deviceList);
}
// Attempt to access the UART device
try {
openUart(UartName, baudrate);
// Read any initially buffered data
Thread thread_read = new Thread(new ThreadUart(123));
thread_read.start();
} catch (IOException e) {
Log.e(TAG, "Unable to open UART device", e);
}
}
public class ThreadUart implements Runnable {
private int data_in;
public ThreadUart(int in) {
this.data_in = in;
}
#Override
public void run() {
while(true){
///////// Test Rx //////
if (mLoopbackDevice != null) {
// Loop until there is no more data in the RX buffer.
try {
byte[] buffer = new byte[CHUNK_SIZE];
int read;
while ((read = mLoopbackDevice.read(buffer, buffer.length)) > 0) { // <<<< when run long time this cannot Rx data
mLoopbackDevice.write(buffer, read);
}
} catch (IOException e) {
Log.w(TAG, "Unable to transfer data over UART", e);
}
}
// sleep 1 sec.
///////// Test Tx //////
String string = "Hello\r\n";
byte[] b = string.getBytes(StandardCharsets.UTF_8);
try {
mLoopbackDevice.write(b, b.length); // <<<< can Tx work!! always time
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
finarly I follow Example example, It work !! in example use felHR85’s USBSerial library
however I don't know cause of Rx lost when use UART API and then run long time
I have this code on which I am receiving data through the android phone
public void run() {
try {
while(true) {
final String hey;
int server_port = 9875;
byte[] message = new byte[255];
DatagramPacket p = new DatagramPacket(message, message.length);
DatagramSocket s = new DatagramSocket(server_port);
s.receive(p);
hey = new String( message, 0 , p.getLength());
Log.d("MESSAGE: ", "Message is:" + hey);
s.close();
//codes for setting the Ultrasonic Sensor
if (hey.equals("Strainer is Empty")){
runOnUiThread(new Runnable() {
#Override
public void run() {
Empty.setAlpha((float) 0.8);
Full.setAlpha((float) 0.2);
SFull.setAlpha((float) 0.2);
AFull.setAlpha((float) 0.2);
}
});
}
if(hey.equals("Strainer is Full")){
runOnUiThread(new Runnable() {
#Override
public void run() {
Full.setAlpha((float) 0.8);
Empty.setAlpha((float)0.2);
SFull.setAlpha((float) 0.2);
AFull.setAlpha((float) 0.2);
}
});
}
The problem is whenever i go back to my main activity and call this one, error seems to point out on the Datagram Socket. I have read about binding the address but i do not know on how to implement it
I solve the issue when i try to implement it this way
DatagramSocket s = new DatagramSocket(null);
s.setReuseAddress(true);
s.setBroadcast(true);
s.bind(new InetSocketAddress(server_port));
I am making an inhouse navigation application with google glass. I am sending orientation data from the google glass to the android phone true WIFI (SOCKETS). My code is running fine and ok, but after about 25 seconds the receiving thread (on the phone) stops for 5 seconds and then continues, this is very annoying.
I tested this by closing the connection (when i see the thread becoming unresponsive) and it takes 5 seconds for the debugger to hit the breakpoint that i set in the application (obviously this is the thread that is causing the problem)
The weird thing is that the UI thread is still responsive i can move every object in the activity, it is just the specific thread containing the connection (Socket) that is getting blocked. I will post the code (i suspect memory leak) so that maybe someone can give me a indication why this could be happening, any advice is welcome.
CHANGED CODE AFTER COMMENT:
public class GlassOrientationSocket implements Runnable {
private final static int PORT = 6604;
private static Socket mClientSocket;
private static String mResult;
private static Handler handler = null;
private static boolean threadIsRunning;
private static BufferedReader inputReader;
public GlassOrientationSocket(Handler handler) {
this.handler = handler;
this.threadIsRunning = true;
}
public void terminateThread() {this.threadIsRunning = false;}
#SuppressWarnings("deprecation")
#Override
public void run() {
//Replace this with ip-address of android server (aka Google glass) // put ip on NFC TAG for easier configuration
String ServerIP = SECRET;
//port should be same as ServerSocketActivity
try {
mClientSocket = new Socket(serverIP, PORT);
inputReader = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
int angleCutter;
int orientationCutter;
float[] results = new float[2];
while(threadIsRunning)
{
if (((mResult = inputReader.readLine()) != null)) {
angleCutter = mResult.indexOf("|", 0);
orientationCutter = mResult.indexOf("|", angleCutter + 1);
results[0] = Float.valueOf(mResult.substring(0, angleCutter));
results[1] = Float.valueOf(mResult.substring(angleCutter + 1, orientationCutter));
Message msg = new Message();
msg.arg1 = 1;
msg.obj = results;
handler.sendMessage(msg);
} else {
if (mClientSocket != null) mClientSocket.close();
Message msg = new Message();
msg.arg1 = 2;
handler.sendMessage(msg);
threadIsRunning = false;
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}}
////
public class CompassMonitor {
static protected ArrayList<CompassListener> listeners=new ArrayList<CompassListener>();
static protected GlassOrientationSocket monitor=null;
private static Handler msgHandler = new Handler();
private static CompassListener orientationListener;
private static float[] dataReturned = new float[2];
static public synchronized void registerListener(Context context,CompassListener listener){
if(listeners.size()==0){
orientationListener = listener;
monitor=new GlassOrientationSocket(msgHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.arg1) {
case 1:
dataReturned = (float[])msg.obj;
notifyListeners(dataReturned[0],dataReturned[1],"Useless Parameter");
break;
case 2:
unregisterListener(orientationListener);
monitor.terminateThread();
}
}
});
Thread t = new Thread(monitor);
t.start();
}
listeners.add(listener);
}
static synchronized public void unregisterListener(CompassListener listener){
if (listeners != null && listener != null)
listeners.remove(listener);
}
static synchronized protected void notifyListeners(float azimuth,float angle, String direction){
for(CompassListener l:listeners){
try{
l.onCompassChanged(azimuth,angle,direction);
}catch(Exception ex){}
}
}}
From a Service I am trying to start another IntentService but it is giving me an error when trying to pass in a new ResultReceiver with a new Handler as the parameter.
Can't figure out why it is giving me this error. Please help!
Line 797 in SocketIOService which the error has occurred is:
downloadIntent.putExtra(DownloadService.KEY_RECEIVER, new DownloadReceiver(new Handler()));
StackTrace Error
06-05 19:51:10.417: E/AndroidRuntime(7716): FATAL EXCEPTION: Thread-6358
06-05 19:51:10.417: E/AndroidRuntime(7716): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
06-05 19:51:10.417: E/AndroidRuntime(7716): at android.os.Handler.<init>(Handler.java:121)
06-05 19:51:10.417: E/AndroidRuntime(7716): at com.walintukai.lfdate.SocketIOService$9.run(SocketIOService.java:797)
06-05 19:51:10.417: E/AndroidRuntime(7716): at java.lang.Thread.run(Thread.java:856)
Code starting IntentService
new Thread(new Runnable() {
public void run() {
try {
JSONArray array = json.getJSONArray(0);
if (array.length() > 0) {
ArrayList<String> coverPhotos = new ArrayList<String>();
for (int i = 0; i < array.length(); i++) {
String id = array.getJSONObject(i).getString(KEY_ID);
String name = array.getJSONObject(i).getString(KEY_NAME);
String genre = array.getJSONObject(i).getString(KEY_GENRE);
String platform = "";
JSONArray platformArray = array.getJSONObject(i).getJSONArray(KEY_PLATFORM);
for (int p = 0; p < platformArray.length(); p++) {
if (p == 0) { platform = platformArray.getString(p); }
else { platform = platform + ", " + platformArray.getString(p); }
}
String coverPhoto = "";
JSONArray coverPhotoArray = array.getJSONObject(i).getJSONArray(KEY_COVER_PHOTO);
for (int c = 0; c < coverPhotoArray.length(); c++) {
if (c == 0) { coverPhoto = coverPhotoArray.getString(c); }
else { coverPhoto = coverPhoto + ", " + coverPhotoArray.getString(c); }
}
Game game = new Game(id, name, genre, platform, coverPhoto);
if (!db.doesGameExist(id)) { db.createGame(game); }
else { db.updateGame(game); }
coverPhotos.add(coverPhoto);
}
Intent downloadIntent = new Intent(SocketIOService.this, DownloadService.class);
downloadIntent.putStringArrayListExtra(DownloadService.KEY_COVER_PHOTOS, coverPhotos);
downloadIntent.putExtra(DownloadService.KEY_RECEIVER, new DownloadReceiver(new Handler()));
startService(downloadIntent);
}
}
catch (JSONException e) { e.printStackTrace(); }
}
}).start();
ResultReceiver Code
private class DownloadReceiver extends ResultReceiver {
public DownloadReceiver(Handler handler) {
super(handler);
}
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
if (resultCode == DownloadService.RESULT_FINISHED) {
Log.i("GAME COVER DOWNLOADS", "COMPLETE");
if (mOnServiceListener != null) {
mOnServiceListener.onGameListUpdated();
}
}
}
}
IntentService Code
public class DownloadService extends IntentService {
public static final String KEY_COVER_PHOTOS = "coverPhotos";
public static final String KEY_RECEIVER = "receiver";
public static final int RESULT_FINISHED = 1000;
private static final String URL_GAME_COVER = "https://test.com/images/game_cover/";
public DownloadService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
ArrayList<String> coverPhotos = intent.getStringArrayListExtra(KEY_COVER_PHOTOS);
ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra(KEY_RECEIVER);
for (String coverPhoto : coverPhotos) {
// TODO: implement code to handle multiple photos
try {
URL url = new URL(URL_GAME_COVER + coverPhoto);
URLConnection connection = url.openConnection();
connection.connect();
// This will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
// Download the file
InputStream input = new BufferedInputStream(url.openStream());
String filepath = this.getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString() + "/" + coverPhoto;
OutputStream output = new FileOutputStream(filepath);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
catch (IOException e) { e.printStackTrace(); }
}
receiver.send(RESULT_FINISHED, null);
}
}
What type is your SocketIOService ? Is it really a Service or not?
If you create a Handler in a common thread which is not an Activity or Service,you should call Looper.prepare();first ,then a message bus is started in the thread and the handler works well.Or you will got the exception because general thread do not have the message bus(just a infinite loop in which the messages are consumed).
EDIT: Oh,your handler is not in your Service,but in the sub-thread(in your new Thread(xxx).start),so this is a general thread which do not have a message bus.I think you should initalize your handler outside and then use it which is a handler of a Service.