My android application is not receiving any data from my server, for some reason. Strangely enough, a different socket client I wrote (which runs on my computer rather than an AVD) receives and prints all server-sent messages without fault. It uses similar code to what is held within the doInBackground method.
public class Client extends AsyncTask<Void, Void, Void> {
int port;
Socket s;
#Override
protected Void doInBackground(Void... voids) {
try {
port = 1818;
s = new Socket("xx.xx.xx.xx", port);
if (!s.isConnected()) {
s.close();
}
BufferedReader re = new BufferedReader(new InputStreamReader(s.getInputStream()));
String temp = null;
while ((temp = re.readLine()) != null)
{
MainActivity.changeT(temp); // This will replace the TextView's text with temp.
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
I am thinking a possible solution would be to place the while loop into a separate thread, but I am not sure. Any suggestions are welcome! :-)
While the application was accessing the server appropriately, MainActivity.changeT(temp); is attempting to access the UI thread from a background thread, which is not appropriate.
I solved this by passing an instance of the MainActivity to this Client class, and I used the runnable method runOnUiThread(...).
public class Client extends AsyncTask<Void, Void, Void> {
int port;
Socket s;
MainActivity instance;
Client(MainActivity instance)
{
this.instance = instance;
}
#Override
protected Void doInBackground(Void... voids) {
try {
port = 1818;
s = new Socket("xx.xx.xx.xx", port);
if (!s.isConnected()) {
s.close();
return null;
}
BufferedReader re = new BufferedReader(new InputStreamReader(s.getInputStream()));
String temp = null;
TextView t = instance.getT(); // Accesses a getter method that returns the TextView.
while ((temp = re.readLine()) != null)
{
setText(t, temp); // Accesses the UI Thread and changes the TextView.
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
private void setText(final TextView text,final String value){
instance.runOnUiThread(new Runnable() {
#Override
public void run() {
text.setText(value); // This is equivalent to writing the code in the UI thread itself.
}
});
}
Related
I'm studying electronic engineering but for my internship I've been asked to make a program that must communicate via a socket to a certain ip and port. The program has a main class which is the GUI and I made another class for the connection which runs parallel using a Thread. The problem is that when I click the "Connect" button that I have on my GUI, it only receives or sends once the data, despite having a while loop. To further receive and send data I must spam-click my connect and disconnect button.
public class ConnectionSocket implements Runnable {
private final int port;
private final String ipAddr;
private final Observer observador;
private DataInputStream in;
private DataOutputStream out;
private Socket sc = null;
private boolean inputAvailable = false;
public boolean lastInput = false;
private String nextOutputMessage;
private boolean disconnect=false;
private Observable observable;
public ConnectionSocket(String ip, int p , Observer panel) {
this.ipAddr = ip;
this.port = p;
this.observador = panel;
}
#Override
public void run() {
this.observable = new Observable();
observable.addPropertyChangeListener(observador);
this.observable.notifyData("Message Connected");
System.out.print("\n**********************\nConectado\n**********************\n");
while (!disconnect) {
try {
try {
sc = new Socket(this.ipAddr , this.port);
}
catch (IOException e) {
System.out.println("Socket TimeOut");
}
if(sc != null) {
out = new DataOutputStream(sc.getOutputStream());
in = new DataInputStream(sc.getInputStream());
}
while(!disconnect){
if (sc != null) {
try {
if(in.available() != 0) {
receiveData();
}
else {
inputAvailable = false;
}
}
catch(IOException ex) {
System.out.println("***Read or write error***");
System.out.println(ex.toString());
}
}
}
if ( sc != null ) {
try { sc.close(); }
catch ( IOException e ) {}
}
} catch (IOException ex) {
Logger.getLogger(ConnectionSocket.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Close the socket
cutConnection();
System.out.print("\n**********************\nDesconectado\n**********************\n");
}
public void sendNewData(String msg) throws IOException { //this method receives data from the GUI//
nextOutputMessage = msg;
sendData();
}
private synchronized void sendData() throws IOException {
System.out.println("Panel: " + nextOutputMessage);
out.writeByte((byte) Integer.parseInt(nextOutputMessage));
}
private synchronized void receiveData() throws IOException {
if(!inputAvailable)System.out.print("CUBE: ");
inputAvailable = true;
while(in.available() != 0) {
byte dat = (byte) in.read();
this.observable.notifyData(Character.toString((char) dat));
System.out.print((char) dat);
}
}
public void cutConnection() {
try {
disconnect = true;
if(this.in != null) {
this.in.close();
}
if(this.out != null) {
this.out.close();
}
if(this.sc != null) {
this.sc.close();
}
} catch (IOException ex) {
this.sc = null;
}
}
}
I use two additional classes which use PropertyChangeListener to send the data received to the GUI, otherwise it just blocks it.
I receive and send data as ASCII code.
This is the method in the GUI class which starts the thread (the connection)
private void connect(String ip, int port) {
jButton_connect.setText("Desconectar");
labelMessage("Conectando...");
observerPanel = new Observer(this);
connection = new ConnectionSocket(ip , port, observerPanel);
Thread t = new Thread(connection);
t.start();
}
So basically I would appreciate any hint about what I'm doing wrong, because I can't really find any solution suitable for my needs. BTW any solution that includes getting rid of the double while loop would be great, as it consumes a lot of cpu in that point. Feel free to criticise any stupid thing I made because I had to learn java from zero to do this so it's probably not really good.
Thanks in advance
Edit 1: Does the sc = new Socket(this.ipAddr , this.port); sentence need to be called in the loop or once it's called it permanently bounds to that ip and port? I only need to connect to a specific ip and port. Thanks
I'm working on Client-Server application and I'v hit the wall with one issue. I got ServerWorker that is responsible for one connected client, it creates 2 threads, 1 to listen for incoming data from this client and 1 to send data to him.
class ServerWorker {
private DataProcessor dataProcessor;
private ObjectInputStream inputStream;
private ObjectOutputStream outputStream;
private Thread receiverThread;
private Thread senderThread;
private Optional<DataPacket> dataToSend;
private ServerWorker(Socket socket) {
try {
dataToSend = Optional.empty();
dataProcessor = new DataProcessor();
receiverThread = new Thread(this::readAndProcessData);
senderThread = new Thread(this::sendData);
inputStream = new ObjectInputStream(socket.getInputStream());
outputStream = new ObjectOutputStream(socket.getOutputStream());
} catch (IOException e) {
//TODO
}
}
static ServerWorker create(Socket socket) {
return new ServerWorker(socket);
}
void start() {
receiverThread.start();
senderThread.start();
}
void stop() {
receiverThread.interrupt();
senderThread.interrupt();
}
private void readAndProcessData() {
DataPacket dataPacket;
try {
while((dataPacket = (DataPacket)inputStream.readObject()) != null) {
System.out.println("incoming message: " + dataPacket.getContent());
dataToSend = Optional.of(dataProcessor.process(dataPacket));
}
} catch (ClassNotFoundException | IOException e) {
//TODO
}
}
private void sendData() {
while(true) { //TODO
dataToSend.ifPresent(data -> {
try {
outputStream.writeObject(data);
outputStream.flush();
dataToSend = Optional.empty();
} catch (IOException e) {
//TODO
}
});
}
}
}
And DataProcessor is just a small class for now
public class DataProcessor {
public DataPacket process(DataPacket packet){
packet.setContent(packet.getContent().toUpperCase());
return packet;
}
}
and ofcourse, DataPacket which is the same for both client and server
public class DataPacket implements Serializable {
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
DataProcessor and DataPackets are just kind of POCs now, this will grow into much larger and more complicated classes, long story short, ServerWorker will recieve data and pass it to process, then after some logic is done, returning data will be stored inside dataToSend variable and removed after sending. Problem is, code I'v posted above works only sometimes. 90% of the time when I run my server app and client one (code below) nothing happens, uppercased "hello world" isnt going back to client. What's funny, when I run my server in debug mode (even without any breakpoints!), it works... Any ideas what the heck went wrong?
public static void main(String... args) throws Exception {
Socket socket = new Socket("localhost", 9999);
DataPacket dataPacket = new DataPacket();
dataPacket.setContent("hello world");
ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(dataPacket);
os.flush();
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
while((dataPacket = (DataPacket)inputStream.readObject()) != null) {
System.out.println(dataPacket.getContent());
}
}
edit#
adding one more class, ConnectionDispatcher that is responsible for creating ServerWorker objects
class ConnectionDispatcher implements Runnable {
private ServerSocket serverSocket;
private List<ServerWorker> serverWorkers;
private volatile boolean isReceiving;
private ConnectionDispatcher(int port) throws IOException {
serverSocket = new ServerSocket(port);
serverWorkers = new ArrayList<>();
isReceiving = false;
}
static ConnectionDispatcher create(int port) throws IOException {
return new ConnectionDispatcher(port);
}
#Override
public void run() {
isReceiving = true;
while(isReceiving) {
acceptIncomingConnections();
}
}
private void acceptIncomingConnections() {
try {
ServerWorker worker = ServerWorker.create(serverSocket.accept());
serverWorkers.add(worker);
worker.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
It seems that you're modifying dataToSend from one thread while simultaneously reading its value in another. This isn't thread-safe, and the thread that's reading its value may never see its updated value set by the other thread. For this reason, I'd declare dataToSend as volatile.
private volatile Optional<DataPacket> dataToSend;
I have not yet had the chance to test this out myself, but I can in about an hour (assuming this change doesn't fix your problem).
You could uses a Array Blocking Queue, to simulate a producer and consumer pattern.
Let the receiver thread, put new DataPacket into the queue, and let the sender take from the queue and process it and send it.
This will eliminate threading issues and acts as a buffer.
With your current code, you might loose packets,when they arrive at higher rate.
And i agree with user930, private Optional<DataPacket> dataToSend; should be volatile.
Also you can make your code much scalable with JavaNIO, you could look into Apache Mina project.
I have an Executor that run a while true loop that just pings a server with data. Now I need to updated the UI with this data, so I am using a handler.
In my main activity I have:
private void createGeneralHandler() {
generalHandler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg){
switch (msg.what){
case SERVER_RESPONSE:
serverTextView.append("\n"+msg.obj);
break;
default:
super.handleMessage(msg);
}
}
};
}
This creates a field in the main activity called generalHandler.
Now the NetworkTask runnable needs to know about this handler in order to send the messages to right ?
So I have this in my main activity:
networkExecutor = Executors.newSingleThreadExecutor();
networkTask = new NetworkTask(serverIPAddress, serverPort);
networkTask.setRequest("I WANT DATA");
networkTask.setHandler(generalHandler); //IS THIS WRONG ???
networkExecutor.execute(networkTask);
networkTask is just a Runnable in a separate file defined as such:
public class NetworkTask implements Runnable {
private int port;
private String ipAddress;
private int pollInterval;
private Socket socket = null;
private PrintWriter out = null;
private BufferedReader br = null;
private String request = null;
private String response = null;
private static final int SERVER_RESPONSE = 1;
private Handler handler = null;
public NetworkTask(String ipAddress, int port){
this.port = port;
this.ipAddress = ipAddress;
this.pollInterval = 50;
}
#Override
public void run() {
try {
socket = new Socket(ipAddress, port);
out = new PrintWriter(socket.getOutputStream(), true);
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
try {
while (!Thread.currentThread().isInterrupted()) {
Thread.sleep(pollInterval);
out.println(request);
try {
response = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if(!response.equals("doNothing")){
Message message = new Message();
message.what = SERVER_RESPONSE;
message.obj = response;
handler.sendMessage(message);
}else if(response.equals("Nothing Connected to Server!")){
Message message = new Message();
message.what = SERVER_RESPONSE;
message.obj = response;
handler.sendMessage(message);
}
}
} catch (InterruptedException threadE) {
try {
br.close();
out.close();
socket.close();
} catch (IOException socketE) {
socketE.printStackTrace();
}
Log.i("NETWORK_TASK_THREAD", "NETWORK TASK closed gracefully!");
}
}
public void setRequest(String request) {
this.request = request;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
Answer to your question will be a bit arbitrary. Since the implementation is just a design choice, there won't be right or wrong but would be good or not so good.
Following are points which I would like to highlight:
If you are just concerned networkTask.setHandler(generalHandler); then its fine as long as you are not invoking any network call or heavy processing on Main thread.
You also need to ensure that your Runnable is interrupted appropriately in apps onStop() or onDestroy() to avoid potential memory leak.
You are continuously trying to ping the server which is not a great idea since it will consume resources and drain battery. You can perform these tasks periodically or use FCM push.
For closing the InputStreams or OutputStreams its considered good practice to clean up in finally {..} block which guarantees clean up in case some other Exceptions occurs during execution.
One alternative would be to implement ViewModel and MutableLiveData and perform the operation. This will no bloat your Activity with un-necessary processing.
Im attempting to read a text file from my onedrive, I need to check the version of the database and update if necessary.
This is an example of my code:
private void checkVersion() {
try {
int dbversion = prefs.getInt("dbversion", 1);
int dblastversion;
URL url = new URL("");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
str = in.readLine();
in.close();
System.out.println(str);
dblastversion = Integer.valueOf(str);
if (dbversion < dblastversion)
System.out.println("updates available");
} catch (IOException e) {
e.printStackTrace();
}
}
When I try to run the app crash and I got this error from logcat:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ex.example/com.ex.example.ActMenu}: android.os.NetworkOnMainThreadException
On this line
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
Somebody know what is the problem? Or its better use another cloud to stor the textfile. Thanks for the help.
UPDATE 2
Ok as GPRathour said I updated my code to this:
class Getversion_Async extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Void... arg0) {
System.out.println("starting");
try {
URL url = new URL("https://onedrive.live.com/redir?resid=b9186f8cb138a030!56556&authkey=!AFmrzOGv_OMArzo&ithint=file%2ctxt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
str = in.readLine();
in.close();
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(final Void unused) {
System.out.println("ended");
}
}
And I call in th onCreate like this to test:
new Getversion_Async().execute();
Ok this code runs fine I use a site to host the file and the link ends with .txt and works fine but I cant edit the file. Somebody know how I can do this with onedrive?
The exception clearly says android.os.NetworkOnMainThreadException. To read file from server you need to perform some Network operation and it is not a good practice to perform it on Main Thread / UI Thread as it will hang the UI till the operation is performed.
What you need to do is, run this in AsyncTask
class LogoutUser_Async extends AsyncTask<Void, Void, Void> {
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Void... arg0) {
// Do your network task here
return null;
}
#Override
protected void onPostExecute(final Void unused) {
// Process the result
}
}
I'm new in java, and im trying to read a text file from the web into a variable, but i'm getting the text file's url, instead of the content, and just can't figure out what could be the problem.
The class where i'm trying to read the file:
public class readtextfile extends AsyncTask<String, Integer, String>{
private TextView description;
public readtextfile(TextView descriptiontext){
this.description = descriptiontext;
}
#Override
protected String doInBackground(String... params) {
URL url = null;
String result ="";
try {
url = new URL("http://example.com/description1.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String line = null;
while ((line = in.readLine()) != null) {
result+=line;
}
in.close();
}
catch (MalformedURLException e) {e.printStackTrace();}
catch (IOException e) {e.printStackTrace();}
return result;
}
protected void onProgressUpdate() {
//called when the background task makes any progress
}
protected void onPreExecute() {
//called before doInBackground() is started
}
#Override
protected void onPostExecute(String result) {
this.description.setText(result);
}
}
The Activity where i call the class:
public class PhotosActivity extends Activity {
TextView description;
String descriptiontext;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photos_layout);
description = ((TextView)findViewById(R.id.description1));
new readtextfile(description).execute();
}
}
Try url.openConnection and the use connection object to get inputStream. The updated method would be like
protected String doInBackground(String... params) {
URL url = null;
String result = "";
try {
url = new URL("http://www.example.com/description1.txt");
URLConnection connection = url.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
result += line;
}
in.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
Update based on your comment.
You need not invoke the postExecute method. If you invoke postExecute it just execute that method. The doInBackground wont get exeuted. Instead you should use the execute method. Just like java thread.start() method invoke the overridden run() method.
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
refer developer doc
Try using Scanner like this.
URL url = new URL("http://www.example.com/description1.txt");
Scanner s = new Scanner(url.openStream());