Android: how to change IP Address from within TCP Client app? - android

I am trying to communicate between a C# TCP server, and an Android TCP client. I am new to android so used the second part of this tutorial to create the android client:
http://www.myandroidsolutions.com/2012/07/20/android-tcp-connection-tutorial/#.V8uZISgrKUk
Everything works fine, and I can send little text messages between my phone and my computer, however this tutorial requires that the client app have the server IP hard coded into the program, and for obvious reasons this is going to cause issues if I actually wanted to make an app that uses this.
Outside of this tutorial I have added a second EditText ("#id/ipTxt") and a second button ("#id/setIp")
As I don't want to make anybody read through the whole tutorial, here are the important parts summarized:
Main Activity:
public class MyActivity extends Activity
{
private ListView mList;
private ArrayList<String> arrayList;
private MyCustomAdapter mAdapter;
private TCPClient mTcpClient;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
arrayList = new ArrayList<String>();
final EditText editText = (EditText) findViewById(R.id.editText);
Button send = (Button)findViewById(R.id.send_button);
//relate the listView from java to the one created in xml
mList = (ListView)findViewById(R.id.list);
mAdapter = new MyCustomAdapter(this, arrayList);
mList.setAdapter(mAdapter);
// connect to the server
new connectTask().execute("");
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = editText.getText().toString();
//add the text in the arrayList
arrayList.add("c: " + message);
//sends the message to the server
if (mTcpClient != null) {
mTcpClient.sendMessage(message);
}
//refresh the list
mAdapter.notifyDataSetChanged();
editText.setText("");
}
});
}
public class connectTask extends AsyncTask<String,String,TCPClient> {
#Override
protected TCPClient doInBackground(String... message) {
//we create a TCPClient object and
mTcpClient = new TCPClient(new TCPClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
publishProgress(message);
}
});
mTcpClient.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//in the arrayList we add the messaged received from server
arrayList.add(values[0]);
// notify the adapter that the data set has changed. This means that new message received
// from server was added to the list
mAdapter.notifyDataSetChanged();
}
}
}
TCPClient class:
public class TCPClient {
private String serverMessage;
public static final String SERVERIP = "192.168.0.102"; //your computer IP address
public static final int SERVERPORT = 4444;
private OnMessageReceived mMessageListener = null;
private boolean mRun = false;
PrintWriter out;
BufferedReader in;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TCPClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends the message entered by client to the server
* #param message text entered by client
*/
public void sendMessage(String message){
if (out != null && !out.checkError()) {
out.println(message);
out.flush();
}
}
public void stopClient(){
mRun = false;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVERIP);
Log.e("TCP Client", "C: Connecting...");
//create a socket to make the connection with the server
Socket socket = new Socket(serverAddr, SERVERPORT);
try {
//send the message to the server
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
Log.e("TCP Client", "C: Sent.");
Log.e("TCP Client", "C: Done.");
//receive the message which the server sends back
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//in this while the client listens for the messages sent by the server
while (mRun) {
serverMessage = in.readLine();
if (serverMessage != null && mMessageListener != null) {
//call the method messageReceived from MyActivity class
mMessageListener.messageReceived(serverMessage);
}
serverMessage = null;
}
Log.e("RESPONSE FROM SERVER", "S: Received Message: '" + serverMessage + "'");
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
//the socket must be closed. It is not possible to reconnect to this socket
// after it is closed, which means a new socket instance has to be created.
socket.close();
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
//Declare the interface. The method messageReceived(String message) will must be implemented in the MyActivity
//class at on asynckTask doInBackground
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
My theory would be to stop the connectTask process every time the "setIp" button is clicked and create a new one, but that seems like a very inefficient way to do it, plus I don't know how I would go about doing that :(
Any Ideas?

Change your SERVERIP and SERVERPORT constants into non-static variables instead, and then initialize them using additional input values to your TCPClient constructor, or as input parameters to AsyncTask.execute() (which will then be passed as input parameters to your doInBackground() method).
Don't call execute() until you have first determined those values, either from your app's stored configuration, or from the user in the UI.
When you do start a new task, save the object to a variable in your main code (which you are not currently doing). To cancel the connection, you can then call the AsyncTask.cancel() method on that variable. Make sure your connectTask.doInBackground() and TCPClient.run() code checks the AsyncTask.isCancelled() method periodically so they can exit as soon as possible when it returns true. This technique is mentioned in the AsyncTask documentation.
After the connectTask object finishes running, you can create a new one with different input values.

Related

How can I retrieve data from an Arduino using Android?

I'm building an app in Android to communicate with Arduino via usb.
In Android, I create a button to send data to the Arduino. The Arduino should then respond to this message and send another message to be treated in the function of the same button. The problem is that when I click on the button the app stops.
My Arduino code:
void setup()
{
Serial.begin(9600);
}
void loop()
{
char c;
int i = 0;
if(Serial.available()){
c=Serial.read();
if (c == '4'){
Serial.write("X:100 Y:10");
}
}
}
Defining a Callback which triggers whenever data is read in Android:
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0) {
String data = null;
try {
data = new String(arg0, "UTF-8");
data.concat("\n");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
};
The button function in Android is:
public void goBefore(View view) {
ssend = "M114"; // send message to update current position
serialPort.write(ssend.getBytes());
String[] current_Pos = data.split(" ");
Do you know what I'm doing wrong?

a TCP client communicating with a server set on ESP8266-01

I'm setting up a TCP/IP communication between an android app and an ESP8266 module connected to Arduino uno. I'm using AT commands to set up the server as follows:
AT+CWMODE=1
AT+CIPMUX=1
AT+CIPSERVER=1,80
I get OK for each.
I want send an int to the app : 0 or 1 , the app read the int and then sends the text typed in the editText to the ESP8266
Now, here is my app code:
public class MainActivity extends AppCompatActivity {
TextView tv;
EditText txt;
EditText txt2;
Button b;
string response;
private static Socket s ;
private static PrintWriter printWriter;
String message="";
private static String ip="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.button);
txt = (EditText) findViewById(R.id.editText);
tv = (TextView) findViewById(R.id.textView) ;
txt2=(EditText)findViewById(R.id.editText2);
}
class myTask extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... params)
{
try
{ s= new Socket(ip,80);
//READING THE INPUT
BufferedReader in = new BufferedReader(new
InputStreamReader(s.getInputStream()));
while(in!=null) {
response = in.readLine();
}
//SENDING THE MESSAGE
printWriter= new PrintWriter(s.getOutputStream());
printWriter.write(message);
printWriter.flush();
post_send();
// closing all connections
// printWriter.close();
// in.close();
// s.close();
}catch(IOException e)
{e.printStackTrace();}
return null;
}
}
public void send_text(View v)
{
message= txt.getText().toString();
ip=txt2.getText().toString();
myTask mt = new myTask();
mt.execute();
Toast.makeText(getApplicationContext(),"MT
LAUNCHED",Toast.LENGTH_LONG).show();
}
public void post_send(){
Toast.makeText(getApplicationContext(),response
,Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(),"Data
sent",Toast.LENGTH_LONG).show();
}
}
I have 1 button to create the socket and receive any data and then send a text.
When I click on the button I get the following message on the serial monitor:
0, connected
so I type:
AT+CIPSEND=0,4
I get :
SEND OK
but none of the toasts show
help me? What am I doing wrong ?
s = new Socket(ip, 80);
If you execute that code in the onClick() of an onClickListener you will get an NetworkOnMainThreadException. Which lets your app crash.
All internet code (also the connecting and reading) should be executed from a thread or AsyncTask.
Your writing is already in an AsyncTask. Which is the way to go.

AsyncTask in an android socket application

i am making an android socket app to communicate with the server for creating accounts, and i noticed i have to do this in AsyncTask sub class, even when i seperate it to another class without UI,but i am terribly confused how can i use AsyncTask on this, is there any one expert here who can help me please?
this is the code:
public class AccountCreator extends Activity {
public AccountCreator(){
super();
}
// for I/O
ObjectInputStream sInput; // to read from the socket
ObjectOutputStream sOutput; // to write on the socket
Socket socket;
public static String LOGTAG="Lifemate";
public String server = "localhost";
public String username = "user";
public String password = "rezapassword" ;
public int port = 1400;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(LOGTAG,"oncreate called");
this.start();
}
AccountCreator(String server, int port, String username,String password) {
this.server = "localhost";
this.port = 1400;
this.username = username;
Log.i(LOGTAG,"first accountcreator called");
}
public boolean start() {
// try to connect to the server
//this method returns a value of true or false when called
try {
socket = new Socket(server, port);
}
// if it failed not much I can so
catch(Exception ec) {
// display("Error connectiong to server:" + ec);
Log.i(LOGTAG,"Error connectiong to server:" + ec);
return false;
}
String msg = "Connection accepted " + socket.getInetAddress() + ":" +
socket.getPort();
// display(msg);
Log.i(LOGTAG, msg);
/* Creating both Data Stream */
try
{
sInput = new ObjectInputStream(socket.getInputStream());
sOutput = new ObjectOutputStream(socket.getOutputStream());
}
catch (IOException eIO) {
// display("Exception creating new Input/output Streams: " + eIO);
Log.i(LOGTAG,"Exception creating new Input/output Streams: " +
eIO);
return false;
}
// creates the Thread to listen from the server
// Send our username to the server this is the only message that we
// will send as a String. All other messages will be ChatMessage objects
try
{
sOutput.writeObject(username);
sOutput.writeObject(password);
}
catch (IOException eIO) {
// display("Exception doing login : " + eIO);
Log.i(LOGTAG,"Exception doing login : " + eIO);
disconnect();
return false;
}
// success we inform the caller that it worked
return true;
}
// private void display(String msg) {
// TextView screenprint = (TextView)findViewById(R.id.systemmessages);
// screenprint.setText(msg);
// }
private void disconnect() {
Log.i(LOGTAG,"reached disconnect");
try {
if(sInput != null) sInput.close();
}
catch(Exception e) {} // not much else I can do
try {
if(sOutput != null) sOutput.close();
}
catch(Exception e) {} // not much else I can do
try{
if(socket != null) socket.close();
}
catch(Exception e) {} // not much else I can do
}
public void Begin() {
Log.i(LOGTAG,"it begun");
int portNumber = 1400;
String serverAddress = server;
String userName = username;
String newpassword = password;
AccountCreator accountcreator = new AccountCreator(serverAddress, portNumber,
userName,password);
if(!accountcreator.start())
return;
}
}
i was trying to put whole code in Async, i dont know if was i right, do i need to do that also or just some parts of it?
In brief, AsyncTask contains a few methods which may be helpful:
onPreExecute:
This method is the first block of code executed when calling asyncTask.execute(); (runs on mainUIThread).
doInBackground:
Here you put all the code which may suspend you main UI (causes hang for your application) like internet requests, or any processing which may take a lot of memory and processing. (runs on background thread), contains one parameter taken from the asyncTask.execute(ParameterType parameter);
onPostExecute
Runs after doInBackground(). Its parameter is the return value of the doInBackground function, and mainly you put the changes in UI need to be done after the connection is finished (runs on mainUIThread)
You have to declare another class within the class you have already created.
class SomeName extends Async<Void, String, Void>{
protected void OnPreExecute(){
// starts the task runs on main UI thread
// Can be used to start a progress dialog to show the user progress
}
#Override
protected Void doInBackground(Void... params){
// does what you want it to do in the background
// Connected to the server to check a log-in
return result;
}
protected void OnPostExecute(Void result){
// finishes the task and can provide information back on the main UI thread
// this would be were you would dismiss the progress dialog
}
}

Networking and Threads in Android Apps

I know that i must use threads to use internet in Android application, but i don't know how to write it.
I have one class call "JabberSmackAPI" - on this class i have Login,send and receive functions via XMPP.
And i have one button on my app, when i press the button it should login to googleTalk account.
This works well on Java project ( i can login and send messages) but not on Android app project.
i receive this error: "android.os.NetworkOnMainThreadException".
My class is:
public class JabberSmackAPI
{
XMPPConnection connection;
public void login(String userName, String password) throws XMPPException
{
ConnectionConfiguration config = new ConnectionConfiguration("talk.google.com",5222,"gmail.com");
connection = new XMPPConnection(config);
connection.connect();
SASLAuthentication.supportSASLMechanism("PLAIN", 0);
connection.login("email", "password");
}
public void sendMessage(String message, String to) throws XMPPException
{
Message msg = new Message(to, Message.Type.chat);
msg.setBody(message);
connection.sendPacket(msg);
listeningForMessages();
}
public void disconnect()
{
connection.disconnect();
}
public void listeningForMessages() {
PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class));
PacketCollector collector = connection.createPacketCollector(filter);
while (true) {
Packet packet = collector.nextResult();
if (packet instanceof Message) {
Message message = (Message) packet;
if (message != null && message.getBody() != null)
System.out.println("Received message from "
+ packet.getFrom() + " : "
+ (message != null ? message.getBody() : "NULL"));
}
}
}
My app code is:
public class MainActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn1=(Button)findViewById(R.id.button1);
btn1.setOnClickListener(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public void onClick(View v) {
if(v.getId()==R.id.button1)
{
try{
Toast.makeText(this, "T", Toast.LENGTH_LONG).show();
JabberSmackAPI c = new JabberSmackAPI();
c.login("username", "password");
}
catch(Exception e)
{
Log.e("Error","Error in code:"+e.toString());
e.printStackTrace();
}
}
}
}
The main application thread should only be used for interface-related work. You need to use multithreading, since networking is not allowed at all on the main thread of Android applications. Since your app requires a persistent data connection, AsyncTasks won't work either, since they are single-serving - fire, get result and close connection.
android.os.NetworkOnMainThreadException
Means exactly what it says - don't do network operations on the main/ui thread

