-
- Services
-
- A service can essentially take two forms
-
- startService开启服务
- startService开启服务示例
- bindService开启服务
- bindService示例
- bindService示例2
- IntentService
- 混合方式开启服务
- 混合方式开启服务示例
- Services
- 代码下载
Services
A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
服务后台长时间运行,无界面,组件可以绑定一个服务与它交互
A service can essentially take two forms:
Started
A service is “started” when an application component (such as an activity) starts it by calling startService(). Once started, a service can run in the background indefinitely(无限期地), even if the component that started it is destroyed. Usually, a started service performs a single operation and does not return a result to the caller. For example, it might download or upload a file over the network. When the operation is done, the service should stop itself.
Bound
A service is “bound” when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.
- 服务通过startService开启,将一直在后台运行,服务一般不返回值,在后台完成任务,最好关闭服务
- 服务是“绑定”当一个应用程序组件绑定到它通过调用bindService(),绑定服务提供了一个客户机-服务器接口,允许组件与服务交互,多个组件可以绑定到服务,但是当他们解开,服务被摧毁。
Caution: A service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify otherwise). This means that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 playback or networking), you should create a new thread within the service to do that work. By using a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the application’s main thread can remain dedicated to user interaction with your activities.
警告:一个服务运行在主线程的托管进程(服务不创建自己的线程和不运行在一个单独的进程(除非您指定)。这意味着,如果你的服务要做任何CPU密集型工作或阻塞操作(如MP3播放或网络),您应该创建一个新线程内的服务工作。通过使用一个单独的线程,你会减少应用程序没有响应的风险(ANR)错误和应用程序的主线程可以继续致力于用户交互活动。
Service生命周期图
startService开启服务
startService开启服务示例
public class DemoService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
//必须要重写的方法
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
//开启服务
public void click1(View view) {
Intent intent = new Intent(this,DemoService.class);
startService(intent);
}
//关闭服务
public void click2(View view) {
Intent intent = new Intent(this,DemoService.class);
stopService(intent);
}
<manifest ... >
...
<application ... >
<service android:name=".DemoService" />
...
</application>
</manifest>
- onCreate–onStartCommand
- onCreate在在第一次创建时执行,多次开启服务,只会开启onStartCommand 方法
- 服务开启后,会长期执行,直到用户手工停止
bindService开启服务
目的是为了调用服务里的方法
//点击按钮 绑定服务 开启服务的第二种方式
public void click3(View view) {
Intent intent = new Intent(this,DemoService.class);
//连接到demoservice 这个服务
conn = new Myconn();
bindService(intent, conn,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
//当activity销毁时要解绑服务
unbindService(conn);
super.onDestroy();
}
//定义一个类来监视服务的状态
private class Myconn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
System.out.println("onServiceConnected");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
System.out.println("onServiceDisconnected");
}
}
- 第一次点击按钮时会执行服务的onCreate方法和onBind方法
- 当onBind方法返回为null时,onServerConnected方法是不执行的
- 第二次点击bind服务时,服务没有响应
- bind方式开启的服务,activity和service同生共死
- 服务不能多次解绑,多次解绑会有异常
- 通过bind方式开启服务,服务不能在设置里找到 相当于是一个隐形的服务
bindService示例
BanZhengService .java
public class BanZhengService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public void banZheng(int money) {
if(money>1000){
Toast.makeText(getApplicationContext(),"我是领导 把证给你办了",Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(),"就这点钱 还想办事...",Toast.LENGTH_LONG).show();
}
}
//定义中间人ibinder
public class MyBinder extends Binder {
public void callbanZheng(int money){
//调用办证的方法
banZheng(money);
}
}
}
配置service
<service android:name=".BanZhengService"></service>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private MyConn conn;
private BanZhengService.MyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent= new Intent(this,BanZhengService.class);
conn = new MyConn();
bindService(intent,conn,BIND_AUTO_CREATE);
}
public void click(View view) {
myBinder.callbanZheng(100000);
}
@Override
protected void onDestroy() {
//解绑服务
unbindService(conn);
super.onDestroy();
}
//监视服务的状态
public class MyConn implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myBinder = (BanZhengService.MyBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
}
在BanZhengService里定义中间人MyBinder,定义一个方法调用service里的方法
bindService示例2
DemoService.java
public class DemoService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public void banZheng(int money) {
if (money > 1000) {
Toast.makeText(getApplicationContext(), "我是领导 把证给你办了", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "就这点钱 还想办事...", Toast.LENGTH_LONG).show();
}
}
public void playMajing() {
System.out.println("陪领导打麻将");
}
public void 洗桑拿() {
System.out.println("陪领导洗桑拿");
}
//定义中间人ibinder
public class MyBinder extends Binder implements Iservice {
public void callbanZheng(int money) {
//调用办证的方法
banZheng(money);
}
public void callPlayMajing() {
playMajing();
}
public void callXiSanNa() {
洗桑拿();
}
}
}
Iservice.java
public interface Iservice {
//把领导想暴露的方法
public void callbanZheng(int money);
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private MyConn conn;
private Iservice myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, DemoService.class);
conn = new MyConn();
bindService(intent, conn, BIND_AUTO_CREATE);
}
public void click(View view) {
myBinder.callbanZheng(100000);
//只有领导才能调桑拿
//myBinder.callPlayMajing();
// myBinder.callXiSanNa();
}
@Override
protected void onDestroy() {
//解绑服务
unbindService(conn);
super.onDestroy();
}
//监视服务的状态
private class MyConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
myBinder = (Iservice) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
}
IntentService
服务中的代码都是默认运行在主线程当中的,如果直接在服务里去处理一些耗时的逻辑,就很容易出现ANR(Application Not Responding)的情况。
所以这个时候就需要用到Android多线程编程的技术了,我们应该在服务的每个具体的方法里开启一个子线程,然后在这里去处理那些耗时的逻辑。因此,一个比较标准的服务就可以写成如下形式:
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//开启一个子线程
new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
但是,这种服务一旦启动之后,就会一直处于运行状态,必须调用stopService()或者stopSelf()方法才能让服务停止下来。所以,如果想要实现让一个服务在执行完毕后自动停止的功能,就可以这样写:
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑
stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}
}
虽说这种写法并不复杂,但是总会有一些程序员忘记开启线程,或者忘记调用stopSelf()方法。为了可以简单地创建一个异步的、会自动停止的服务,Android专门提供了一个IntentService类,这个类就很好地解决了前面所提到的两种尴尬,下面我们就来看一下它的用法。
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
// 调用父类的有参构造函数
}
/* public MyIntentService(String name) {
super(name);
}*/
@Override
protected void onHandleIntent(Intent intent) {
// 打印当前线程的id
Log.d("MyIntentService", "Thread id is " +
Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}
开启MyIntentService
public void click5(View view) {
// 打印主线程的id
Log.d("MainActivity", "Thread id is " + Thread.currentThread(). getId());
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);
}
可以看到,不仅MyIntentService和MainActivity所在的线程id不一样,而且onDestroy()方法也得到了执行,说明MyIntentService在运行完毕后确实自动停止了。这就是集开启线程和自动停止于一身IntentService.
混合方式开启服务
我们知道,通过startservice开启服务,服务会一直运行下去,除非自己stopservice;而bindservice开启服务,可以调用服务里的方法,但服务的生命周期和activity是绑定的,同生共死;可是我想服务长期运行,又想调用服务里的方法,这就需要混合方式开启服务
开启流程
- 先调用startService方法开启服务,让服务长期运行
- 调用bindService方法开启服务 ,去获取中间人对象
关闭流程
- unbindService 解绑服务
- stopService 关闭服务
混合方式开启服务示例
MainActivity.java
public class MainActivity extends AppCompatActivity {
private IService iService;
private Myconn conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//混合开启服务
//先调用startService 目的是可以保证服务在后台长期运行
Intent intent = new Intent(this,MusicService.class);
startService(intent);
//调用bindservice 目的是获取我们定义的中jian人对象 就可以间接的调用服务
conn = new Myconn();
bindService(intent, conn,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
//当activity销毁的时候 解绑服务 不报红色日志
unbindService(conn);
super.onDestroy();
}
public void click1(View view) {
//播放
iService.callplayMusic();
}
public void click2(View view) {
//暂停
iService.callpauseMusic();
}
public void click3(View view) {
//继续播放
iService.callreplayMusic();
}
private class Myconn implements ServiceConnection {
//当服务连接成功
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//获取我们定义的中间人Ibinder
iService = (IService) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
}
}
MusicService.java
public class MusicService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
//把我们定义的中间人返回
return new MyBinder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
/**
* 开启一个线程,验证后台服务是否一直运行
*/
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//要做的事情
Log.d("MusicService", new Date().toString());
//每隔十秒执行一次
handler.postDelayed(this, 10000);
}
};
//两秒后执行
handler.postDelayed(runnable, 2000);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
public void playMusic() {
Toast.makeText(getApplication(), "音乐播放了", Toast.LENGTH_SHORT).show();
System.out.println("音乐播放了");
}
public void pauseMusic() {
Toast.makeText(getApplicationContext(), "音乐暂停了", Toast.LENGTH_SHORT).show();
System.out.println("音乐暂停了");
}
public void replayMusic() {
Toast.makeText(getApplicationContext(), "音乐继续播放了", Toast.LENGTH_SHORT).show();
System.out.println("音乐继续播放了");
}
//定义service和activity的中间人对象(Ibinder)
private class MyBinder extends Binder implements IService {
@Override
public void callplayMusic() {
playMusic();
}
@Override
public void callpauseMusic() {
pauseMusic();
}
@Override
public void callreplayMusic() {
replayMusic();
}
}
}
IService.java
public interface IService {
//在接口里暴露方法
public void callplayMusic();
public void callpauseMusic();
public void callreplayMusic();
}
这样就可以调用service里的方法了
即使把应用程序关闭后,也会定时打印出时间,说明service还在后台运行,只要不把进程关闭,service就会一直运行下去