服务(Service)

服务(Service)是Android系统中的四大组件之一,与Activity不同,它是不能与用户交互的。它是一种长生命周期、没有可视化界面、运行于后台的服务程序。比如我们播放音乐的时候,有可能想干其他事情,当退出播放音乐的应用,如果不用Service,我们就听不到歌;又比如一个应用的数据是通过网络获取的,不同时间(一段时间)的数据是不同的,这时候可以用Service在后台定时更新,而不用在打开应用的时候去获取。

1.本地服务

本地服务(Local Service)用于应用程序内部,可以实现应用程序的一些耗时任务,比如查询升级信息、网络传输,或者需要在后台执行,比如播放音乐并不占用应用程序的线程,而是在后台单开线程执行,从而使用户体验比较好。

1.2两种启动方式

Service有两种启动方式:Context.bindService()和Context.startService()。这两种方式对Service生命周期的影响是不同的。

1.通过Context.bindService(Intent intent,ServiceConnection conn,int flags)启动

(1)绑定时,bindService→onCreate()→onBind();绑定Service需要3个参数。

①intent:Intent对象,需要定义执行服务类。

②conn:ServiceConnection接口对象,创建该对象要实现它的onServiceConnected()和onServiceDisconnected()来判断是连接成功还是断开连接。

onServiceConnected(ComponentName name,IBinder service):系统调用该函数来传递由service的onBind()方法返回的IBinder。

onServiceDisconnected(ComponentName name):如果对service的连接意外丢失,比如当service奔溃或被杀死时,系统就会调用该函数。

bindService方法执行之后会自动调用ServiceConnection接口里的onServiceConnected方法;如果执行unbindService方法,则不会自动调用ServiceConnection接口里的onServiceDisconnected方法。因为ServiceConnection接口的onServiceDisconnected方法只会在Service被停止或者被系统杀死后调用,也就是说,执行unbindService只是告诉系统已经和这个服务没有关系了。在内存不足的时候,系统可以优先杀死这个服务。

这里需要注意一点的是,Service和需要绑定的Activity需要放在同一个包内,否则将无法调用ServiceConnection接口中的上述方法。

③flags:创建Service模式,一共有以下三种模式。

  • Service.BIND_AUTO_CREATE:指定绑定的时候自动创建Service,这是最常使用的模式。
  • Service.BIND_DEBUG_UNBIND:测试绑定的时候创建创建Service,这里进行调试所用的模式。
  • Service.BIND_NOT_FOREGROUND:不在前台进行绑定时创建Service。(例如后台播放音乐)

(2)解绑定时,unbindService→onUnbind()→onDestroy()。

此时如果调用者(如Activity)直接退出,Service由于与调用者绑定在一起,就会随着调用者一同停止。

用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。此时如果调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,多次调用Context.bindService()方法并不会导致多次创建服务及绑定(也就是说,onCreate()和onBind()方法并不会被多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用Context.unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()和onDestroy()方法。

下面以播放一首歌为例,新建一个工程项目,

音乐类(Music.java)的代码如下。

package com.example.demo_test_for_service_music;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;

import androidx.annotation.Nullable;

public class Music extends Service {
    private MediaPlayer mediaPlayer;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        this.mediaPlayer = MediaPlayer.create(this,R.raw.liekkas);
        this.mediaPlayer.start();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        this.mediaPlayer.stop();
    }
}

Music类继承自Service,它是一个服务,在创建的时候开始播放一首歌,在销毁的时候停止播放。在AndroidManifest.xml中进行配置并声明Action,配置文件如下。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.demo_test_for_service_music">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".Music">
            <intent-filter>
                <action android:name="com.example.demo_test_for_service_music.Music"/>
            </intent-filter>
        </service>
    </application>

</manifest>

播放类代码如下。

package com.example.demo_test_for_service_music;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }
    private  void initView(){
        Button playButton = findViewById(R.id.start);
        Button stopButton = findViewById(R.id.stop);
    }
    private View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.start:
                    bindService(new Intent("com.example.demo_test_for_service_music.Music"),null, Service.BIND_AUTO_CREATE);
                    break;
                case R.id.stop:
                    unbindService(null);
                    default:
                        break;
            }
        }
    };

}

当点击播放时进行播放,当点击停止时音乐停止。当播放的时候退出程序,音乐也随之停止了。这就是用绑定方法启动服务产生的效果。有时候我们的需求并非这么简单,比如我们希望在播放音乐的时候,可以干其他事情,退出音乐播放界面后还要求音乐还能够继续在后台播放。第二种启动方式将有助于解决这一问题。

2.通过Context.startService(Intent intent)启动

(1)启动时,startService→onCreate()→onStart()

(2)停止时,stopService→onDestroy()

此时如果调用者(Activity)直接退出而没有停止Service,则Service会一直在后台运行。Context.startService() 方法启动服务,在Service未被创建时,系统会先调用Service的onCreate()方法,接着调用onStart()方法。如果调用Context.startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用Context.startService()启动的服务,只能调用Context.stopService()方法结束,服务结束时会调用onDestroy()方法。

在上一个例子中,如果退出程序后还能够播放音乐,我们只需改变它的启动方式即可,代码如下。