android asynctask NetworkOnMainThreadException

I'm trying to write a server/client app in android using sockets and i handle the client socket in AsyncTask (server is not android, just ordinary java).I get the exception when I'm trying to read from the server.I found out that when I delete android:targetSdkVersion="16" from android manifest the exception goes away and I can read from the server.
I don't understand why is that? could anyone help me clarify this? I also have problems understanding how the asynctask method doInBackground and my own methods relate. Does conhandler.execute() run doInBackground() and then just waits until I call the other methods? thanks for help.
public class ConnectionHandler extends AsyncTask<Void, Void, Void>{
public static String serverip = "10.0.2.2";
public static int serverport = 5000;
Socket s;
PrintWriter out;
BufferedReader in;
protected Void doInBackground(Void... params) {
try {
s = new Socket(serverip, serverport);
Log.i("AsyncTank", "doInBackgoung: Created Socket");
}...
if (s.isConnected()) {
try {
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = new PrintWriter(s.getOutputStream(), true);
Log.i("AsyncTank", "doInBackgoung: Socket created, Streams assigned");
} ....
}
public void writeToStream(String message) {
try {
if (s.isConnected()){
out.println(message);
} else {
Log.i("AsynkTask", "writeToStream : Cannot write to stream, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "writeToStream : Writing failed");
}
}
public String readFromStream() {
try {
if (s.isConnected()) {
Log.i("AsynkTask", "readFromStream : Reading message");
String ret=in.readLine();
Log.i("AsynkTask", "readFromStream : read "+ret);
return ret;
} else {
Log.i("AsynkTask", "readFromStream : Cannot Read, Socket is closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "readFromStream : Reading failed"+e.getClass());
}
return null;
}
}
this is my main activity
public class MainActivity extends Activity {
private EditText view_email;
private EditText view_password;
TextView result;
ConnectionHandler conhandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
conhandler = new ConnectionHandler();
conhandler.execute();
}
public void register(View view) {
view_email= (EditText) findViewById(R.id.email);
view_password = (EditText) findViewById(R.id.password);
String email=view_email.getText().toString();
String password=view_password.getText().toString();
conhandler.writeToStream("register");
conhandler.writeToStream(email);
conhandler.writeToStream(password);
String res=conhandler.readFromStream(); //here's the exception
result=(TextView) findViewById(R.id.result);
result.setText(res);
}
}
There are two Solution of this Problem.
1) Don't write network call in Main UIThread, Use Async Task for that.
2) Write below code into your MainActivity file after setContentView(R.layout.activity_main);
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
And below import statement into your java file.
import android.os.StrictMode;
android.os.NetworkOnMainThreadException
this eror comes With HoneyComb(3.0 or Later).
you can not perform a networking operation on its main thread as documentation says. to getting ride of this you must use handler or asynctask. AFAIK There is no another way to do it.
you can See this for More Details WHY ICS Crashes your App
Try Using Below Code Snippet
new Thread(){
public void run(){
//do your Code Here
}
}.start();

Categories

Resources