activity and service communication binder

From the perspective of js's closure, the activity gets the internal value of the service

Js code

function service(){
let count=0;
return function(){
          return count
       }
}

function activity(){
   let ser=service();//step one

   //Get the value of the local variable inside the service function
   let getCount=ser();
}


There is nothing special about this code, but it is somewhat similar to the android activity getting the value inside the service.

ideas

On the service object, the android service is almost the same as the js service code above, but the android return is written in a specific method onBind

public class MsTestService extends Service {



    private int count = 2;



    private MsBinder binder = new MsBinder();

  //Maintaining an inner class is somewhat similar in thinking to the anonymous function returned in js

    public class MsBinder extends Binder {



        public int getCount() {

            return count;

        }

    }



    @Override

    public void onCreate() {

        super.onCreate();

    }



    @Override

    public IBinder onBind(Intent intent) {

        return binder;

    }

}

activity

In terms of activity, the activity of andrid is almost the same as the activity of js, but it needs to maintain an inner class that implements ServiceConnection, obtain the binder object in this inner class, and obtain the internal data of the service through this binder object.

And this instance of ServiceConnection needs to be associated with the current activity through the help of Intent &&bindService (I don't understand the principle for the time being, record the question first), and it also needs to be unbound when the activity is destroyed.

code show as below:

public class MainActivity2 extends AppCompatActivity {

    private MsTestService.MsBinder mBinder;

  //Instance inner class ====

    private TestConnection conn = new TestConnection();

    private Button btn;

    private TextView txt;

@Override
protected void onDestroy() {
    unbindService(conn);
    super.onDestroy();
}
    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main2);

//Need to use intent and bindService to bind service to the current activity

    //If you don't add these 2 lines, the app crashes

        Intent it = new Intent(this,MsTestService.class);

        bindService(it, conn, BIND_AUTO_CREATE);



        btn=findViewById(R.id.btn);

        txt=findViewById(R.id.text);

        btn.setOnClickListener(view -> {

//get service

           int count= mBinder.getCount();   

           txt.setText(String.valueOf(count));

        });

    }

  //Maintain an inner class =============It implements ServiceConnection

    private final class TestConnection implements ServiceConnection {

        public void onServiceConnected(ComponentName name, IBinder service) {

            mBinder = (MsTestService.MsBinder)service;



        }

        public void onServiceDisconnected(ComponentName name) {

            mBinder = null;

        }

    }

}

The value in the above code service is always 2, which is a bit fake. Let's write a timed task and it will increase by one every second, so that each time the button is clicked, the result will be different.

Thread

public class MsTestService extends Service {



    private int count = 2;



    private MsBinder binder = new MsBinder();



    public class MsBinder extends Binder {



        public int getCount() {

            return count;

        }

    }



    @Override

    public void onCreate() {

        super.onCreate();

//auto increment function

        autoAdd();

    }

    /**

     * Monitor the progress, call the getProgress() method of MsgService every second to obtain the progress and update the UI

     */

    public void autoAdd(){

        new Thread(() -> {

            while(count < 10000){

                count+=1;

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }



        }).start();

    }



    @Override

    public IBinder onBind(Intent intent) {

        return binder;

    }

}

The service actively updates the activity

Can the service actively update the content of the activity without requiring the user to click it?

Can

Callback

First, the service needs to provide a way to pass the callback function to the activity.

When the activity passes the callback function, the Service saves the callback function, and then continuously calls the callback function during the countdown.

Callback? I'm familiar with this, isn't js also written like this?

function a(cb){
    let callbak=cb;
    setInterval(()=>callbak(),1000)
}

Java is similar, but with relatively more template code

Service

Declare an interface, this interface has a method with an int parameter named onProgress

public interface OnProgressListener {

    void onProgress(int progress);

}

//declare a variable to store

private OnProgressListener onProgressListener;


//Declare a method to update [the variable that stores the callback function]

public void setOnProgressListener(OnProgressListener onProgressListener) {

    this.onProgressListener = onProgressListener;

}


Activity

msTestService.setOnProgressListener(new MsTestService.OnProgressListener() {



    @Override

    public void onProgress(int count) {

        txt.setText(String.valueOf(count));



    }

});

When changing to lambda, the code becomes like this, is it a bit es6 rushed?

msTestService.setOnProgressListener(count -> txt.setText(String.valueOf(count)));

full code

acitivty

public class MainActivity2 extends AppCompatActivity {
    private MsTestService.MsBinder mBinder;
    private MsTestService  msTestService;
    private TestConnection conn = new TestConnection();
    private Button btn;
    private TextView txt;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Intent it = new Intent(this,MsTestService.class);
        bindService(it, conn, BIND_AUTO_CREATE);

        btn=findViewById(R.id.btn);
        txt=findViewById(R.id.text);
        btn.setOnClickListener(view -> {
           int count= mBinder.getCount();   
           txt.setText(String.valueOf(count));
        });
    }

    private final class TestConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinder = (MsTestService.MsBinder)service;
            msTestService= mBinder.getServerInstance();
            msTestService.setOnProgressListener(count -> txt.setText(String.valueOf(count)));

        }
        public void onServiceDisconnected(ComponentName name) {
            mBinder = null;
        }
    }
    @Override
    protected void onDestroy() {
        unbindService(conn);
        super.onDestroy();
    }
}

//omit

sevice

public class MsTestService extends Service {

    private int count = 2;
    //Add a callback interface
    public interface OnProgressListener {
        void onProgress(int progress);
    }

    /**
     * Callback interface for update progress
     */
    private OnProgressListener onProgressListener;


    /**
     * Register the method of the callback interface for external invocation
     * @param onProgressListener
     */
    public void setOnProgressListener(OnProgressListener onProgressListener) {
        this.onProgressListener = onProgressListener;
    }

    private MsBinder binder = new MsBinder();

    public class MsBinder extends Binder {
        public int getCount() {
            return count;
        }
        //Provides methods for obtaining instances of external classes
        public MsTestService getServerInstance() {
            return MsTestService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        autoAdd();
    }
    /**
     * Monitor the progress, call the getProgress() method of MsgService every second to obtain the progress and update the UI
     */
    public void autoAdd(){
        new Thread(() -> {
            while(count < 10000){
                count+=1;
                //Notify caller of progress change
                if(onProgressListener != null){
                    onProgressListener.onProgress(count);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }).start();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

Inner class access outer class instance

MsTestService.this

In addition to binder, there is also the form of broadcasting, refer to Several ways to communicate between Android Service and Activity - Alibaba Cloud Community

Tags: Android Javascript binder

Posted by mikeylikesyou on Mon, 10 Oct 2022 22:18:33 +0530