Reputation: 43
I am writing a socket client application by android. Right now I encounter a problem with how to deal my a nest UI in the do while loop. Because I want my programm keep listening message from the server until server Terminate. Because network exception, I put those socket connection into AsyncTask, but once i run the client, it only can process readobject() in processConnection()
here is original client code.
package com.example.socketclien;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.OutputStream;
import java.io.StreamCorruptedException;
import java.net.Socket;
import java.net.UnknownHostException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class ClientFragment extends Fragment {
private Socket clientSocket;
private Button mSentButton;
private TextView mMessageTextView;
private EditText mMessagEditText;
private String message="";
private ObjectOutputStream outputStream;
private ObjectInputStream inputStream;
private static String TAG="clientFragment";
AsyncTask<Void, Void, Void> mRegisterTask;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.i(TAG,"onCreate starts");
}
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
//refer a view which wires a layout
View v = inflater.inflate(R.layout.fragment_client,parent,false);
mSentButton=(Button)v.findViewById(R.id.Sentbutton);
mMessageTextView=(TextView)v.findViewById(R.id.messageTextView);
Log.i(TAG,"onCreateView starts");
mMessagEditText=(EditText)v.findViewById(R.id.Message);
new connection().execute();
return v;
}
public void runClient() throws IOException, Throwable
{
Log.i(TAG,"runClient() starts");
connectToServer();
getStreams();
processConnection();
closeConnection();
}
private void connectToServer() throws IOException, Exception {
// TODO Auto-generated method stub
Log.i(TAG,"connectToServer() starts");
mMessageTextView.setText("Attempting connection\n");
Log.i(TAG,"connectToServer() 's setText starts");
clientSocket = new Socket("134.129.125.123",8080);
Log.i(TAG,"connectToServer() 's Connect to 134.129.125.123");
mMessageTextView.append("Connect to "+"134.129.125.123 \n");
}
private void getStreams() throws IOException{
// TODO Auto-generated method stub
Log.i(TAG,"getStreams()'s onGetStream starts");
outputStream = new ObjectOutputStream(clientSocket.getOutputStream());
outputStream.flush();
Log.i(TAG,"getStreams()'s outputStream created");
inputStream = new ObjectInputStream(clientSocket.getInputStream());
mMessageTextView.append("\nGot i/O stream \n");
}
private class connection extends AsyncTask{
@Override
protected Object doInBackground(Object... params) {
// TODO Auto-generated method stub
try {
connectToServer();
getStreams();
processConnection();
closeConnection();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
private void processConnection(){
Log.i(TAG,"ProcessConnection() starts");
// TODO Auto-generated method stub
do {
try {
message=(String) inputStream.readObject();
} 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();
}
Log.i(TAG,"ProcessConnection()'s readobject() starts");
mMessageTextView.append("\n"+ message);
Log.i(TAG,"ProcessConnection()'s append() starts");
} while (!message.equals("SERVER>>> TERMINATE"));
}
private void closeConnection() throws IOException {
// TODO Auto-generated method stub
Log.i(TAG,"closeConnection starts");
mMessageTextView.append("\nTerminating connection\n");
outputStream.close();
inputStream.close();
clientSocket.close();
}
private void sentDate(String message)
{
try {
outputStream.writeObject("CLIENT>>>"+message);
outputStream.flush();
mMessageTextView.append("\nCLIENT>>>"+ message);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The Error:
08-22 11:11:53.230: W/System.err(12048): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
08-22 11:11:53.240: W/System.err(12048): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6024)
08-22 11:11:53.240: W/System.err(12048): at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:853)
08-22 11:11:53.240: W/System.err(12048): at android.view.ViewGroup.invalidateChild(ViewGroup.java:4320)
08-22 11:11:53.240: W/System.err(12048): at android.view.View.invalidate(View.java:10935)
08-22 11:11:53.240: W/System.err(12048): at android.view.View.invalidate(View.java:10890)
08-22 11:11:53.240: W/System.err(12048): at android.widget.TextView.updateAfterEdit(TextView.java:7430)
08-22 11:11:53.240: W/System.err(12048): at android.widget.TextView.handleTextChanged(TextView.java:7453)
08-22 11:11:53.240: W/System.err(12048): at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:9187)
08-22 11:11:53.240: W/System.err(12048): at android.text.SpannableStringBuilder.sendTextChanged(SpannableStringBuilder.java:962)
08-22 11:11:53.240: W/System.err(12048): at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:496)
08-22 11:11:53.240: W/System.err(12048): at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:253)
08-22 11:11:53.240: W/System.err(12048): at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:30)
08-22 11:11:53.240: W/System.err(12048): at android.widget.TextView.append(TextView.java:3409)
08-22 11:11:53.240: W/System.err(12048): at android.widget.TextView.append(TextView.java:3396)
08-22 11:11:53.240: W/System.err(12048): at com.example.socketclien.ClientFragment.processConnection(ClientFragment.java:174)
08-22 11:11:53.240: W/System.err(12048): at com.example.socketclien.ClientFragment.access$2(ClientFragment.java:153)
08-22 11:11:53.240: W/System.err(12048): at com.example.socketclien.ClientFragment$connection.doInBackground(ClientFragment.java:100)
08-22 11:11:53.240: W/System.err(12048): at android.os.AsyncTask$2.call(AsyncTask.java:288)
08-22 11:11:53.240: W/System.err(12048): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
08-22 11:11:53.240: W/System.err(12048): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
08-22 11:11:53.240: W/System.err(12048): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
08-22 11:11:53.240: W/System.err(12048): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
08-22 11:11:53.240: W/System.err(12048): at java.lang.Thread.run(Thread.java:841)
08-22 11:15:51.574: W/System.err(13286): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
08-22 11:15:51.574: W/System.err(13286): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6024)
08-22 11:15:51.574: W/System.err(13286): at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:853)
08-22 11:15:51.574: W/System.err(13286): at android.view.ViewGroup.invalidateChild(ViewGroup.java:4320)
08-22 11:15:51.574: W/System.err(13286): at android.view.View.invalidate(View.java:10935)
08-22 11:15:51.574: W/System.err(13286): at android.view.View.invalidate(View.java:10890)
08-22 11:15:51.574: W/System.err(13286): at android.widget.TextView.updateAfterEdit(TextView.java:7430)
08-22 11:15:51.584: W/System.err(13286): at android.widget.TextView.handleTextChanged(TextView.java:7453)
08-22 11:15:51.584: W/System.err(13286): at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:9187)
08-22 11:15:51.584: W/System.err(13286): at android.text.SpannableStringBuilder.sendTextChanged(SpannableStringBuilder.java:962)
08-22 11:15:51.584: W/System.err(13286): at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:496)
08-22 11:15:51.584: W/System.err(13286): at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:253)
08-22 11:15:51.584: W/System.err(13286): at android.text.SpannableStringBuilder.append(SpannableStringBuilder.java:30)
08-22 11:15:51.584: W/System.err(13286): at android.widget.TextView.append(TextView.java:3409)
08-22 11:15:51.584: W/System.err(13286): at android.widget.TextView.append(TextView.java:3396)
08-22 11:15:51.584: W/System.err(13286): at com.example.socketclien.ClientFragment.processConnection(ClientFragment.java:131)
08-22 11:15:51.584: W/System.err(13286): at com.example.socketclien.ClientFragment.access$2(ClientFragment.java:110)
08-22 11:15:51.584: W/System.err(13286): at com.example.socketclien.ClientFragment$connection.doInBackground(ClientFragment.java:98)
08-22 11:15:51.584: W/System.err(13286): at android.os.AsyncTask$2.call(AsyncTask.java:288)
08-22 11:15:51.584: W/System.err(13286): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
08-22 11:15:51.584: W/System.err(13286): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
08-22 11:15:51.584: W/System.err(13286): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
08-22 11:15:51.584: W/System.err(13286): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
08-22 11:15:51.584: W/System.err(13286): at java.lang.Thread.run(Thread.java:841)
I know it must happen between UIthread and Asytask.
Upvotes: 1
Views: 347
Reputation: 18977
you can not update UI thread or any widget from none UI thread. asynctask is a none UI thread, so you can not update your textview
from its method execpt you are in onPreExecute()
or onProgressUpdate
or onPostExecute()
.every time you want to acccess UI thread you can use runOnUiThread
for example all codes in asynctask that are in doInBackground
method can accesses to mMessageTextView
like any of these ways:
ClientFragment.this.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mMessageTextView.append("\nTerminating connection\n");
}
});
or you can use:
mMessageTextView.post(new Runnable() {
@Override
public void run() {
mMessageTextView.append("\nTerminating connection\n");
}
});
you can also publish your updates by using publishProgress()
and onProgressUpdate
. for quick information just look at :
http://developer.android.com/reference/android/os/AsyncTask.html
you can also use handler
. if you want to know more let me edit this answer to include handler sample code.
Upvotes: 1
Reputation: 9103
You cannot update UI from doInBackground()
method.
You can call Activity.runOnUiThread(Runnable action)
e.g.
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mMessageTextView.append("Connect to "+"134.129.125.123 \n");
}
});
or use this:
mMessageTextView.post(new Runnable() {
@Override
public void run() {
mMessageTextView.append("Connect to "+"134.129.125.123 \n");
}
});
Upvotes: 0