-1

I have two applications one is the service and one is the client the client is connected to the service application via AIDL . when the client receives data from the service I want it to display it in a textView, however I am unable to update the textView , I get the following error :

*** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
            at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4039)
            at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:709)
            at android.view.View.requestLayout(View.java:12675)
            at android.view.View.requestLayout(View.java:12675)
            at android.view.View.requestLayout(View.java:12675)
            at android.view.View.requestLayout(View.java:12675)
            at android.view.View.requestLayout(View.java:12675)
            at android.view.View.requestLayout(View.java:12675)
            at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:268)
            at android.view.View.requestLayout(View.java:12675)
            at android.widget.TextView.checkForRelayout(TextView.java:6773)
            at android.widget.TextView.setText(TextView.java:3306)
            at android.widget.TextView.setText(TextView.java:3162)
            at android.widget.TextView.setText(TextView.java:3137)
            at com.tfl.tfltemperatureapplication.MainActivity.DisplayTemp(MainActivity.java:139)
            at com.tfl.tfltemperatureapplication.MainActivity$1.onSuccess(MainActivity.java:84)
            at com.tfl.extprotocolservice.IParameterCallBack$Stub.onTransact(IParameterCallBack.java:54)
            at android.os.Binder.execTransact(Binder.java:338)
            at dalvik.system.NativeStart.run(Native Method)

My client code :

public class MainActivity extends ActionBarActivity implements ServiceConnection {
    double temperature;
    TextView frontTemp,rearTemp;
    private IParameter binding=null;
    public static final int FRONT_TEMPERATURE_PARAMETER=262;
    public static final int REAR_TEMPERATURE_PARAMETER=263;

    public static final String TAG="TEMPERATURE";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(activity_main);
        frontTemp= (TextView) findViewById(R.id.front_temp);
        rearTemp= (TextView) findViewById(R.id.rear_temp);
        connectToService();
    }

    public void connectToService() {
        Intent implicit = new Intent(IParameter.class.getName());
        List<ResolveInfo> matches = getPackageManager().queryIntentServices(implicit, 0);
        if (matches.size() == 0) {
            Toast.makeText(getApplicationContext(), "Cannot find a matching service!", Toast.LENGTH_LONG).show();
        } else if (matches.size() > 1) {
            Toast.makeText(getApplicationContext(), "Found multiple matching services!", Toast.LENGTH_LONG).show();
        } else {

            Intent explicit = new Intent(implicit);
            ServiceInfo svcInfo = matches.get(0).serviceInfo;
            ComponentName cn = new ComponentName(svcInfo.applicationInfo.packageName, svcInfo.name);
            explicit.setComponent(cn);
            ComponentName myService=startService(new Intent(this,IParameter.class));
            bindService(explicit, this, Context.BIND_AUTO_CREATE);


        }
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.d(TAG, "Connected to service");
        Thread t1=new Thread(new BindingToService(service));
        t1.start();


    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        binding=null;

    }
    IParameterCallBack.Stub cb=new IParameterCallBack.Stub(){



        @Override
        public void onSuccess(int parameter, int value) throws RemoteException {
            temperature=ConvertToCelcius(value);
            DisplayTemp(parameter,temperature);

        }

        @Override
        public void onFailure(String msg) throws RemoteException {
            Log.d(TAG,"Failed to receive parameter: "+msg );

        }
    };

    public class BindingToService implements Runnable{
        IBinder service;
        public BindingToService(IBinder service){
            this.service=service;
        }

        @Override
        public void run() {
            binding=IParameter.Stub.asInterface(service);
            while(true){
                try {
                    binding.askForParameter(FRONT_TEMPERATURE_PARAMETER,cb);
                } catch (RemoteException e) {
                    Log.e(TAG, "" + e);
                }
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    binding.askForParameter(REAR_TEMPERATURE_PARAMETER, cb);
                } catch (RemoteException e) {
                    Log.e(TAG, "" + e);
                }
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }
    }
    public static double ConvertToCelcius(int temperature){
        return (double)temperature*0.00390625-273;
    }

    public void DisplayTemp(int parameter,double temperature){
        if(parameter==262){
            frontTemp.setText(""+temperature);
        }
        if(parameter==263){
            rearTemp.setText(""+temperature);
        }
    }
yanish
  • 257
  • 2
  • 15

2 Answers2

4

Instead of using

textView.setText("text");

use

textView.post(new Runnable(){    
    @Override
    public void run(){
        textView.setText("text");
    }    
};

This can be called from any Thread and will always execute the Runnable action on the UI Thread. Also, it does not require you to have a reference to a Context object, which saves you from making unneeded cross-references.

Kelevandos
  • 7,024
  • 2
  • 29
  • 46
1

you can use

runOnUiThread(new Runnable() {
        @Override
        public void run() {
            //do your UI related operation
        }
    }); 
Ravi
  • 34,851
  • 21
  • 122
  • 183
  • 1
    This will work fine, but it requires the caller to implement Context or have a Context reference. In complex application it is not a given, please see my answer. – Kelevandos Aug 25 '15 at 12:11