11. Why separate process?
● GC not affecting your app
● Crashing not affecting UI
● Less chance to be killed:
○ Process serving others has at least the ranking of those it serve
○ Process with Service > Process with Background activities
● New Heap Space
● Smaller cold start + resource efficiency
● Because we can! :)
12. Why and when not?
●If you don’t have driver licenses
●Memory leaks
●Two process
●Keep it simple, stupid
18. Benefit for free
●Thread migration
●Identifying senders to receivers
●Unique object-mapping across process
●AIDL!!!!
●Bult-in support for marshalling
●Local execution mode (no IPC) if same process
19. We are already using binder today
●LifeCycle callbacks (onResume, OnDestroy) invoked by
ActivityManagerService
●Intents
●Content Provider
21. DarthVaderActivity
@Override
public void onClick(View v) {
Intent intent = new Intent(this, EmpireService.class);
switch (v.getId()) {
case R.id.iv_dva_build_death_star:
intent.putExtra(COMMAND_TYPE,
EmpireService.EmpireServiceCommands.BUILD_DEATH_STAR);
break;
case R.id.iv_dva_interact_with_luke:
intent.putExtra(COMMAND_TYPE,
EmpireService.EmpireServiceCommands.FIND_LUKE);
break;
}
mStartedCommandTime = System.currentTimeMillis();
startService(intent);
}
22. DarthVaderActivity
public class EmpireServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG,"Time took: " +String.valueOf(System.currentTimeMillis()-
mStartedCommandTime));
Toast.makeText(DarthVaderActivity.this, "Death Star deployed and ready for
your command, my lord",
Toast.LENGTH_LONG).show();
}
}
23. EmpireService
public int onStartCommand(Intent intent, int flags, int startId) {
EmpireServiceCommands command = (EmpireServiceCommands) intent.getExtras()
.get(COMMAND_TYPE);
switch (command) {
case BUILD_DEATH_STAR:
..do some hard work...
Intent jobDoneIntent = new Intent(EMPIRE_SERVICE_ACTION);
jobDoneIntent.putExtra("result",
new DeathStar(270000, 270000, "THIS IS THE BIG GUN"));
sendBroadcast(jobDoneIntent);
break;
case FIND_LUKE:
break;
}
stopSelf();
return START_NOT_STICKY;
}
26. A reference to a Handler that can be sent to a remote process via
an Intent
Messages sent by the remote process via the messenger are
delivered to the local handler
Relatively fast
Overview
27. DarthVaderActivity
public void onClick(View v) {
Intent intent = new Intent(this, EmpireService.class);
Messenger messenger = new Messenger(new DarthVaderHandler(this));
intent.putExtra("ImperialMessenger", messenger);
switch (v.getId()) {
case R.id.iv_dva_build_death_star:
intent.putExtra("Command type",
EmpireService.EmpireServiceCommands.BUILD_DEATH_STAR);
break;
case R.id.iv_dva_interact_with_luke:
intent.putExtra("Command type",
EmpireService.EmpireServiceCommands.FIND_LUKE);
break;
}
startService(intent);
}
28. DarthVaderActivity
private static class DarthVaderHandler extends Handler {
private final WeakReference<DarthVaderActivity> clientRef;
public DarthVaderHandler(DarthVaderActivity client) {
this.clientRef = new WeakReference<>(client);
}
...//Handle message
}
29. DarthVaderActivity
private static class DarthVaderHandler extends Handler {
@Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
DarthVaderActivity client = clientRef.get();
if (client != null && msg.what == EmpireService.CALLBACK_MSG && data != null) {
Toast.makeText(client, "Death Star deployed and ready for your command, my lord",
Toast.LENGTH_LONG).show();
}
}
}
30. EmpireService
public int onStartCommand(Intent intent, int flags, int startId) {
Messenger messenger = intent.getParcelableExtra("ImperialMessenger");
EmpireServiceCommands command = (EmpireServiceCommands) intent.getExtras()
.get("Command type");
… more code coming...
31. EmpireService
switch (command) {
case BUILD_DEATH_STAR:
..do some hard work...
if (messenger != null) {
Message message = Message.obtain();
message.what = CALLBACK_MSG;
Bundle data = new Bundle(1);
data.putParcelable("result",
new DeathStar(270000, 270000, "THIS IS THE BIG GUN"));
message.setData(data);
try {
messenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
34. Android Interface Definition Language (AIDL)
Our business operation on top of Binder object
Java-like interface
Defined in a separate .aidl file
AIDL Generate code of real java interface
38. IStarWars.Stub
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder
implements com.academy.android.aidlserviceexample.IStarWars {
@Override
public java.lang.String buildDeathStar(
com.academy.android.aidlserviceexample.DeathStar deathStar)
throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_buildDeathStar, _data, _reply, 0);
… not really necessary to dig in
39. Interface directional flag
in means that the object is transferred from client to service and
only used for inputs. If any changes are made to the bar object in
the service then they won’t reflect in the client.
out indicates that the object has no relevant data and will be
populated by the service and returned as a response.
inout means that the data gets copied, i.e., if any changes are
made to bar in the service then that’ll also reflect in the client’s
bar object.
40. AIDL Data Types
All primitives and arrays of
primitives
FileDescriptor
Serializable/Parcelable****
Map
Bundle
List
SparseArray
42. IStarWarsImplementation
public class IStarWarsImplementation extends IStarWars.Stub {
public String buildDeathStar(DeathStar deathStar) throws RemoteException {
...doing hard work..
deathStar.setBFG("BIG GUN IS VERY VERY");
deathStar.setHeight(270000);
deathStar.setWidth(270000);
return "Death Star deployed and ready for your command, my lord";
}
…
other interface methods
43. EmpireService
public class EmpireService extends Service {
private IStarWarsImplementation service;
@Override
public void onCreate() {
super.onCreate();
service = new IStarWarsImplementation();
}
44. EmpireService
@Override
public IBinder onBind(Intent intent) {
return service;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
this.service = null;
super.onDestroy();
}
45. DarthVaderActivity
public class DarthVaderActivity extends Activity implements ServiceConnection {
@Override
protected void onResume() {
super.onResume();
final boolean isServiceBounded = super.bindService(new Intent(this,
EmpireService.class),
this, BIND_AUTO_CREATE);
if (!isServiceBounded) {
Log.w(TAG, "Failed to bind to service");
}
}
… more methods
50. IStarWarsImplementation
...other AIDL interface implementation methods
@Override
public void findLuke(IEmpireServiceResponseListener listener) throws RemoteException
{
..Doing very hard job through couple episodes…
listener.onResponse("I'm your father, Luke!");
}
51. DarthVaderActivity
IEmpireServiceResponseListener.Stub mListener
= new IEmpireServiceResponseListener.Stub() {
@Override
public void onResponse(final String response) throws RemoteException {
//Other process. We should run on UI Thread in order to interact with UI
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(DarthVaderActivity.this, response,
Toast.LENGTH_LONG)
.show();
}
});
}
};