I'm kind of new in this kind of development. To be short I'm working on a android app which sends a string to the cloud (I have a virtual server machine on Amazon), everything works well sending the string from my phone to the server machine, I print the string I'm sending and it works!. But when getting the response back from the server to my android app (I'm running it on my android phone) I don't get anything (The response should be a string + another string concatenated), that's it, easy right? But unfortunately I can't receive it back. I tested the server side and It's working properly (The amazon EC2). I'm not really sure if I can do what Im doing which is:
CREATING ransmission code to send the String by using a SOCKET TO SEND DATA TO THE CLOUD ON THE doInBackground() method from the AsyncTask class.
In the same method doInBackground I do the code to receive the response back by using a ServerSocket to receive the response back from the cloud. Is it possible or do I need another thread or something like that?
Here is my code:
`import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.*;
import android.os.AsyncTask;
import android.view.View;
public class ReadWebpageAsyncTask extends Activity {
private TextView textView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.TextView01);
}
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls)
{
String response = "";
//Transmission
try
{
Socket socket = new Socket("MyAmazonServerIp", 5678);
DataOutputStream salida = new DataOutputStream (socket.getOutputStream());
salida.writeUTF("Llego Perfectamente");
socket.close();
salida.close();
}
catch (Exception e)
{
e.printStackTrace();
}
//Final ends
// Reception
boolean ak=true;
try
{
ServerSocket ServerSock = new ServerSocket(7896);
while(ak)
{
Socket cl=ServerSock.accept();
InetAddress ipC = cl.getInetAddress();
DataInputStream en= new DataInputStream(cl.getInputStream());
response= en.readUTF();
//response= response.toString();
ak=false;
}
}
catch(Exception exp)
{
exp.printStackTrace();
}
// Reception ends
return response;
} //doInBackground ends
#Override
protected void onPostExecute(String result)
{
textView.setText(result);
}
}
public void readWebpage(View view) {
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] { "????" });
}
}`
I will really appreciate any help since I've been working on this for days and I have not been able to solve it.
Thanks,
The way you are doing it can not work over a 3G or likely even a WiFi connection. It can't work over 3G because the address your Amazon server sees is the address of the proxy/firewall on your cell provider's network. No external application can open a socket directly to your phone. Instead you need to send the response back over the same socket the phone created to send the initial message.
Over WiFi, it will not work because of the NAT translation likely going on with your WiFi firewall.
This is done for many reasons, not the least of which is data usage and security. Specifically, think about if your phone was publicly addressable to the entire Internet? It would constantly be getting hit with attempts to hack it.
So basically, just keep the original socket open and listen for a response on that socket and on your cloud server just send the response back over teh same socket you receive the request on.
Related
I'm new to both java and android and I am currently working on a simple data logging app for information sent via bluetooth. I have recently switched to using an HM-10 (CC41) BLE module from classic bluetooth. Since I don't know anything about using Gatt characteristics to create a connection and receive data, I would like to continue using socket communication. My phone S7 edge is not able to pair to the BLE device though so it's not an option for me to create a bond programatically before starting the RfcommSocket. Is there any way to continue using socket communication without pairing? Finally, I already have the MAC address of my BLE module so I would rather not be scanning. Here is my relevant code:
public class MainActivity extends AppCompatActivity implements Runnable {
private BluetoothAdapter adapter;
private InputStream inputStream;
private OutputStream outputStream;
private Thread thread;
private TextView Status;
private TextView Connection;
private BluetoothSocket socket = null;
public boolean threadStatusInitial; //changed the status global variables to public static
public boolean threadStatus;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
threadStatusInitial=true;
threadStatus=true;
Status=(TextView) findViewById(R.id.StatusID);
Connection=(TextView) findViewById(R.id.ConnectionStatus);
adapter= BluetoothAdapter.getDefaultAdapter();
if(adapter==null){
Toast.makeText(this,"bluetooth is unavailable",Toast.LENGTH_SHORT).show();
finish();
return;
}
thread=new Thread(this);
}
public void connect(View view){
BluetoothDevice device=adapter.getRemoteDevice("3C:A3:08:94:C3:11");
try {
socket=device.createRfcommSocketToServiceRecord(device.getUuids()[0].getUuid());
socket.connect();
Connection.setText("Connected");
inputStream=socket.getInputStream();
outputStream=socket.getOutputStream();
if (threadStatusInitial){
thread.start();
threadStatusInitial=false; //this ensures that the thread.start() method will only be called during the initial connection
}
threadStatus=true;
} catch (IOException e) {
Toast.makeText(this,"Can't Connect",Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
The thread related global variables have to do with maintaining the logging thread during disconnects and reconnects to the BLE module.
Thanks!
First of all Bluetooth low energy is not meant to use Sockets for connection and data transfer. The whole point of BLE is to keep power consumption as low as possible that cannot be achieved by sockets as they maintain the continue data transfer stream regardless we are sending any data or not.
You can get help from this link for android- HM10 communication.
http://android-er.blogspot.in/2015/12/connect-hm-10-ble-module-to-android.html
Bluetooth classic and Bluetooth Low Energy, although related are different standards. For a classic connection you would use something like the code you have illustrated. But a BLE client is much different. Requires completely different client code. I think your device HM-10 (CC41) BLE module likely only supports BLE. I believe your only choice is to migrate to BLE.
I'm following this tutorial to try to make an andorid app with a backend on google app-engine.
I'm at the point where I want to test the connection between my app and GAE Api locally so I try to execute the following code on my Nexus 5 phone (not emulated).
MainActivity.java
public class MainActivity extends FragmentActivity {
private final String DEBUG_TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* AsyncTask for calling Mobile Assistant API for checking into a place (e.g., a store)
*/
private class CheckInTask extends AsyncTask<Void, Void, Void> {
/**
* Calls appropriate CloudEndpoint to indicate that user checked into a place.
*
* #param params the place where the user is checking in.
*/
#Override
protected Void doInBackground(Void... params) {
CheckIn checkin = new CheckIn();
// Set the ID of the store where the user is.
// This would be replaced by the actual ID in the final version of the code.
checkin.setPlaceId("StoreNo123");
Checkinendpoint.Builder builder = new Checkinendpoint.Builder(
AndroidHttp.newCompatibleTransport(), new JacksonFactory(),
null);
builder = CloudEndpointUtils.updateBuilder(builder);
Checkinendpoint endpoint = builder.build();
try {
endpoint.insertCheckIn(checkin).execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
}
And I get this
Where I shouldget this
(source: google.com)
And the log shows :
java.net.SocketTimeoutException: failed to connect to /10.0.2.2 (port 8888) after 20000ms
No CheckIn is available on the "entity kind" list
I've lauched the appengine locally i get : INFOS: Dev App Server is now running
I've CloudEndPointUtils.java setting to : LOCAL_ANDROID_RUN = true; LOCAL_APP_ENGINE_SERVER_URL = "http://localhost:8888/"; and LOCAL_APP_ENGINE_SERVER_URL_FOR_ANDROID = "http://10.0.2.2:8888";
I feel like it's because I'm using a physical device for debugging...
What do you think and how to make it work ?
(I can't figure out how run an emulator of android on my computer so if there is another solution that would be great)
Edit: I've tried to deploy the app but I'm having the same issue with the same log error.
This is beacause 10.0.2.2 is the address of localhost when using the emulator. If you want to try it on your device and all your computer and device are connected to the local network, try changing the server address to http://local-network-ip:port/_ah/api. When launching the appengine application set the host address to 0.0.0.0 to make it accessible to other machines on the network.
I'm trying to connect to .NET 4.0 webservice I created for receiving SOAP-calls from Android-devices, now hosted on local IIS for testing purposes.
I found out that ksoap2 would be an excellent class library for doing what i want to do. Downloaded the .jar package from https://code.google.com/p/ksoap2-android/ and started pounding the keyboard in ecstacy... with my fingers.
The amount of information being sent is from few kilobytes to few megabytes.
What is working
HttpTransportSE.call(String, SoapSerializationEnvelope)-method works perfectly while still in Eclipse's Android emulator, sending the call to webservice hosted in local IIS. Even tested that the webservice receives empty calls from trying to open the service address from a web browser in the same local area network.
What doesn't work
When I copy the .apk-file to an Android device, install it, start it and trying to make the call, the whole program freezes without making the call.
As you can see from a code block presented some lines after that possible errors are being taken into account: In emulated environment a successful call returns a SoapPrimitive-object or flows into the correct catch block generating an error message for the user according to the current situation.
Then on live Android device, program loses it's responsivity forever and has to be terminated from application menu.
What have i tried
I removed the call from the asynchronous method, and tried calling it straight from an anonymous inner function assigned for a button click-event.
Tried not trying to get a response, just making the call.
Tried getting a logcat-program for the device to see what's happening behind the UI, found two, they needed root access, which i don't have in the device. This is why i don't have any logcats to show you, and showing the emulator logcat would probably(?) be useless because it works fine there.
Not trying to connect to localhost.
Tried installing the program on older Lenovo-tablet running Android 4.2.2 and on brand new Samsung Galaxy Tab, both would have the same problem while otherwise working well.
The code
Here's the asynchronous method for making the call in device/emulator, where variables str_URL and soapRequest are a correct service address (checked) and a well formed SoapObject respectively:
#Override
protected WebServiceResult doInBackground(Void... v) {
WebServiceResult _ret;
SoapSerializationEnvelope soapEnvelope= new SoapSerializationEnvelope(SoapEnvelope.VER11);
soapEnvelope.dotNet=true;
soapEnvelope.setAddAdornments(false);
soapEnvelope.setOutputSoapObject(soapRequest);
HttpTransportSE conn = new HttpTransportSE(str_URL);
conn.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
conn.debug = true;
try {
conn.call(str_ACTION, soapEnvelope);
SoapObject o = (SoapObject)soapEnvelope.getResponse();
_ret = new WebServiceResult(o, WebServiceResultEnum.ok);
} catch (NetworkOnMainThreadException e) {
_ret = new WebServiceResult(null, WebServiceResultEnum.keskeytys);
} catch (HttpResponseException e) {
_ret = new WebServiceResult(null, WebServiceResultEnum.httpVirhe);
} catch (XmlPullParserException e) {
_ret = new WebServiceResult(null, WebServiceResultEnum.vaara_muoto);
} catch (SocketTimeoutException e) {
_ret = new WebServiceResult(null, WebServiceResultEnum.aikakatkaisu);
} catch (Exception e) {
_ret = new WebServiceResult(null, WebServiceResultEnum.keskeytys);
}
return _ret;
}
Thank you in advance!
Is it possible you are doing something like this:
YourAsyncTask task = new YourAsyncTask();
WebServiceResult result = task.doInBackground();
Because that would be wrong, completely wrong. If you call doInBackground() directly it will run in the same Thread and not in a new one. You need to start the AsyncTask with execute() like this:
YourAsyncTask task = new YourAsyncTask();
task.execute();
You need to implement the AsyncTask like this:
public class ExampleTask extends AsyncTask<Void, Void, WebServiceResult> {
public interface FinishedListener {
public void onFinished(WebServiceResult result);
}
private final FinishedListener finishedListener;
public ExampleTask(FinishedListener listener) {
this.finishedListener = listener;
}
#Override
protected WebServiceResult doInBackground(Void... params) {
WebServiceResult result = ...;
return result;
}
#Override
protected void onPostExecute(WebServiceResult result) {
super.onPostExecute(result);
if(this.finishedListener != null) {
this.finishedListener.onFinished(result);
}
}
}
And if you implemented it that way you can use it like this:
ExampleTask task = new ExampleTask(new ExampleTask.FinishedListener() {
#Override
public void onFinished(WebServiceResult result) {
// This will be called if the task has finished
}
});
task.execute();
It seems that I had declared the minimum SDK as 14 and target SDK as 17 in AndroidManifest.xml. I didn't use any fancy things in newer sdk's so i lowered the target SDK to the same level as minimum SDK, 14. I also had an Avast! Antivirus service running on the tablet which i removed.
This solved my problem. It could be that probably the Avast! antivirus-program wanted to block all communications from applications not downloaded from Play-store. I don't know if changing the target SDK had much effect really.
Well, I had the same question as you. When it goes to the method transport.call, it pauses, and for a while, it throws a timeout problem. At first, I thought maybe the network was poor, but the server logcat shows it is not the problem. The request was fine and the response was good. My business process is like below:
First, I get a list from the server through ksoap inner a child thread, then cycle the list, send a ksoap request based on every item of the list. It means it will send another list.size() request. When debugging in a real device the above problems occured. I solved it by starting a new child thread after getting the list and making all the list.size requests in the new child thread. So, ksoap use in android may cause thread block which leads to ioexception. So when you put it in a new thread, it escapes from the parent catch exception and works fine.
I'm using socket communication in my android app. Right now I'm opening socket for every message I send to server and then close it.
In my every Activity I have a private class which extends from AsyncTask.
Something like following code:
public class MainWindowActivity extends Activity{
...
private class SendRequest extends AsyncTask<ArrayList<String>, Void, String> {
#Override
protected String doInBackground(ArrayList<String>... params) {
// opening socket
// sending mesasge
// closing socket
return result;
}
}
}
My question is that can I make a class for communication which open a socket when user does login and closes it when user does logout and I can use that socket instance in my all activities?
I have this AsyncTask which I use to send a chat message over the internet. The problem is that when I execute the task nothing happens - at least not on the UI. I suspect that onProgressUpdate() does not execute at all. The idea is that when the task is started, a message will be sent over the internet and an EditText on the UI will be updated with the new text. Here is the whole class:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import android.os.AsyncTask;
import android.widget.EditText;
public class Messager extends AsyncTask<SocketAndEditText, Void, Void> {
private MulticastSocket socket;
private EditText host;
private EditText port;
private EditText sendMessage;
private EditText messageBoard;
private InetAddress serverAddress;
private int pt;
private String newConverstion;
private String message;
#Override
protected Void doInBackground(SocketAndEditText... soEd) {
// get the text that they contain and add the new messages to the old ones
//host = soEd[0].getHost();
//port = soEd[0].getPort();
messageBoard = soEd[0].getMessageBoard();
sendMessage = soEd[0].getSendMessage();
message = sendMessage.getText().toString();
String conversation = messageBoard.getText().toString();
newConverstion = conversation.concat("\n[You] ").concat(message);
return null;
}
protected void onProgressUpdate(Integer... progress) {
// make the messages text view editable
messageBoard.setFocusable(true);
messageBoard.setText(newConverstion); // add the new message to the text view
messageBoard.setFocusable(false); // make the messages text view not editable
// erase the text on the second text view that has just been sent
sendMessage.setText("");
sendMessage(message);
}
public void sendMessage(String message) {
// convert the host name to InetAddress
try {
serverAddress = InetAddress.getByName("localhost");
} catch (Exception e) {}
pt = 4456;
// create socket and start communicating
try {
socket = new MulticastSocket(pt);
socket.joinGroup(serverAddress);
} catch (IOException e) {}
// Send message to server
// convert message to bytes array
byte[] data = (message).getBytes();
// create and send a datagram
DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, pt);
try {
socket.send(packet);
} catch (IOException e) {}
}
}
What could be wrong?
The onProgressUpdate() won't be called if you don't call publishProgress() yourself. See the 4 steps of AsyncTask.
As Boris pointed out. You should call sendMessage() in doInBackground() and update UI in onPostExecute().
onProgressUpdate should be invoked explicitly from within doInBackground as seen here. It is not the correct method to use in your case. I would rather expect that the setting of the text field should be done in onPostExecute. Reason being that the value of newConverstion is determined just after the remote call and it might take a while to complete. If you do it before the asynctask has finished execution you risk NPE.
Edit Adding some code:
public class Messager extends AsyncTask<SocketAndEditText, Void, Void> {
//skipping some field declaration
#Override
protected Void doInBackground(SocketAndEditText... soEd) {
// get the text that they contain and add the new messages to the old ones
//host = soEd[0].getHost();
//port = soEd[0].getPort();
messageBoard = soEd[0].getMessageBoard();
sendMessage = soEd[0].getSendMessage();
message = sendMessage.getText().toString();
sendMessage(message); //NOTE: added the remote call in the background method. This is the only thing that really SHOULD be done in background.
String conversation = messageBoard.getText().toString();
newConverstion = conversation.concat("\n[You] ").concat(message);
return null;
}
protected void onPostExecute(Void result) {
// make the messages text view editable
messageBoard.setFocusable(true);
messageBoard.setText(newConverstion); // add the new message to the text view
messageBoard.setFocusable(false); // make the messages text view not editable
// erase the text on the second text view that has just been sent
sendMessage.setText("");
}
Basically the most important thing is to place the most time consuming calls in the background of the task. In your case this is sendMessage. From then on you can do whatever fixes you wish in the postExecute and the preExecute. I am not quite sure what your intention for the onProgressUpdate was. Holever I just translated it to using onPostExecute. If you need to temporarily disable the field you can disable it in onPreExecute and enable it onPostExecute.