user3799770
user3799770

Reputation: 43

How to deal with AsyncTask with UI thread in the do while situation

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

Answers (2)

mmlooloo
mmlooloo

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 onProgressUpdateor 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

Damian Petla
Damian Petla

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

Related Questions