I am having a problem with creating a socket and sending messages from an android app to a raspberry pi. I used this example from the following site: http://android-er.blogspot.nl/2016/05/android-client-example-2-communicate.html , this to understand how sockets work. But while I use AsyncTask, I still get an android.os.NetworkOnMainThreadException. This is my MainActivity:
public class MainActivity extends AppCompatActivity {
EditText editTextAddress, editTextPort, editTextMsg;
Button buttonConnect, buttonDisconnect, buttonSend;
TextView textViewState, textViewRx;
ClientHandler clientHandler;
ClientThread clientThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextAddress = (EditText) findViewById(R.id.address);
editTextPort = (EditText) findViewById(R.id.port);
editTextMsg = (EditText) findViewById(R.id.msgtosend);
buttonConnect = (Button) findViewById(R.id.connect);
buttonDisconnect = (Button) findViewById(R.id.disconnect);
buttonSend = (Button)findViewById(R.id.send);
textViewState = (TextView)findViewById(R.id.state);
textViewRx = (TextView)findViewById(R.id.received);
buttonDisconnect.setEnabled(false);
buttonSend.setEnabled(false);
buttonConnect.setOnClickListener(buttonConnectOnClickListener);
buttonDisconnect.setOnClickListener(buttonDisConnectOnClickListener);
buttonSend.setOnClickListener(buttonSendOnClickListener);
clientHandler = new ClientHandler(this);
}
View.OnClickListener buttonConnectOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View arg0) {
MainActivity.this.startService(new Intent(MainActivity.this,
ClientThread.class));
clientThread = new ClientThread(
editTextAddress.getText().toString(),
Integer.parseInt(editTextPort.getText().toString()),
clientHandler);
clientThread.execute();
buttonConnect.setEnabled(false);
buttonDisconnect.setEnabled(true);
buttonSend.setEnabled(true);
}
};
View.OnClickListener buttonDisConnectOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if(clientThread != null){
clientThread.setRunning(false);
}
}
};
String msgToSend;
View.OnClickListener buttonSendOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if(clientThread != null){
msgToSend = editTextMsg.getText().toString();
clientThread.txMsg(msgToSend);
}
}
};
private void updateState(String state){
textViewState.setText(state);
}
private void updateRxMsg(String rxmsg){
textViewRx.append(rxmsg + "\n");
}
private void clientEnd(){
clientThread = null;
textViewState.setText("clientEnd()");
buttonConnect.setEnabled(true);
buttonDisconnect.setEnabled(false);
buttonSend.setEnabled(false);
}
public static class ClientHandler extends Handler {
public static final int UPDATE_STATE = 0;
public static final int UPDATE_MSG = 1;
public static final int UPDATE_END = 2;
private MainActivity parent;
public ClientHandler(MainActivity parent) {
super();
this.parent = parent;
}
#Override
public void handleMessage(Message msg) {
switch (msg.what){
case UPDATE_STATE:
parent.updateState((String)msg.obj);
break;
case UPDATE_MSG:
parent.updateRxMsg((String)msg.obj);
break;
case UPDATE_END:
parent.clientEnd();
break;
default:
super.handleMessage(msg);
}
}
}
}
This the ClientThread.java code:
public class ClientThread extends AsyncTask<Void, Void, Void>{
String dstAddress;
int dstPort;
private boolean running;
MainActivity.ClientHandler handler;
Socket socket;
PrintWriter printWriter;
BufferedReader bufferedReader;
public ClientThread(String addr, int port, MainActivity.ClientHandler handler) {
super();
dstAddress = addr;
dstPort = port;
this.handler = handler;
}
public void setRunning(boolean running){
this.running = running;
}
private void sendState(String state){
handler.sendMessage(
Message.obtain(handler,
MainActivity.ClientHandler.UPDATE_STATE, state));
}
public void txMsg(String msgToSend){
if(printWriter != null){
printWriter.println(msgToSend);
}
}
#Override
protected Void doInBackground(Void... arg0) {
System.out.println("In doinbackground");
sendState("connecting...");
running = true;
try {
socket = new Socket(dstAddress, dstPort);
sendState("connected");
OutputStream outputStream = socket.getOutputStream();
printWriter = new PrintWriter(outputStream, true);
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
while (running) {
//bufferedReader block the code
String line = bufferedReader.readLine();
if (line != null) {
handler.sendMessage(
Message.obtain(handler,
MainActivity.ClientHandler.UPDATE_MSG, line));
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (printWriter != null) {
printWriter.close();
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
handler.sendEmptyMessage(MainActivity.ClientHandler.UPDATE_END);
return null;
}
}
This is the error I'm getting:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.zerocj.projectsocked, PID: 2415
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:157)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:295)
at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
at java.io.BufferedWriter.flush(BufferedWriter.java:254)
at java.io.PrintWriter.newLine(PrintWriter.java:482)
at java.io.PrintWriter.println(PrintWriter.java:629)
at java.io.PrintWriter.println(PrintWriter.java:740)
at com.example.zerocj.projectsocked.ClientThread.txMsg(ClientThread.java:47)
at com.example.zerocj.projectsocked.MainActivity$3.onClick(MainActivity.java:85)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22260)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
You're calling your txMsg() method from a click listener which runs on the UI thread. And this method seems to be writing to a Writer that wired up to a socket.
If your wanna exchange messages back and forth between background thread and UI thread, maybe a better idea that an AsyncTask would be a Thread with Looper and handlers to pass the messages along from one thread to the other.
Please check your stack trace. It says use strict mode in your code
int SDK_INT = android.os.Build.VERSION.SDK_INT;
if (SDK_INT > 8)
{
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
// Where you get exception write that code inside this.
}
Thanks hope this help you.
Related
I called postValue() but MutableLivdata does not update its value.
When I print Log in UserInfoViewModel at setNetworkObj() and setUserName(), value from parameter nothing wrong(parameter arrived well).
But userName.getValue() print null.
So I tried postValue() in Handler and runOnUiThread but nothing work either.
I'd really appreciate it if you could tell me how to figure it out.
this is my code..
UserInfoViewModel.java
public class UserInfoViewModel extends ViewModel {
private MutableLiveData<NetworkObj> networkObj = new MutableLiveData<>();
private MutableLiveData<String> userName = new MutableLiveData<>();
public MutableLiveData<NetworkObj> getNetworkObj() {
return networkObj;
}
public void setNetworkObj(NetworkObj networkObj) {
this.networkObj.postValue(networkObj);
}
public MutableLiveData<String> getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName.postValue(userName);
}
}
LoginActivity.java
public class LoginActivity extends AppCompatActivity {
private ActivityLoginBinding binding;
private UserInfoViewModel userInfoViewModel;
public Socket socket;
public ObjectInputStream ois;
public ObjectOutputStream oos;
private NetworkUtils networkUtils;
private NetworkObj networkObj;
private String userName ="";
final String ip_addr = "10.0.2.2"; // Emulator PC의 127.0.0.1
final int port_no = 30000;
Handler mHandler = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
binding = ActivityLoginBinding.inflate(getLayoutInflater());
super.onCreate(savedInstanceState);
setContentView(binding.getRoot());
userInfoViewModel = new ViewModelProvider(this).get(UserInfoViewModel.class);
mHandler = new Handler();
binding.btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
userName = binding.etName.getText().toString();
new Thread() {
public void run() {
try {
socket = new Socket(ip_addr, port_no);
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
networkObj = new NetworkObj(socket, ois, oos);
networkUtils = new NetworkUtils(networkObj);
mHandler.post(new Runnable() {
#Override
public void run() {
userInfoViewModel.setNetworkObj(networkObj);
userInfoViewModel.setUserName(userName);
}
});
ChatMsg obj = new ChatMsg(userName, "100", "Hello");
networkUtils.sendChatMsg(obj, networkObj);
startMainActivity();
} catch (IOException e) {
Log.w("Login", e);
}
}
}.start();
}
});
}
public void startMainActivity() {
startActivity(new Intent(this, MainActivity.class));
}
}
I'm tracking the UDP messages I'm sending from my android phone on Wireshark, but the source port number changes every time I send a message.
So I have two questions:
Is this bad if I want to receive messages back? Or would it be find, just each received message comes through a different port?
If the answer to 1) is yes it is bad, then what should I do to change that?
Here's my code:
edit: Full code
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final int SERVERPORT = 1111;
public static final String SERVER_IP = "255.255.255.255";
private LinearLayout msgList;
private EditText edMessage;
private int clientTextColor;
private ClientThread clientThread;
private Thread thread;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
msgList = findViewById(R.id.msgList);
edMessage = findViewById(R.id.edMessage);
clientTextColor = ContextCompat.getColor(this, R.color.colorAccent);
handler = new Handler();
}
// Just for displaying messages on device
public TextView textView(String message, int color) {...}
public void showMessage(final String message, final int color) {
handler.post(new Runnable() {
#Override
public void run() {
msgList.addView(textView(message, color));
}
});
}
// Implementation
#Override
public void onClick(View view) {
if(view.getId() == R.id.clear) {
msgList.removeAllViews();
}
if (view.getId() == R.id.send_data) {
// Starting thread
clientThread = new ClientThread();
thread = new Thread(clientThread);
thread.start();
String clientMessage = edMessage.getText().toString().trim(); // Client's Message
showMessage(clientMessage, Color.BLUE); // Just display
if (null != clientThread) {
clientThread.sendMessage(clientMessage + "\r\n");
}
}
}
class ClientThread implements Runnable {
byte[] buffer = new byte[1024];
#Override
public void run() {
try {
while (true) {
DatagramSocket ds = new DatagramSocket(SERVERPORT);
DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
ds.receive(dp);
String serverMsg = new String(dp.getData(), 0, dp.getLength());
showMessage("Server: " + serverMsg, clientTextColor);
ds.close();
}
} catch (UnknownHostException e1) {
e1.printStackTrace();
}
}
void sendMessage(final String message) { // Called by "Send Data" button
new Thread(new Runnable() {
#Override
public void run() {
try {
byte[] msg = message.getBytes();
InetAddress ip = InetAddress.getByName(SERVER_IP);
DatagramSocket socket = new DatagramSocket();
DatagramPacket packet = new DatagramPacket(msg, msg.length, ip, SERVERPORT);
socket.setBroadcast(true);
socket.send(packet);
} catch(Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
String getTime() {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date());
}
#Override
protected void onDestroy() {
super.onDestroy();
if (null != clientThread) {
clientThread.sendMessage("Disconnect");
clientThread = null;
}
}
}
What I'm trying to do is to constantly update a TextView once I read a new line from a BufferedReader that reads serial data from a Bluetooth module. Currently, the data gets displayed once, then the connection is closed and nothing happens.
Shouldn't content() and refresh() functions call each other up endlessly, so that the connection is never closed?
Here's my code so far:
public class MainActivity extends AppCompatActivity {
static final UUID mUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
String line;
int cnt = 0;
BluetoothSocket btSocket = null;
InputStream in = null;
BufferedReader br = null;
TextView data;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = (TextView)findViewById(R.id.data);
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
System.out.println(bt.getBondedDevices());
BluetoothDevice hc06 = bt.getRemoteDevice("00:14:03:05:5A:94");
System.out.println(hc06.getName());
do {
try {
btSocket = hc06.createInsecureRfcommSocketToServiceRecord(mUUID);
System.out.println(btSocket);
btSocket.connect();
System.out.println(btSocket.isConnected());
} catch (IOException e) {
e.printStackTrace();
}
cnt++;
} while(!btSocket.isConnected()&& (cnt < 5));
content();
try {
btSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void content() {
try {
in = btSocket.getInputStream();
br = new BufferedReader(new InputStreamReader(in));
line = br.readLine();
System.out.println(line);
refresh();
} catch (IOException e) {
e.printStackTrace();
}
}
private void refresh(){
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
#Override
public void run() {
data.setText(line);
content();
}
};
handler.postDelayed(runnable, 100);
}
}
I would like to modify dynamically an ImageView (setImageResource) in ServerSocket
I used :
public class MainActivity extends AppCompatActivity {
private SocketServer server;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
server = new SocketServer(MainActivity.this);
}
}
public class SocketServer {
private final Context context;
public SocketServer(Context context) {
this.context = context;
new Thread(new SocketServerThread()).start();
}
private class SocketServerThread implements Runnable {
private String read;
private BufferedInputStream reader = null;
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress("192.168.1.1", 11000));
while (true) {
Socket socket;
socket = serverSocket.accept();
//On attend la demande du client
reader = new BufferedInputStream(socket.getInputStream());
read = Strings.getBuffered(reader);
((Activity) context).runOnUiThread(new Runnable() {
final ImageView ls_fp = (ImageView) ((Activity) context).findViewById(R.id.ls_fp);
#Override
public void run() {
if(read != "1")
ls_fp.setImageResource(R.mipmap.ls_fp_light);
else
ls_fp.setImageResource(R.mipmap.ls_fp);
}
});
}
} catch (IOException e) {
Log.e(Log.TAG.SOCKETSERVER, "SocketServerThread", e);
}
}
}
}
And this code work perfectly fine
But, when in change to another activity and i rerun activity base, the image source not change.
Could you help me ?
I'm trying for sometime now and I cant figure it out why this is not working.
CLIENT:
public class MainActivity extends AppCompatActivity {
private Socket socket;
public static final int PORT = 6000;
public static final String server_IP = "192.168.2.30";
public String mensagem = null;
public String mensagem_final = null;
Button btn_conetar;
TextView txt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_conetar = (Button) findViewById(R.id.btn_conetar);
txt = (TextView) findViewById(R.id.txt);
Thread t = new Thread() {
public void run() {
try {
while(!isInterrupted())
{
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
txt.setText(mensagem_final);
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
public void onClick(View view)
{
new Thread((new ClientThread())).start();
//Intent i = new Intent(MainActivity.this,Main2Activity.class);
// startActivity(i);
}
//Thread que inicia o socket
class ClientThread implements Runnable
{
#Override
public void run() {
try
{
InetAddress serveradress = InetAddress.getByName(server_IP);
Log.e("TCP","A conetar...");
socket = new Socket(serveradress,PORT);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while((mensagem = in.readLine()) != null)
{
mensagem_final += mensagem;
}
if(in.readLine() == null)
{
Log.e("TCP","Nao tem mensagens");
}
Log.e("MSG",mensagem);
socket.close();
}
catch (UnknownHostException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
}
}
Server:
Servidor servidor = new Servidor();
servidor.serverthread();
class Servidor
{
public void serverthread()
{
Thread serverthread = new Thread(server);
serverthread.Start();
}
public void server()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
TcpListener tcplistener = new TcpListener(IPAddress.Any, 6000);
tcplistener.Start();
TcpClient tcpclient = tcplistener.AcceptTcpClient();
byte[] data = new byte[1024];
NetworkStream ns = tcpclient.GetStream();
string welcome = "Ola";
data = Encoding.ASCII.GetBytes(welcome);
ns.Write(data, 0, data.Length);
}
}
Any idea why I cant receive the string "Ola" in my android application? It doesnt give me any error, it just doesnt do anything.
My internet's default adress is 192.168.2.1.
Good links are also welcome.