Recent study utilizing Asynctask to establish socket connections, but encountered some situation
now I can use to press the button to establish a connection, , but I do not know how to make the button text from "unconnected" to "Connected ".Compile no problem but it can not be executed on the simulator, press the button, I can see a text from "unconnected" to "Connected", but the next second forced off the APP.
The following is my code fragment:
public class MainActivity extends Activity {
public static Button Btn_Wifi,Btn_Power,Btn_Flame;
public static Boolean connected=false;
public static DataOutputStream dataOutputStream = null;
public static DataInputStream dataInputStream = null ;
public static Socket socket;
AsyncTask:
static class SocketTask extends AsyncTask<Void, Void, Void > {
#Override
protected Void doInBackground(Void ... parms) {
try {
socket = new Socket("ip", port);//
dataOutputStream = new DataOutputStream(socket.getOutputStream());//and stream
changeConnectionStatus(true);//change the connection status
}catch (UnknownHostException e) {
}catch (IOException e) {
}finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
};
Button.OnClickListener:
Button.OnClickListener BtnWifiOnClickListener = new Button.OnClickListener(){
#Override
public void onClick(View view) {
//SocketTask sockettask = new SocketTask();
new SocketTask().execute();
}
};
changeConnectionStatus:
public static void changeConnectionStatus(Boolean isConnected) {
connected=isConnected;//change variable
if(isConnected){//if connection established
Btn_Wifi.setText("connected");
Btn_Power.setEnabled(true);
}else{
Btn_Wifi.setText("unconnected");
Btn_Power.setText("POWER OFF");
Btn_Power.setEnabled(false);
PowerStatus(false);
}
}
Positive solutions
#Override
protected void onPostExecute(Void result) {
changeConnectionStatus(true);
}
you can't touch UI from doInBackground()
you need to use onPostExecute()
move the call of changeConnectionStatus(true) from doInBackground() as following:
#Override
protected void onPostExecute() {
changeConnectionStatus(true);
}
Related
I have simple Java server:
public class Main {
public static void main(String[] args) throws IOException {
System.out.println("Welcome to Server side");
BufferedReader in;
PrintWriter out;
ServerSocket servers = null;
Socket fromClient = null;
// create server socket
try {
servers = new ServerSocket(4444);
} catch (IOException e) {
System.out.println("Couldn't listen to port 4444");
System.exit(-1);
}
try {
System.out.print("Waiting for a client...");
fromClient = servers.accept();
System.out.println("Client connected");
} catch (IOException e) {
System.out.println("Can't accept");
System.exit(-1);
}
in = new BufferedReader(new InputStreamReader(fromClient.getInputStream()));
out = new PrintWriter(fromClient.getOutputStream(), true);
String input;
System.out.println("Wait for messages");
while ((input = in.readLine()) != null) {
if (input.equalsIgnoreCase("exit")) break;
out.println("S ::: " + input);
System.out.println(input);
}
out.close();
in.close();
fromClient.close();
servers.close();
}
}
and simple Android client:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.editText);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
new MyAsync().execute();
}
---------------------
public class MyAsync extends AsyncTask<Void, Void, Void>{
#Override
protected Void doInBackground(Void... params) {
try {
fromServer = new Socket("192.168.0.103",4444);
in = new BufferedReader(new InputStreamReader(fromServer.getInputStream()));
out = new PrintWriter(fromServer.getOutputStream(), true);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
-------------------
#Override
public void onClick(View v) {
if (v.getId() == R.id.button){
out.println(editText.getText().toString());
}
}
All work good. I send message from Android to server and sever print this message in console. But I want send Object, for example User:
public class User {
private int age;
private String fio;
public User() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getFio() {
return fio;
}
public void setFio(String fio) {
this.fio = fio;
}
In Android i can write:
User user = new User();
out.print(user);
But i am not understanding that how can i read this on server side?
You can't do it with print(). Use an ObjectOutputStream.writeObject() at the sender, and ObjectInputStream.readObject() at the receiver. You will need to adjust your User class to implement Serializable and provide a private static long serialVersionUID value.
NB Don't write code like this. Code that depends on the success of code in a try block should be inside the same try block.
Using this great tutorial by the Java Code Geeks, I am easily able to create a client activity that sends data via TCP to a server's port 4000 using the following code:
public class Client extends Activity {
private Socket socket;
private static final int SERVERPORT = 5000;
private static final String SERVER_IP = "10.0.2.2";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Thread(new ClientThread()).start();
}
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
Then using their other snippet for the server activity I can catch messages using TCP on that port:
public class Server extends Activity {
private ServerSocket serverSocket;
Handler updateConversationHandler;
Thread serverThread = null;
private TextView text;
public static final int SERVERPORT = 6000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text = (TextView) findViewById(R.id.text2);
updateConversationHandler = new Handler();
this.serverThread = new Thread(new ServerThread());
this.serverThread.start();
}
#Override
protected void onStop() {
super.onStop();
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class updateUIThread implements Runnable {
private String msg;
public updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
text.setText(text.getText().toString()+"Client Says: "+ msg + "\n");
}
}
}
My question is how can I make it so these 2 can communicate back and forth?
Android -> Server(4000) -> Android(4001)?
In other words how can I make my app help the device act as both the client (sending out data to another device on port 4000) and the server (listening for data on port 4001) at the same time?
On the Server side change the port to 5000 (same as Client) instead of 6000:
And you need to update the following class because you don't want to create a new socket, you should use the one already created (in the Client part).
NB: the socket given as an argument to CommunicationThread is the socket that you supposedly already created (Client part).
class ServerThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
}
}
}
I'm currently working on an android chat application.
First, I have created the server and then, the android client. But for some reason, the client cannot connect to the server. Nevertheless, I have specified the same port for both client and server.
Could you help me, please ?
Here is the code of my server :
public class ChatServer {
private static int port = 8080;
public static void main (String[] args) throws IOException {
ServerSocket server = new ServerSocket(port); /* start listening on the port */
System.out.println( "Listening on "+ server );
Socket client = null;
while(true) {
try {
client = server.accept();
System.out.println( "Connection from " + client );
/* start a new thread to handle this client */
Thread t = new Thread(new ClientConnect(client));
t.start();
} catch (IOException e) {
System.err.println("Accept failed.");
System.err.println(e);
System.exit(1);
server.close();
}
}
}
}
and here is the client :
public class MainActivity extends Activity implements OnClickListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText nickname = (EditText)findViewById(R.id.nicknameField);
EditText password = (EditText)findViewById(R.id.passwordField);
Button signin = (Button) findViewById(R.id.signin);
Button signup = (Button) findViewById(R.id.signup);
new Downloader(this).execute(8080);
}
and the Asynctask class
public class Downloader extends AsyncTask<Integer, Void, Void> {
private WeakReference<MainActivity> activity;
private int port;
public Downloader(MainActivity act){
super();
activity = new WeakReference<MainActivity>(act);
}
protected Void doInBackground(Integer... params) {
port = params[0];
try {
Socket clientSocket = new Socket("localhost", port);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
When I used the debugger on eclipse, it goes through the line
Socket clientSocket = new Socket("localhost", port);
but after that it goes to the IOException.
Thanks for your help !
You can go to the properties of Android on the emulator equal like you do on a smartphone Android and see the ip you go atributed.
But if you still using the Eclipse i advise you to change to Android Studio but i think you gonna have a problema with SDK you have to unnistall that but beside that no problems.
I've built a TCP server and now I would like to turn it into a jar so I can use it in many different app. So basically later on I'd like to just include it in other projects. if it was just a list of functions I could figure it out but it's not I'm so I'm not sure. I thought about making it all just one function but it wouldn't run, when I called the function the app would just fail.
Also I hope other people can find this server code useful for their own projects
public class MainActivity extends Activity {
private ServerSocket serverSocket;
Handler updateConversationHandler;
Thread serverThread = null;
public String serverIP = "127.0.0.1";
private InetAddress serverAddr;
public static final int SERVERPORT = 4444;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
updateConversationHandler = new Handler();
this.serverThread = new Thread(new ServerThread());
this.serverThread.start();
}
#Override
protected void onStop() {
super.onStop();
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I have an android application that is a client for a simple chat server. I am able to connect to the server and my ObjectStreams. The problem is when I receive a message, the thread that handles my server connection calls upon my display message which updates the list view.
I am getting the error "only the original thread that created a view hierarchy can touch its views."
I am pretty sure its because I'm calling my displayMessage() method from my connect thread, but I am not sure how to organize my threads to have a connection to the server and dynamically update my listview.
Here is my main activity.
public class MainActivity extends Activity {
private Connection serverConnection;
private ArrayList<String> listItems = new ArrayList<String>();
private ArrayAdapter<String> adapter;
/**
* Sets the ArrayAdaptor, and starts the connectThread.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
runOnUiThread(new Runnable() {
public void run() {
ListView listview = (ListView) findViewById(R.id.list);
adapter = new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1,
listItems);
listview.setAdapter(adapter);
}
});
/**
* Starts a new connection Thread
*/
Thread connectThread = new Thread(new Runnable(){
public void run(){
serverConnection = new Connection(MainActivity.this);
serverConnection.run();
}
});
connectThread.start();
}
/**
* Adds a message to the list view.
* #param string - message to be added.
*/
public void displayMessage(String string) {
listItems.add(string);
adapter.notifyDataSetChanged();
}
}
Here is my connection thread class.
public class Connection extends Thread {
private Socket client;
private ObjectOutputStream output;
private ObjectInputStream input;
private MainActivity mainActivity;
private String message;
/**
* Constructor starts the socket and ObjectStreams
*
* #param mainActivity - reference to the MainActivity
*/
public Connection(MainActivity mainActivity) {
this.mainActivity = mainActivity;
try {
client = new Socket("192.168.1.105", 50499);
mainActivity.displayMessage("Connected to: "
+ client.getInetAddress().getHostName());
output = new ObjectOutputStream(client.getOutputStream());
output.flush();
input = new ObjectInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Run method for the Thread.
*/
public void run() {
for (;;) {
try {
message = (String) input.readObject();
mainActivity.displayMessage(message);
} catch (OptionalDataException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
You are updating Ui on the background thread. You should update ui on the ui thread. Move your code that updates ui in the background thread. You are refreshing your listview on the background thread.
mainActivity.displayMessage("Connected to: "
+ client.getInetAddress().getHostName());
mainActivity.displayMessage(message);
public void displayMessage(String string) {
listItems.add(string);
adapter.notifyDataSetChanged();
}
The above should be outside the thread or You can use runonuithread inside the thread to update ui.
runOnUiThread(new Runnable() {
#Override
public void run() {
// update ui
}
});
Another way would be to use asynctask. Do all your network related operation in doInbackground() and update ui in onPostExecute().
Async Task
Edit: Not sure what you are trying to do.
public class MainActivity extends Activity {
private Connection serverConnection;
private ArrayList<String> listItems = new ArrayList<String>();
private ArrayAdapter<String> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listview = (ListView) findViewById(R.id.lv);
adapter = new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1,
listItems);
listview.setAdapter(adapter);
// use a button and on button click start the thread.
Thread connectThread = new Thread(new Runnable(){
public void run(){
serverConnection = new Connection(MainActivity.this);
serverConnection.run();
}
});
connectThread.start();
}
public void displayMessage(String string) {
listItems.add(string);
adapter.notifyDataSetChanged();
}
class Connection extends Thread {
private Socket client;
private ObjectOutputStream output;
private ObjectInputStream input;
private MainActivity mainActivity;
private String message;
public Connection(MainActivity mainActivity) {
this.mainActivity = mainActivity;
try {
client = new Socket("192.168.1.105", 50499);
runOnUiThread(new Runnable() {
#Override
public void run() {
displayMessage("Connected to: "
);
}
});
output = new ObjectOutputStream(client.getOutputStream());
output.flush();
input = new ObjectInputStream(client.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
for (;;) {
try {
message = (String) input.readObject();
runOnUiThread(new Runnable() {
#Override
public void run() {
displayMessage(message);
}
});
} catch (OptionalDataException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}