1 题目要求
创建一个服务 QueryWeekdayService,该服务提供一个公共方法 QueryWeekday,输入参数日期(年、月、日),返回该日期是星期几。要求本应用程序和其它应用程序都能够绑定到该服务,并调用公共方法。
原创作品,转载请声明
2 实现思路
笔者上课的教材上面明确标注BindService只能进行进程内绑定,因此让笔者在实现题目需要的时候费了很多精力(辣鸡书,不看也罢 √)
回归正题,分析题目可知,需要通过服务去获取输入日期是星期几,所以一个简单的直觉就是使用BindService来进行通信,然而题目要求其他应用程序也要能使用该服务,所以这里引入一个新东西(反正书上没写)AIDL接口。
3 AIDL 接口
AIDL是Android Interface Definition Language的缩写,即Android接口定义语言。它是Android的进程间通信比较常用的一种方式。
通过使用AIDL接口可以轻松实现跨进程通信(IPC - Inter Process Communication),也就是说可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。
4 如何使用
4.1 新建AIDL文件
- 在包中,new—>AIDL—>AIDL file。
- 声明想要远程调用的接口
3. 下一步是关键,点击 Build–>Rebuild Project,从而将接口文件自动生成为java文件
4.2 写Service文件(这一步与本地Service有点不同)
-
声明并实现一个IBinder对象(这里与一般的bindService不同),这里就是实例化你刚刚定义的接口
private final IBinder mBinder = new IMyAidlInterface.Stub(){ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String remoteGetWeekday(String date) throws RemoteException { return getWeekday(date); //调用具体的业务 } };
-
绑定你的接口
@Override public IBinder onBind(Intent intent) { // return new MyBinder(); return mBinder; }
-
写具体的业务
public String getWeekday(String date){ String[] dates = date.split("-"); String[] weekdays = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六",}; Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR,Integer.parseInt(dates[0])); cal.set(Calendar.MONTH,Integer.parseInt(dates[1])-1); cal.set(Calendar.DATE,Integer.parseInt(dates[2])); int weekday = cal.get(Calendar.DAY_OF_WEEK)-1; return date+"的那天是"+weekdays[weekday]; }
4.3 在Manifests中声明你的服务
<service
android:name=".service.QueryWeekday"
android:process=":remote"
android:exported="true"
android:enabled="true">
</service>
4.4 新建一个App,用于验证
- 将AIDL接口文件放在新的App中,注意要先创建一个与原来AIDL接口所在的接口一样包名的包。
-
然后build—>rebuild project,生成对应的java文件
-
在Acitivity中调用服务,即new一个ServiceConnection对象(这里是new的是接口对象),然后在onStart中调用服务,注意这里需要setComponent,具体看代码和注释
private final ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { queryWeekday = IMyAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { } };
@Override protected void onStart() { super.onStart(); Intent serviceIntent = new Intent(); //这里的包名是原来服务所在的包的包名,cls是你在manifests文件中定义的服务的name serviceIntent.setComponent(new ComponentName("com.young.project02","com.young.project02.service.QueryWeekday")); bindService(serviceIntent,conn, BIND_AUTO_CREATE); boolean result = bindService(serviceIntent,conn, Context.BIND_AUTO_CREATE); Log.i("result",result+"" ); }
然后就是你的业务逻辑了,这里因人而异了
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button queryBtn = (Button)findViewById(R.id.queryBtn); EditText dateText = (EditText)findViewById(R.id.dateEditView); queryBtn.setOnClickListener(v -> { String date = dateText.getText().toString(); String weekday = null; try { weekday = queryWeekday.remoteGetWeekday(date); } catch (RemoteException e) { e.printStackTrace(); } Toast.makeText(this,weekday,Toast.LENGTH_LONG).show(); }); }
5 效果
从结果可以看到跨APP可以调用服务
6 源代码
https://github.com/GoatYoung/issue10A 给颗小星星⭐可否? 嘿嘿