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