四大组件——Service基础

Service是什么

定义

服务可由其余应用组件启动,并且即便用户切换到其余应用,服务仍将在后台继续运行。此外,组件可经过绑定到服务与之进行交互,甚至是执行进程间通讯 (IPC)android

  • 后台运行,不可见,没有界面
  • 优先级高于Activity

用途:

  • 服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互等...

注意

  • Service运行在主线程中,不能直接作耗时操做
  • 能够在服务中开启一个线程,在线程中作耗时操做

AndroidManifest.xml中注册Service

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true" />
复制代码
  • enable为true表示容许Service运行
  • exported为true表示容许其余应用隐式调用该服务
public class MyService extends Service {
    private static final String TAG = "MyService";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "--------onCreate: ");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "--------onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "--------onBind: ");
        // TODO: Return the communication channel to the service.
        return new InnerBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "--------onUnbind: ");
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.d(TAG, "--------onRebind: ");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "--------onDestroy: ");
    }

}
复制代码

Service类型

本地服务(Local Service)

  • 应用程序内部

远程服务(Remote Service)

  • Android系统内部的应用程序之间
  • 定义IBinder接口
启动服务方式

1.startServicebash

  • 关闭方法:stopService、stopSelf

2.bindService网络

  • 关闭方法:unbindService
两种启动方式的区别
  • startService方式启动的服务能够长期在后台运行,而bindService方式启动的服务没法长时间在后台运行
  • startService方式启动的服务,不能够和服务进行通信,而bindService方式启动的服务,能够和服务进行通信(经过实现IBinder接口)

service_actiivity.png

以startService方式启动的Service

service.png

实例代码:

布局文件:app

<string name="button">启动服务</string>
<string name="button2">中止服务</string>
<string name="button3">调用服务内部方法</string>
<string name="button4">绑定服务</string>
<string name="button5">解绑服务</string>
复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="64dp"
        android:onClick="startServiceClick"
        android:text="@string/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:onClick="stopServiceClick"
        android:text="@string/button2"
        app:layout_constraintStart_toStartOf="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/button" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="188dp"
        android:onClick="callService"
        android:text="@string/button3"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:onClick="bindService"
        android:text="@string/button4"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="unBindService"
        android:text="@string/button5"
        app:layout_constraintBottom_toTopOf="@+id/button3"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toBottomOf="@+id/button4"
        app:layout_constraintVertical_bias="0.298" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
复制代码

接口定义:ide

public interface ICommunication {
    void callServiceInnerMethod();
}
复制代码

Service实现:布局

public class MyService extends Service {
    private static final String TAG = "MyService";

    //自定义一个Binder内部类实现ICommunication接口实现服务的通信
    private class InnerBinder extends Binder implements ICommunication{

        @Override
        public void callServiceInnerMethod() {
            sayHello();
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "--------onCreate: ");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "--------onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "--------onBind: ");
        // TODO: Return the communication channel to the service.
        return new InnerBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "--------onUnbind: ");
        return super.onUnbind(intent);
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.d(TAG, "--------onRebind: ");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "--------onDestroy: ");
    }

    private void sayHello(){
        Toast.makeText(this,"Hello World!",Toast.LENGTH_SHORT).show();
    }
}
复制代码

Activity实现:ui

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private boolean mIsServiceBind;
    private ICommunication mICommunication;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "--------onCreate: ");
    }

    /**
     * 开启服务
     */
    public void startServiceClick(View view) {
        Intent intent = new Intent();
        intent.setClass(this, MyService.class);
        startService(intent);
    }

    /**
     * 中止服务
     */
    public void stopServiceClick(View view) {
        Intent intent = new Intent();
        intent.setClass(this, MyService.class);
        stopService(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "--------onDestroy: ");
    }

    public void callService(View view) {
        mICommunication.callServiceInnerMethod();
    }

    /**
     * 绑定服务
     */
    public void bindService(View view) {
        Intent intent = new Intent();
        intent.setClass(this, MyService.class);
        mIsServiceBind = bindService(intent, mConnection, BIND_AUTO_CREATE);
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "--------onServiceConnected: ");
            mICommunication = (ICommunication) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "--------onServiceDisconnected: ");
            mICommunication = null;
        }
    };

    /**
     * 解绑服务
     */
    public void unBindService(View view) {
        if (mConnection != null && mIsServiceBind) {
            unbindService(mConnection);
        }
    }
}
复制代码
  • ServiceConnection的onServiceConnected()在绑定Service时调用
  • onServiceDisconnected()只有在异常解绑中止服务时调用,正常解绑不会调用
  • BIND_AUTO_CREATE参数表示绑定Service时建立Service,解绑Service时中止Service

生命周期

回调方法

  • onCreate() 最初建立服务时(在调用onStartCommand()或onBind()以前),系统将调用此方法以执行一次性设置过程。若是服务已经在运行,则不会调用此方法。
  • onStartCommand() 当另外一个组件(例如活动)请求启动服务时,系统经过调用startService()来调用此方法。执行此方法时,服务将启动并能够无限期在后台运行。若是执行此操做,则有责任经过调用stopSelf()或stopService()在服务完成后中止该服务。若是只想提供绑定,则不须要实现此方法。
  • onBind() 当另外一个组件想要与服务绑定时,系统经过调用bindService()来调用此方法。在此方法的实现中,必须提供一个接口,客户端能够经过返回IBinder使用该接口与服务进行通讯。您必须始终实现此方法。可是,若是不想容许绑定,则应返回null。
  • onDestroy() 当再也不使用该服务并将其销毁时,系统将调用此方法。您的服务应实现此目的,以清理全部资源,例如线程,注册的侦听器或接收器。这是服务收到的最后一个回调。

回调调用

  • startService ——> stopService的生命周期
onCreate ——> onStartCommand ——> onDestory
复制代码
  • bindService ——> unBindService的生命周期
onCreate ——> onBind ——> onUnbind ——> onDestory
复制代码

service_lifecycle.png

前台服务ForegroundService

前台服务是用户主动意识到的服务,不是内存不足时系统要杀死的候选对象。前台服务必须为状态栏提供一个通知,该通知位于“正在进行”标题下。这意味着除非服务中止或从前台删除,不然没法取消该通知。this

注意:使用时须要添加权限spa

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
复制代码
public class MyForegroundService extends Service {
    public MyForegroundService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
        //后面一个参数为渠道参数,Android8.0新增要求
        Notification notification = new NotificationCompat.Builder(this, "foreground")
                .setContentTitle("这是标题")
                .setContentText("这是内容")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pi)
                .build();
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel channel = null;
        //Android8.0要求设置通知渠道
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            channel = new NotificationChannel("foreground", "foregroundName", NotificationManager.IMPORTANCE_HIGH);
            if (notificationManager != null) notificationManager.createNotificationChannel(channel);
        }
        //给startForeground()的整数ID不能为0
        startForeground(1, notification);
    }

    @Override
    public void onDestroy() {
        stopForeground(true);// 中止前台服务 参数:表示是否移除以前的通知
        super.onDestroy();
    }
}
复制代码

注意:给startForeground()的整数ID不能为0线程

Activity中启动此服务:

/**
     * 启动前台服务
     */
    public void startFServiceClick(View view) {
        Intent intent = new Intent();
        intent.setClass(this, MyForegroundService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent);
        }
    }
复制代码
相关文章
相关标签/搜索