上一篇说道Binder机制的通讯框架,也说过Messenger的底层实现自AIDL,所以对于跨进程通讯中,Messenger是一种比较高级的框架,能够说对于一个app开发者来讲重要性不言而喻多线程
public class BackgroundService extends Service { private Messenger mMessenger = null;//监听数据 private Messenger replyMessenger = null //响应数据 @Override public IBinder onBind(Intent intent) { if(mMessenger==null) { mMessenger = new Messenger(new ServerHandler()); } return mMessenger.getBinder(); } @Override public boolean onUnbind(Intent intent) { return super.onUnbind(intent); } //注意,将ServerHandler静态化,以防止内存泄露 public static class ServerHandler extends Handler { @Override public void handleMessage(Message msg) { if (msg.what>0) { try { replyMessenger = msg.replyTo; replyMessenger.send(Message.obtain(null,0x000001, HttpStatus.SC_OK, 0)); LogUtils.e("[后台数据]=>报告地瓜,土豆收到 <MSGID[FlightID:"+msg.obj+",arg1:"+msg.arg1+"]>"); } catch (RemoteException e) { e.printStackTrace(); } } else { super.handleMessage(msg); } } } }
public class MainActivity extends Activity { private Activity activity = null; private final int RETRY_INTERVAL_TIME = 2 * 1000; private final Messenger clientMessenger= new Messenger(new ClientHandler()); private Messenger replyMessenger = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); activity = this; startBackgroundService(this); //启动广播是异步的,所以必须经过不断轮询的方式来检测广播是否已启动 bindgroundService(); } public static class ClientHandler extends Handler { @Override public void handleMessage(Message msg) { if (msg.what == HttpStatus.SC_OK) { //msg.arg1就是remoteInt Log.i("TAG", "服务端响应数据:"+msg.arg1); } else { super.handleMessage(msg); } } } /**绑定服务*/ private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { replyMessenger = null; LogUtils.d("ServiceClient>>service onServiceDisconnected :链接失败"); } @Override public void onServiceConnected(ComponentName name, IBinder service) { replyMessenger = new Messenger(service); LogUtils.d("ServiceClient>>service onServiceConnected : 链接成功"); if(replyMessenger !=null) { LogUtils.e("[前台数据]==>土豆土豆,我是地瓜,收到请回应!"); Message msgTo = Message.obtain(null,200); msgTo.obj = "[如今能够开始上传数据]"; msgTo.arg1 = 1024; msgTo.replyTo = clientMessenger; try { replyMessenger.send(msgTo); } catch (RemoteException e) { e.printStackTrace(); } } } }; /** * 启动后台服务 * @param context */ private void startBackgroundService(Context context) { if(!isServiceRunning(BackgroundService.class.getName(),context)) { Intent targetIntent = new Intent(context,RCCBackgroundService.class); //targetIntent.setAction(TARGET_SERVICE_ACTION); context.startService(targetIntent); } } /** * 绑定后台服务 */ private void bindgroundService() { if(replyMessenger ==null && isServiceRunning(BackgroundService.class.getName())) { Log.e("[前台数据]","[绑定服务]"); activity.getWindow().getDecorView().postDelayed(new Runnable() { @Override public void run() { Intent intent = new Intent(activity, BackgroundService.class); intent.setAction(WifiNetworkChangedReceiver.TARGET_SERVICE_ACTION); activity.bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE); } }, RETRY_INTERVAL_TIME); }else{ activity.getWindow().getDecorView().postDelayed(new Runnable() { @Override public void run() { replyMessenger = null; bindgroundService(); } }, RETRY_INTERVAL_TIME); } } /** * 检测Service是否已经启动 * @param serviceClassName * @return */ public boolean isServiceRunning(String serviceClassName) { final ActivityManager activityManager = (ActivityManager)activity.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE); for (RunningServiceInfo runningServiceInfo : services) { if (runningServiceInfo.service.getClassName().equals(serviceClassName)) { LogUtils.e("-ServiceClient->服务已经启动,开始绑定后台服务"); return true; } } LogUtils.e("->ServiceClient->服务未启动,等待从新尝试绑定服务!"); return false; } }
Android 5.0的调度做业JobScheduler并发
原理是经过Parceable参数传递app
public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); public static final int MSG_UNCOLOR_START = 0; public static final int MSG_UNCOLOR_STOP = 1; public static final int MSG_COLOR_START = 2; public static final int MSG_COLOR_STOP = 3; public static final String MESSENGER_INTENT_KEY = BuildConfig.APPLICATION_ID + ".MESSENGER_INTENT_KEY"; public static final String WORK_DURATION_KEY = BuildConfig.APPLICATION_ID + ".WORK_DURATION_KEY"; private EditText mDelayEditText; private EditText mDeadlineEditText; private EditText mDurationTimeEditText; private RadioButton mWiFiConnectivityRadioButton; private RadioButton mAnyConnectivityRadioButton; private CheckBox mRequiresChargingCheckBox; private CheckBox mRequiresIdleCheckbox; private ComponentName mServiceComponent; private int mJobId = 0; // Handler for incoming messages from the service. private IncomingMessageHandler mHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sample_main); // Set up UI. mDelayEditText = (EditText) findViewById(R.id.delay_time); mDurationTimeEditText = (EditText) findViewById(R.id.duration_time); mDeadlineEditText = (EditText) findViewById(R.id.deadline_time); mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered); mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any); mRequiresChargingCheckBox = (CheckBox) findViewById(R.id.checkbox_charging); mRequiresIdleCheckbox = (CheckBox) findViewById(R.id.checkbox_idle); mServiceComponent = new ComponentName(this, MyJobService.class); mHandler = new IncomingMessageHandler(this); } @Override protected void onStop() { // A service can be "started" and/or "bound". In this case, it's "started" by this Activity // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call // to stopService() won't prevent scheduled jobs to be processed. However, failing // to call stopService() would keep it alive indefinitely. stopService(new Intent(this, MyJobService.class)); super.onStop(); } @Override protected void onStart() { super.onStart(); // Start service and provide it a way to communicate with this class. //主动发送Messenger,传递handler的IMessenger到Service Intent startServiceIntent = new Intent(this, MyJobService.class); Messenger messengerIncoming = new Messenger(mHandler); startServiceIntent.putExtra(MESSENGER_INTENT_KEY, messengerIncoming); startService(startServiceIntent); } /** * Executed when user clicks on SCHEDULE JOB. */ public void scheduleJob(View v) { JobInfo.Builder builder = new JobInfo.Builder(mJobId++, mServiceComponent); String delay = mDelayEditText.getText().toString(); if (!TextUtils.isEmpty(delay)) { builder.setMinimumLatency(Long.valueOf(delay) * 1000); } String deadline = mDeadlineEditText.getText().toString(); if (!TextUtils.isEmpty(deadline)) { builder.setOverrideDeadline(Long.valueOf(deadline) * 1000); } boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked(); boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked(); if (requiresUnmetered) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); } else if (requiresAnyConnectivity) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); } builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked()); builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked()); // Extras, work duration. PersistableBundle extras = new PersistableBundle(); String workDuration = mDurationTimeEditText.getText().toString(); if (TextUtils.isEmpty(workDuration)) { workDuration = "1"; } extras.putLong(WORK_DURATION_KEY, Long.valueOf(workDuration) * 1000); builder.setExtras(extras); // Schedule job Log.d(TAG, "Scheduling job"); JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); tm.schedule(builder.build()); } /** * Executed when user clicks on CANCEL ALL. */ public void cancelAllJobs(View v) { JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); tm.cancelAll(); Toast.makeText(MainActivity.this, R.string.all_jobs_cancelled, Toast.LENGTH_SHORT).show(); } /** * Executed when user clicks on FINISH LAST TASK. */ public void finishJob(View v) { JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); List<JobInfo> allPendingJobs = jobScheduler.getAllPendingJobs(); if (allPendingJobs.size() > 0) { // Finish the last one int jobId = allPendingJobs.get(0).getId(); jobScheduler.cancel(jobId); Toast.makeText( MainActivity.this, String.format(getString(R.string.cancelled_job), jobId), Toast.LENGTH_SHORT).show(); } else { Toast.makeText( MainActivity.this, getString(R.string.no_jobs_to_cancel), Toast.LENGTH_SHORT).show(); } } /** * A {@link Handler} allows you to send messages associated with a thread. A {@link Messenger} * uses this handler to communicate from {@link MyJobService}. It's also used to make * the start and stop views blink for a short period of time. */ private static class IncomingMessageHandler extends Handler { // Prevent possible leaks with a weak reference. private WeakReference<MainActivity> mActivity; IncomingMessageHandler(MainActivity activity) { super(/* default looper */); this.mActivity = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { MainActivity mainActivity = mActivity.get(); if (mainActivity == null) { // Activity is no longer available, exit. return; } View showStartView = mainActivity.findViewById(R.id.onstart_textview); View showStopView = mainActivity.findViewById(R.id.onstop_textview); Message m; switch (msg.what) { /* * Receives callback from the service when a job has landed * on the app. Turns on indicator and sends a message to turn it off after * a second. */ case MSG_COLOR_START: // Start received, turn on the indicator and show text. showStartView.setBackgroundColor(getColor(R.color.start_received)); updateParamsTextView(msg.obj, "started"); // Send message to turn it off after a second. m = Message.obtain(this, MSG_UNCOLOR_START); sendMessageDelayed(m, 1000L); break; /* * Receives callback from the service when a job that previously landed on the * app must stop executing. Turns on indicator and sends a message to turn it * off after two seconds. */ case MSG_COLOR_STOP: // Stop received, turn on the indicator and show text. showStopView.setBackgroundColor(getColor(R.color.stop_received)); updateParamsTextView(msg.obj, "stopped"); // Send message to turn it off after a second. m = obtainMessage(MSG_UNCOLOR_STOP); sendMessageDelayed(m, 2000L); break; case MSG_UNCOLOR_START: showStartView.setBackgroundColor(getColor(R.color.none_received)); updateParamsTextView(null, ""); break; case MSG_UNCOLOR_STOP: showStopView.setBackgroundColor(getColor(R.color.none_received)); updateParamsTextView(null, ""); break; } } private void updateParamsTextView(@Nullable Object jobId, String action) { TextView paramsTextView = (TextView) mActivity.get().findViewById(R.id.task_params); if (jobId == null) { paramsTextView.setText(""); return; } String jobIdText = String.valueOf(jobId); paramsTextView.setText(String.format("Job ID %s %s", jobIdText, action)); } private int getColor(@ColorRes int color) { return mActivity.get().getResources().getColor(color); } } }
public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); public static final int MSG_UNCOLOR_START = 0; public static final int MSG_UNCOLOR_STOP = 1; public static final int MSG_COLOR_START = 2; public static final int MSG_COLOR_STOP = 3; public static final String MESSENGER_INTENT_KEY = BuildConfig.APPLICATION_ID + ".MESSENGER_INTENT_KEY"; public static final String WORK_DURATION_KEY = BuildConfig.APPLICATION_ID + ".WORK_DURATION_KEY"; private EditText mDelayEditText; private EditText mDeadlineEditText; private EditText mDurationTimeEditText; private RadioButton mWiFiConnectivityRadioButton; private RadioButton mAnyConnectivityRadioButton; private CheckBox mRequiresChargingCheckBox; private CheckBox mRequiresIdleCheckbox; private ComponentName mServiceComponent; private int mJobId = 0; // Handler for incoming messages from the service. private IncomingMessageHandler mHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sample_main); // Set up UI. mDelayEditText = (EditText) findViewById(R.id.delay_time); mDurationTimeEditText = (EditText) findViewById(R.id.duration_time); mDeadlineEditText = (EditText) findViewById(R.id.deadline_time); mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered); mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any); mRequiresChargingCheckBox = (CheckBox) findViewById(R.id.checkbox_charging); mRequiresIdleCheckbox = (CheckBox) findViewById(R.id.checkbox_idle); mServiceComponent = new ComponentName(this, MyJobService.class); mHandler = new IncomingMessageHandler(this); } @Override protected void onStop() { // A service can be "started" and/or "bound". In this case, it's "started" by this Activity // and "bound" to the JobScheduler (also called "Scheduled" by the JobScheduler). This call // to stopService() won't prevent scheduled jobs to be processed. However, failing // to call stopService() would keep it alive indefinitely. stopService(new Intent(this, MyJobService.class)); super.onStop(); } @Override protected void onStart() { super.onStart(); // Start service and provide it a way to communicate with this class. Intent startServiceIntent = new Intent(this, MyJobService.class); Messenger messengerIncoming = new Messenger(mHandler); startServiceIntent.putExtra(MESSENGER_INTENT_KEY, messengerIncoming); startService(startServiceIntent); } /** * Executed when user clicks on SCHEDULE JOB. */ public void scheduleJob(View v) { JobInfo.Builder builder = new JobInfo.Builder(mJobId++, mServiceComponent); String delay = mDelayEditText.getText().toString(); if (!TextUtils.isEmpty(delay)) { builder.setMinimumLatency(Long.valueOf(delay) * 1000); } String deadline = mDeadlineEditText.getText().toString(); if (!TextUtils.isEmpty(deadline)) { builder.setOverrideDeadline(Long.valueOf(deadline) * 1000); } boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked(); boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked(); if (requiresUnmetered) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); } else if (requiresAnyConnectivity) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); } builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked()); builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked()); // Extras, work duration. PersistableBundle extras = new PersistableBundle(); String workDuration = mDurationTimeEditText.getText().toString(); if (TextUtils.isEmpty(workDuration)) { workDuration = "1"; } extras.putLong(WORK_DURATION_KEY, Long.valueOf(workDuration) * 1000); builder.setExtras(extras); // Schedule job Log.d(TAG, "Scheduling job"); JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); tm.schedule(builder.build()); } /** * Executed when user clicks on CANCEL ALL. */ public void cancelAllJobs(View v) { JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); tm.cancelAll(); Toast.makeText(MainActivity.this, R.string.all_jobs_cancelled, Toast.LENGTH_SHORT).show(); } /** * Executed when user clicks on FINISH LAST TASK. */ public void finishJob(View v) { JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); List<JobInfo> allPendingJobs = jobScheduler.getAllPendingJobs(); if (allPendingJobs.size() > 0) { // Finish the last one int jobId = allPendingJobs.get(0).getId(); jobScheduler.cancel(jobId); Toast.makeText( MainActivity.this, String.format(getString(R.string.cancelled_job), jobId), Toast.LENGTH_SHORT).show(); } else { Toast.makeText( MainActivity.this, getString(R.string.no_jobs_to_cancel), Toast.LENGTH_SHORT).show(); } } /** * A {@link Handler} allows you to send messages associated with a thread. A {@link Messenger} * uses this handler to communicate from {@link MyJobService}. It's also used to make * the start and stop views blink for a short period of time. */ private static class IncomingMessageHandler extends Handler { // Prevent possible leaks with a weak reference. private WeakReference<MainActivity> mActivity; IncomingMessageHandler(MainActivity activity) { super(/* default looper */); this.mActivity = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { MainActivity mainActivity = mActivity.get(); if (mainActivity == null) { // Activity is no longer available, exit. return; } View showStartView = mainActivity.findViewById(R.id.onstart_textview); View showStopView = mainActivity.findViewById(R.id.onstop_textview); Message m; switch (msg.what) { /* * Receives callback from the service when a job has landed * on the app. Turns on indicator and sends a message to turn it off after * a second. */ case MSG_COLOR_START: // Start received, turn on the indicator and show text. showStartView.setBackgroundColor(getColor(R.color.start_received)); updateParamsTextView(msg.obj, "started"); // Send message to turn it off after a second. m = Message.obtain(this, MSG_UNCOLOR_START); sendMessageDelayed(m, 1000L); break; /* * Receives callback from the service when a job that previously landed on the * app must stop executing. Turns on indicator and sends a message to turn it * off after two seconds. */ case MSG_COLOR_STOP: // Stop received, turn on the indicator and show text. showStopView.setBackgroundColor(getColor(R.color.stop_received)); updateParamsTextView(msg.obj, "stopped"); // Send message to turn it off after a second. m = obtainMessage(MSG_UNCOLOR_STOP); sendMessageDelayed(m, 2000L); break; case MSG_UNCOLOR_START: showStartView.setBackgroundColor(getColor(R.color.none_received)); updateParamsTextView(null, ""); break; case MSG_UNCOLOR_STOP: showStopView.setBackgroundColor(getColor(R.color.none_received)); updateParamsTextView(null, ""); break; } } private void updateParamsTextView(@Nullable Object jobId, String action) { TextView paramsTextView = (TextView) mActivity.get().findViewById(R.id.task_params); if (jobId == null) { paramsTextView.setText(""); return; } String jobIdText = String.valueOf(jobId); paramsTextView.setText(String.format("Job ID %s %s", jobIdText, action)); } private int getColor(@ColorRes int color) { return mActivity.get().getResources().getColor(color); } } }
对于有疑问说,使用Messenger没有AIDL方便,由于AIDL是IPC代理方式的,这个须要按照状况来决定,对于小型项目,不必使用IPC代理,但对于大项目最好使用IPC代理,由于IPC代理这种方式是面向接口的服务。框架
①Messenger和AIDL相比,均可以使用Parcelable传递复杂类型的数据,AIDL相对底层,灵活性比较好。异步
②Messenger底层封装自AIDLide
③AIDL和Messenger都是经过Binder机制通讯oop
④Messenger使用的是同一个线程的Handler和消息队列,所以没法处理多线程并发任务,而AIDL能够。post
④Messenger能够实如今无绑定服务的状况下和Service交互ui