package com.example.demo_test_for_service_music;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }
    private  void initView(){
        Button playButton = findViewById(R.id.start);
        Button stopButton = findViewById(R.id.stop);
    }
    private View.OnClickListener clickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.start:
                    startService(new Intent("com.example.demo_test_for_service_music.Music"));
                    break;
                case R.id.stop:
                    stopService(new Intent("com.example.demo_test_for_service_music.Music"));
                    default:
                        break;
            }
        }
    };

}

1.2生命周期

Service生命周期一般有两种运行模式。

(1)在程序没有停止Service或者Service自己停止的情况下,Service将一直在后台运行。

在该模式下,Service通过Context.startService()方法开始,并通过Context.stopService()方法停止。当然,它也可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自身。stopService()方法只须调用一次便可停止服务。

(2)Service可以通过接口被外部程序调用。外部程序建立一个到Service的连接,并通过这个连接来操作Service。建立连接开始于Context.bindService(),结束于Context.unbindService()。多个客户端可以绑定到同一个Service。如果Service没有启动,可以通过Context.bindService()启动它。

这两种模式并不是完全分离,可以被绑定到一个通过Context.startService()启动的服务上。比如一个Intent想要播放音乐,就通过Context.startService()方法启动在后台播放音乐的Service。如果用户想要操作播放器或者获取当前正在播放的音乐的信息,一个新的Activity就会通过Context.bindService()建立一个到此Service的连接。举例如下。

//每一次进入该界面,都要绑定这个服务,这样才能查看在该服务器中所播放的音乐的信息
//而多次调用startService方法并不会每次都创建一个新的服务实例
bindService(new Intent(this,MusicService.class),conn,Context.BIND_AUTO_CREATE);
startService(new Intent(this,MusicService.class));
//像Activity一样,Service也有可以监视生命周期状态的方法,如下所示。
void onCreate()
void onStart(Intent intent)//由Context.startService()启动的服务所具有的方法
void onBind()//由Context.bindService()启动的服务所具有的方法
void onUnBind()//由Context.bindService()启动的服务所具有的方法
void onReBind()//由Context.bindService()启动的服务所具有的方法
void onDestroy

通过实现这几个方法,我们看一下Service的生命周期。

1.整个生命周期

Service的生命周期从onCreate()开始,到onDestroy()结束,跟Activity很类似。Service生命周期在onCreate()中执行初始化操作,在onDestroy()中释放所有用到的资源。如后台播放音乐可以在onCreate()创建一个播放音乐的线程,在onDestroy中销毁这个线程。

2.活动生命周期

Service的活动生命周期开始于onStart(),或者开始于onBind()方法。在音乐播放器中,使用Context.startService()方法启动,音乐服务会通过Intent来查看要播放哪首歌曲并开始播放。注意:onCreate()和onDestroy()用于所有通过Context.startService()或者Context.bindService()启动的Service,而onStart()只用于通过Context.startService() 开始的Service,onBind()则用于通过Context.bindService()启动的Service。

绑定的Service能触发以下的方法。

IBinder onBind(Intent intent)

boolean onUnbind(Intent intent)

void onRebind(Intent intent)

onBind()被传递给调用Context.bindService()的Intent,onUnbind被Context.unbindService()中的Intent使用。如果服务允许被绑定,那么onBind()方法返回客户端和Service的连接通道。如果一个新的客户端连接到服务,onUnbind()会触发onRebind()的调用。

2.远程服务

远程服务(Remote Service)用于Android系统内部的应用程序之间。

远程服务可以通过自己定义并暴露出来的接口进行程序操作。连接以调用Context.bindService()方法建立,以调用Context.unbindService()关闭。多个应用程序可以绑定至同一个服务。此时如果服务还没有加载,Context.bindService会先加载它。远程服务可被其他应用程序复用,比如天气预报服务,其他应用程序不再写这样的服务,调用已有的即可。

在Android系统中,一个进程通常不能直接访问其他进程的内存空间。如果要在不同的进程间传递对象,需要把对象解析成操作系统能够理解的数据格式,Android采用AIDL(Android Interface Definition Language,接口定义语言)的方式实现这个操作。

具体案例操作可以参考:https://blog.csdn.net/yancr/article/details/88978448?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161698224816780255221369%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161698224816780255221369&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-88978448.first_rank_v2_pc_rank_v29&utm_term=aidl

3.服务小程序

在综合案例中,客户端需要定时与服务器进行交互,以获得最新的话题、私信以及好友的信息,并在界面中进行提示、刷新。MsgService类可以完成这些功能。

MsgService类继承自Service类,实现了其中的onCreate() 、onStar()、onBind()与onDestroy()方法,同时也实现了接口Runnable和其中的run()方法。

onCreate()方法初始化Service,并获得当前登录用户的用户名与密码信息,为请求服务器的参数设置做好准备。

onStart()方法利用Runnable开启一个线程,并运行run()方法,进行服务器的数据请求。在线程中请求是为了防止程序过多地占用内存。在run()方法中对所需要的数据进行不同的请求,通过调用request()方法来连网实现,并在request()方法中对结果进行判别,最后对返回的数据进行解析以完成数据库的更新和修改操作,run()方法中根据request()方法的返回结果进行判断是否有新数据插入数据库,是否需要刷新界面,若有,则要进行界面刷新,刷新UI界面的工作通过Handler来实现。在onStart()方法中,setNextRequestTime是设置定时启动服务的方法,因为涉及定时器类AlarmManager类,在此不多做叙述。

onBind()方法用来绑定服务。

onDestroy方法用来销毁此后台服务。

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值