案例一:监听手机通话状态(日志输出)【启动方式】
案例二:Activity调用Service换歌方法进行换歌【绑定方式】
代码补充
案例三:Find Name【绑定方式】
案例一:监听手机通话状态(日志输出)
1. 创建并在功能清单中注册服务:MobileStateService
<service android:name=".MobileStateService" />
2. 启动服务 (MainActivity中启动)
// 启动服务 Intent intent = new Intent(this, MobileStateService.class); startService(intent); // 停止服务 // stopService(intent);
3. MobileStateService。将onBind方法中的异常删掉,返回null。(否则运行时直接退出)
@Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. // throw new UnsupportedOperationException("Not yet implemented"); // 改为返回null return null; }
4. MobileStateService。重写 onCreate() 和 onDestroy() 方法
@Override public void onCreate() { super.onCreate(); Log.v(TAG, "创建服务."); } @Override public void onDestroy() { super.onDestroy(); Log.v(TAG, "销毁服务."); }
5. 监听手机来电状态,需要在功能清单中授予读取手机状态权限。
<!-- 读取手机状态权限 <uses-permission android:name="android.permission.read_phone_state" /> <uses-permission android:name="ANDROID.PERMISSION.READ_PHONE_STATE" /> 这两种写法,都不会报错。但是,在按住ctrl键并点击的时候,弹不出来。 而下面这种正确写法,按住ctrl键并点击,可以弹出来。 因此可用这种方法检验写的是否正确。 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
6. MobileStateService。通过电话管理器来监听手机状态。
@Override public void onCreate() { super.onCreate(); Log.v(TAG, "创建服务."); // 获得电话管理器(电话管理的服务) // telephony:电话(学);电话制造 TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); // 电话管理器监听手机状态 // LISTEN_CALL_STATE 三个状态:响铃状态,接通状态,空闲状态 tm.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE); }
7. MobileStateService。创建手机状态监听器类:MyPhoneStateListener。
private class MyPhoneStateListener extends PhoneStateListener { /** * @param state 状态 * @param incomingNumber 来电号码 */ @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { // idle:闲置的 case TelephonyManager.CALL_STATE_IDLE: Log.v(TAG, "空闲状态"); break; // ring:响铃 case TelephonyManager.CALL_STATE_RINGING: Log.v(TAG, "响铃状态:" + incomingNumber); if ("13888888888".equals(incomingNumber)) { // 日志输出,并不是真的挂断 Log.v(TAG, "挂断情敌号码:" + incomingNumber); } break; // offhook:摘机 case TelephonyManager.CALL_STATE_OFFHOOK: Log.v(TAG, "接听状态"); break; } } }
效果如下:
![](http://dl2.iteye.com/upload/attachment/0110/6261/923fba44-9830-3300-8d3c-1e6c8648c8a9.png)
案例二:Activity调用Service换歌方法进行换歌【绑定方式】
主界面如下:
![](http://dl2.iteye.com/upload/attachment/0110/6287/cd04b970-41c8-30c3-b91e-77b312136618.png)
当点击“Play Music”的时候,跳转到 SingerActivity 页面。该页面有3个按钮。
![](http://dl2.iteye.com/upload/attachment/0110/6289/ece007f9-ed2f-306c-bc07-fea1d039ab84.png)
当点击“绑定服务”按钮之后,再点击“换歌”按钮,Toast输出:“更改歌曲:七里香”。
![](http://dl2.iteye.com/upload/attachment/0110/6291/88d315ea-d31f-35d3-8963-daf1dbaf9e30.png)
当点击“解绑服务”按钮之后,再点击“换歌”按钮,Toast输出:“未绑定服务”。
![](http://dl2.iteye.com/upload/attachment/0110/6293/0012f4b0-559e-39b0-bf33-e3f4630afe0e.png)
1. activity_main.xml。写 Play Music 按钮。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="playMusic" android:text="@string/play_music" /> </RelativeLayout>
2. MainActivity。写按钮点击事件。
public void playMusic(View view) { // 跳转到 播放歌 的活动 startActivity(new Intent(this, SingerActivity.class)); }
3. 创建 SingerActivity。并在功能清单中写返回主页面的按钮。
<activity android:name=".SingerActivity" android:label="@string/title_activity_singer" android:parentActivityName=".MainActivity" />
4. activity_singer.xml。写3个按钮。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.android.localservice.SingerActivity"> <Button android:id="@+id/btnBindService" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="@string/btn_bind_service" /> <Button android:id="@+id/btnUnbindService" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/btnBindService" android:onClick="onClick" android:text="@string/btn_unbind_service" /> <Button android:id="@+id/btnChangeSong" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/btnUnbindService" android:onClick="onClick" android:text="@string/btn_change_song" /> </RelativeLayout>
5. SingerActivity。写3个按钮的点击事件。
public void onClick(View view) { switch (view.getId()) { case R.id.btnBindService: break; case R.id.btnUnbindService: break; case R.id.btnChangeSong: break; } }
6. 创建并注册 SingerService。
7. SingerService。将onBind方法中的异常删掉,返回null。(否则运行时直接退出)
@Override public IBinder onBind(Intent intent) { Log.v(TAG, "服务被成功绑定了"); return null; }
8. SingerService。重写 onCreate 和 onDestroy 方法
@Override public void onCreate() { super.onCreate(); Log.v(TAG, "创建服务,开始唱歌."); } @Override public void onDestroy() { super.onDestroy(); Log.v(TAG, "销毁服务,停止唱歌."); }
9. SingerService。创建 换歌的方法:changeSong。
public void changeSong(String songName) { Log.v(TAG, "更改歌曲:" + songName); Toast.makeText(getApplicationContext(), "更改歌曲:" + songName, Toast.LENGTH_LONG).show(); }
10. SingerActivity。“绑定服务”按钮事件。
// 是否绑定服务(默认值:false) private boolean isBind; public void onClick(View view) { // 创建 激活服务的意图 Intent intent = new Intent(this, SingerService.class); switch (view.getId()) { case R.id.btnBindService: // 绑定服务 // 如果没有绑定服务 if (!isBind) { // bindService:绑定服务 // 参数一:intent 激活服务的意图 // 参数二:conn 代理人中间对象,用来与服务建立联系(不能为空) // 参数三:BIND_AUTO_CREATE 在绑定服务时,若服务不存在则自动创建 bindService(intent, conn, BIND_AUTO_CREATE); // 设置为:已绑定服务 isBind = true; } break; case R.id.btnUnbindService: break; case R.id.btnChangeSong: break; } }
11. SingerActivity。创建 服务连接 的方法。
/** * 创建 服务连接 的方法 */ private ServiceConnection conn = new ServiceConnection() { /** * 在服务被成功绑定时调用 * * @param name * @param service */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.v(TAG, "歌手返回代理人对象"); } /** * 在服务失去绑定时调用(只有程序异常终止) * @param name */ @Override public void onServiceDisconnected(ComponentName name) { } };
12. 创建接口类 ISingerService,暴露出来,供 SingerActivity 中 中间代理人的实例 调用 换歌 的方法。
package com.android.localservice; /** * 接口类:用于 Binder中的方法 * * 暴露出来,供 SingerActivity 中 中间代理人的实例 调用 换歌 的方法, * 这样,因为 中间代理人 MyBinder 实现了该接口, * 因此, SingerActivity 中 中间代理人的实例 调用接口中的 换歌 方法, * 相当于调用了 私有的 MyBinder 中的 换歌 的方法。 */ public interface ISingerService { void callChangeSong(String songName); }
13. SingerService。创建中间代理人、中间代理人的实例,并在onBind方法中返回该实例。
/** * 当Service被绑定时,系统会调用onBind()函数, * 通过该函数的返回值, 将Service对象返回给调用者。 * * 注意:onBind()的返回值必须符合IBinder接口, * IBinder接口是用于进程内部和进程间过程调用的轻量级接口, * 定义了与远程对象交互的抽象协议,使用时需要继承Binder类。 * @param intent * @return */ @Override public IBinder onBind(Intent intent) { Log.v(TAG, "服务被成功绑定了"); // 在 onBind() 方法中, 返回 中间代理人的实例 return binder; } // 创建 中间代理人的实例 private IBinder binder = new MyBinder(); /** * 创建 中间代理人(私有类) */ private final class MyBinder extends Binder implements ISingerService { // 重写 ISingerService 接口 中的 换歌 方法 @Override public void callChangeSong(String songName) { // 内部类 MyBinder 中,可以调用外部类 SingerService 中的 换歌 的方法 // 这样,通过在 SingerActivity 中 中间代理人的实例 调用接口中的 换歌 方法, // 就相当于 调用了 SingerService 类 中的 换歌 的方法。 changeSong(songName); } }
14. SingerService。解绑的方法:onUnbind
/** * 解绑 * * 如果返回为 true,则代表在新调用者绑定服务时,onRebind()函数才被调用 * * @param intent * @return */ @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "取消本地绑定"); return false; }
15. SingerActivity。onBind方法中将中间代理人的实例,返回至SingerActivity中的“服务连接”的方法中。
private ISingerService singerService; /** * 创建 服务连接 的方法 */ private ServiceConnection conn = new ServiceConnection() { /** * 在服务被成功绑定时调用 * * @param name * @param service */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.v(TAG, "歌手返回代理人对象"); // service 是 MyBinder 类的实例,是 IBinder接口类型。 // 因为 MyBinder 类 实现了 ISingerService 接口, // 因此,service 也可由 IBinder接口类型 强转为 SingerService 接口类型。 singerService = (ISingerService) service; } /** * 在服务失去绑定时调用(只有程序异常终止) * @param name */ @Override public void onServiceDisconnected(ComponentName name) { singerService = null; } };
补充:SingerService中,返回的中间代理人的实例 binder,就是 SingerActivity 的“服务连接”方法中的 service,二者指向同样的地址。
@Override public IBinder onBind(Intent intent) { Log.v(TAG, "服务被成功绑定了"); /* Test 结果: 此处的 binder 与 SingerActivity 中的 onServiceConnected 中的 service 指向同样的地址。 二者是一样的。 */ // Test:打印 binder.toString() Log.v(TAG, "...." + binder.toString()); // 在 onBind() 方法中, 返回 中间代理人的实例 return binder; }
@Override public void onServiceConnected(ComponentName name, IBinder service) { Log.v(TAG, "歌手返回代理人对象"); // 打印 service.toString() Log.v(TAG, "...." + service.toString()); }
![](http://dl2.iteye.com/upload/attachment/0110/6313/9724b10c-c829-31d4-bdbd-60e0674cb2fb.png)
16. SingerActivity。“解绑服务”按钮事件。
case R.id.btnUnbindService: // 解绑 // 如果已绑定服务 if (isBind) { // 设置为:未绑定服务 isBind = false; // 解绑 unbindService(conn); singerService = null; } break;
17. SingerActivity。“换歌”按钮事件。
case R.id.btnChangeSong: // 换歌 if (singerService == null) { Toast.makeText(this, "未绑定服务", Toast.LENGTH_LONG).show(); } else { singerService.callChangeSong("七里香"); } break;
补充:不能在 Activity中直接调用 Service 中的方法:
SingerService service = new SingerService(); service.changeSong("七里香");
由于系统框架在创建服务时会创建与之对应的上下文,而下面的代码是直接 new 对象,直接 new 出来后,与上下文就没有关系了,所以抛 空指针异常。
整个过程的示意图如下:
![](http://dl2.iteye.com/upload/attachment/0110/6315/4a8fa7e5-02ca-3eb2-8d6c-8e4a46c8d0d8.png)
Activity与服务进行通信,开发人员通常把通信方法定义在接口里,然后让Ibinder对象实现该接口,而Activity通过该接口引用服务onBind()方法返回的Ibinder对象,然后调用Ibinder对象里自定义的通信方法。
代码补充
项目目录结构如下:
![](http://dl2.iteye.com/upload/attachment/0110/6317/95d8523a-0bce-3f1b-abc0-52b99e2219f6.png)
1. strings.xml
<resources> <string name="app_name">LocalService</string> <string name="hello_world">Hello world!</string> <string name="action_settings">Settings</string> <string name="play_music">Play Music</string> <string name="btn_change_song">换歌</string> <string name="btn_bind_service">绑定服务</string> <string name="btn_unbind_service">解绑服务</string> <string name="title_activity_singer">SingerActivity</string> </resources>
2. MainActivity
package com.android.localservice; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /** * 按钮点击事件 * @param view */ public void playMusic(View view) { // 跳转到 播放歌 的活动 startActivity(new Intent(this, SingerActivity.class)); } // ------------------------------------------------------------------ @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
3. SingerActivity
package com.android.localservice; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; /** * 创建 SingerActivity */ public class SingerActivity extends Activity { private static final String TAG = "LocalService"; private ISingerService singerService; // 是否绑定服务(默认值:false) private boolean isBind; /** * 创建 服务连接 的方法 */ private ServiceConnection conn = new ServiceConnection() { /** * 在服务被成功绑定时调用 * * @param name * @param service */ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.v(TAG, "歌手返回代理人对象"); // 打印 service.toString() Log.v(TAG, "...." + service.toString()); // service 是 MyBinder 类的实例,是 IBinder接口类型。 // 因为 MyBinder 类 实现了 ISingerService 接口, // 因此,service 也可由 IBinder接口类型 强转为 SingerService 接口类型。 singerService = (ISingerService) service; } /** * 在服务失去绑定时调用(只有程序异常终止) * @param name */ @Override public void onServiceDisconnected(ComponentName name) { singerService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_singer); } /** * 写 3个按钮的点击事件 * * @param view */ public void onClick(View view) { // 创建 激活服务的意图 Intent intent = new Intent(this, SingerService.class); switch (view.getId()) { case R.id.btnBindService: // 绑定服务 // 如果没有绑定服务 if (!isBind) { // bindService:绑定服务 // 参数一:intent 激活服务的意图 // 参数二:conn 代理人中间对象,用来与服务建立联系(不能为空) // 参数三:BIND_AUTO_CREATE 在绑定服务时,若服务不存在则自动创建 bindService(intent, conn, BIND_AUTO_CREATE); // 设置为:已绑定服务 isBind = true; } break; case R.id.btnUnbindService: // 解绑 // 如果已绑定服务 if (isBind) { // 设置为:未绑定服务 isBind = false; // 解绑 unbindService(conn); singerService = null; } break; case R.id.btnChangeSong: if (singerService == null) { Toast.makeText(this, "未绑定服务", Toast.LENGTH_LONG).show(); } else { singerService.callChangeSong("月亮之上"); } break; } } // -------------------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_singer, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
4. SingerService
package com.android.localservice; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; import android.widget.Toast; /** * 创建服务:SingerService */ public class SingerService extends Service { private static final String TAG = "LocalService"; public SingerService() { } /** * 创建 onCreate 方法 */ @Override public void onCreate() { super.onCreate(); Log.v(TAG, "创建服务,开始唱歌."); } /** * 创建 onDestroy 方法 */ @Override public void onDestroy() { super.onDestroy(); Log.v(TAG, "销毁服务,停止唱歌."); } /** * 换歌 的方法 * @param songName */ public void changeSong(String songName) { Log.v(TAG, "更改歌曲:" + songName); Toast.makeText(getApplicationContext(), "更改歌曲:" + songName, Toast.LENGTH_LONG).show(); } /** * 当Service被绑定时,系统会调用onBind()函数, * 通过该函数的返回值, 将Service对象返回给调用者。 * * 注意:onBind()的返回值必须符合IBinder接口, * IBinder接口是用于进程内部和进程间过程调用的轻量级接口, * 定义了与远程对象交互的抽象协议,使用时需要继承Binder类。 * * @param intent * @return */ @Override public IBinder onBind(Intent intent) { Log.v(TAG, "服务被成功绑定了"); /* Test 结果: 此处的 binder 与 SingerActivity 中的 onServiceConnected 中的 service 指向同样的地址。 二者是一样的。 */ // Test:打印 binder.toString() Log.v(TAG, "...." + binder.toString()); // 在 onBind() 方法中, 返回 中间代理人的实例 return binder; } // 创建 中间代理人的实例 private IBinder binder = new MyBinder(); /** * 创建 中间代理人(私有类) */ private final class MyBinder extends Binder implements ISingerService { // 重写 ISingerService 接口 中的 换歌 方法 @Override public void callChangeSong(String songName) { // 内部类 MyBinder 中,可以调用外部类 SingerService 中的 换歌 的方法 // 这样,通过在 SingerActivity 中 中间代理人的实例 调用接口中的 换歌 方法, // 就相当于 调用了 SingerService 类 中的 换歌 的方法。 changeSong(songName); } } /** * 解绑 * * 如果返回为 true,则代表在新调用者绑定服务时,onRebind()函数才被调用 * * @param intent * @return */ @Override public boolean onUnbind(Intent intent) { Log.i(TAG, "取消本地绑定"); return false; } }
5. ISingerService
package com.android.localservice; /** * 接口类:用于 Binder中的方法 * * 暴露出来,供 SingerActivity 中 中间代理人的实例 调用 换歌 的方法, * 这样,因为 中间代理人 MyBinder 实现了该接口, * 因此, SingerActivity 中 中间代理人的实例 调用接口中的 换歌 方法, * 相当于调用了 私有的 MyBinder 中的 换歌 的方法。 */ public interface ISingerService { void callChangeSong(String songName); }
案例三:Find Name【绑定方式】
主界面如下:
![](http://dl2.iteye.com/upload/attachment/0110/6319/ed055e1f-a2af-312a-a043-55593d6499e8.png)
当点击“Find Name”按钮后,下面的TextView被“Android L Google / 1”代替,数字按每秒加1的速率在变,但只有当点击“Find Name”按钮时,才可以看到数字变化了。
![](http://dl2.iteye.com/upload/attachment/0110/6321/cedc75bf-6e2b-3a3e-a3c4-248f69ac45a6.png)
![](http://dl2.iteye.com/upload/attachment/0110/6323/06075bd9-aaa5-3842-a525-661a754160b5.png)
1. strings.xml
<resources> <string name="app_name">ServiceDemo</string> <string name="hello_world">Hello world!</string> <string name="action_settings">Settings</string> <string name="btn_find_name">Find Name</string> <string name="title_activity_service_demo">ServiceDemo</string> </resources>
2. activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <Button android:id="@+id/btnFindName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="@string/btn_find_name" /> <TextView android:id="@+id/tvResult" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/btnFindName" android:text="@string/hello_world" /> </RelativeLayout>
3. MainActivity
package com.android.servicedemo; import android.app.Activity; import android.content.ComponentName; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.TextView; public class MainActivity extends Activity { // 3.1 声明变量(文本) private TextView tvResult; // 16. private INameService nameService; /** * 15. */ private ServiceConnection conn = new ServiceConnection() { /** * 在服务被成功绑定时调用 * @param name * @param service */ @Override public void onServiceConnected(ComponentName name, IBinder service) { // 17. 对于本地服务,获取的实例 service 和 // 服务 onBind() 返回的实例 binder 是同一个 nameService = (INameService) service; } /** * 服务失去绑定时调用(只有程序异常终止) * @param name */ @Override public void onServiceDisconnected(ComponentName name) { // 18. nameService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 3.2 获得 文本 tvResult = (TextView) findViewById(R.id.tvResult); // 14. 绑定并启动服务 (写在 onCreate里面,在创建活动的时候,就绑定并启动服务了) bindService(new Intent(this, NameService.class), conn, BIND_AUTO_CREATE); /* 当 Activity(调用者) 退出,Service(服务) 也随着调用者退出,就销毁了。 当下次调用者进入,服务也随着创建,再次绑定并启动。 */ } /** * 2. 按钮事件点击事件 * * @param view */ public void onClick(View view) { // 19. 格式化字符串 String text = String.format("%s / %d", nameService.getName("Google"), nameService.getCount()); // 20. TextView 设置字符串,进行显示 tvResult.setText(text); } // ------------------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
4. NameService
package com.android.servicedemo; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; import android.util.Log; /* * 小结:何时使用 启动方式,何时使用 绑定方式?: * * 如果要用服务中自定义的方法,必须用 binder方法。 * 如果启动后,就不管了,就用 onStart方法 */ /** * 4. 创建 服务 NameService */ public class NameService extends Service { private static final String TAG = "MainActivity"; // 8.1 退出的条件 (默认为 false) private boolean exit; // 8.2 private int count; public NameService() { } /** * 5.1 */ @Override public void onCreate() { super.onCreate(); // 5.1.1 Log.v(TAG, "onCreate..."); // 8.3 Service 中耗时的操作应使用线程处理 new Thread() { @Override public void run() { /* 如果把 while 直接写入 onCreate, 则 onCreate 一直要做事情,线程可能死掉。 因此,写入一个新的线程中。 */ while (!exit) { try { // 线程休眠1秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 每次休眠一秒,count +1 count++; } } }.start(); } /** * 5.2 */ @Override public void onDestroy() { super.onDestroy(); // 5.2.1 Log.v(TAG, "onDestroy..."); } /** * 7. 自定义的方法 * <p/> * MainActivity中并不能调用该方法,因此必须通过 binder来操作 */ public String getName(String name) { return "Android L " + name; } @Override public IBinder onBind(Intent intent) { // 6. Log.v(TAG, "onBind..."); // 10.2 return binder; } // 10.1 // binder实例是 IBinder 类型,是 NameBinder的实例 // private Binder binder = new NameBinder(); 也可 // private NameBinder binder = new NameBinder(); 也可 // 即:既可以是 NameBinder类型(儿子),也可以是 Binder类型(爸爸), // 还可以是 IBinder类型(爷爷),一般写成 接口类型。 private IBinder binder = new NameBinder(); /** * 9. */ private final class NameBinder extends Binder implements INameService { /** * 12. * @return */ public int getCount() { // 内部类(NameBinder)可直接访问外部类(NameService)的成员变量 count return count; } /** * 13. * * @param name * @return */ @Override public String getName(String name) { // 内部类(NameBinder)访问外部类(NameService)的成员方法 // 若方法名相同时,必须指定所有者(NameService.this.) // --- 此处,内部类的方法名与外部类的方法名相同。 // 若方法名不同时,无需指定所有者(也可指定) return NameService.this.getName(name); } } }
5. INameService
package com.android.servicedemo; /** * 11. 接口:方便于调用者(Activity)访问 Binder 子类中的方法 */ public interface INameService { // 接口中的方法都是 public static的,因此前面可以不写。 int getCount(); String getName(String name); }