Android中的服务(service)

Service是Android的四大组件之一

Service是一个能够在后台执行长时间运行的操作应用程序组件,不提供用户界面,应用在后台启用一个Service运行,即使用户切换到另一个应用此Service也会继续运行。

Service有以下几个特点:

(1)无法与用户直接进行交互;

(2)必须由用户或其他的程序启动

(3)优先级介于前台应用和后台的应用之间。

那么我们什么时候会使用Service呢?例如,打开音乐播放器之后,我们想要打开电子书,,而不希望音乐停止播放,此时可以使用Service。

Service具有自己的生命周期,Service服务的生命周期与Activity生命周期是分离的,当Activity被暂停,停止销毁的时候,Service组件还可以继续处理其他的任务。

Android支持服务的原因

(1)允许我们方便的执行后台的任务。

(2)实现同一台设备应用之间的跨进程通信。

Android系统支持两种类型的服务

(1)本地服务

(2)远程服务

创建一个服务,有两种的方式:

1启动方式(startService),通过startService()方式启动

启动方式

(1)Context.startService();服务开始无限期的运行

(2)Context.stopService();被其他的组件终止

以自启动模式启动的服务需要具备自管理的能力,不需要通过方法的调用想外部组件提供数据或功能。

2绑定方式(bindService),通过bindService()方法启动

绑定方式

Context.bindService();绑定后客户端通过Ibinder接口和服务通信。

Context.unbindService();客户端解绑

ServiceConnection提供数据

一个服务可以绑定多个ServiceConnection提供数据。一个服务可以绑定多个ServiceConnection同时为不同的组件提供服务。

被绑定的服务要等待所有服务组件都结束才会被销毁,服务不需要自己终止自己。

这两种的方法是相互独立的,我们可以对一个已经StartService()的服务进行绑定操作,此时该服务必须等到所有绑定客户都解绑后才能执行自己的stopService()方法和stopSelf()方法。

3服务的生命周期

Service实现中,需要重写一些处理服务生命周期关键特征的回调方法。

相同

onCreate();当服务第一次创建的时候,系统会调用这个方法来执行一次安装过程。

onDestroy();当服务不再使用或正在销毁时,系统会调用这个方法。要进行所有需要关闭的资源的关闭

不同

Service实现中,需要重写一些处理服务生命周期关键特征的回调方法

onStartCommand();当一个组件通过调用startService()方法请求启动一个服务的时候,系统会调用onStartCommand()方法。

第一次启动一个服务,会执行onCreate(),onStartCommand(),第二次启动直接只调用onStartCommand()。另外,关于onStartCommand()必须有返回一个整形的常量,用于描述系统应该如何应对服务被KILL的情况:

START_NOT_STICKY:如果系统在onStartCommand()返回后终止服务,则除非有挂起的Intent要传递,否则系统不会重建服务,这是最安全的选项,可以避免在不必要的时候以及应用能够轻松的重启所有未完成的作业时运行服务。

START_STICKY如果系统在onStartCommand()返回后终止服务,则会重建服务并且调用onstartCommand(),但不会重新传递最后一个Intent,相反,除非有挂起Intent要启动服务(在这种情况下,将传递这些Intent),否则系统会通过空Intent调用onStartCommand(),这适应与于执行命令,但无限期运行并等待作业的媒体播放器。

START_REDELIVER_INTENT:如果系统在onStartCommand()返回后终止服务,则会重建服务,并通过传递给服务的最后一个Intent调用onStartCommand().任何挂起Intent均依次传递,这是应用于注定执行应该立即恢复的作业(例如下载文件的服务)

onBind();当一个组件想要通过调用bindService()方法跟这个服务(如执行RPC)绑定的时候,系统会调用这个方法。

manifest.xml

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

    <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/Theme.BindingDemo">
        <service
            android:name=".MyBindService"
            android:enabled="true"
            android:exported="true"></service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
public class MainActivity extends AppCompatActivity {
    MyBindService mService;
    boolean mbind=false;
    ServiceConnection mConnected=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("MyBindService","onServiceConnected.............");
            MyBindService.MyBinder mBinder=( MyBindService.MyBinder)service;
            mService=mBinder.getService();
            mbind=true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("MyBindService","onServiceDisconnected.............链接断开");
            mbind=false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void bindService(View view){
        Intent intent=new Intent(this,MyBindService.class);
        bindService(intent,mConnected, Context.BIND_AUTO_CREATE);
    }
    public void unBindService(View view){
        if(mbind){
            unbindService(mConnected);
            mbind=false;
        }
    }
    public void getData(View view){
        if(mbind){
            Toast.makeText(this,"获取到的随机数为"+mService.getRandomNumber(),Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(this,"服务未绑定",Toast.LENGTH_LONG).show();
        }
    }

}
package com.example.bindingdemo;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.view.View;

import java.util.Random;

public class MyBindService extends Service {
    final static String TAG="MyBindService";
    IBinder iBinder=null;
    Random mGenerator;
    public class MyBinder extends Binder {
        MyBindService getService(){
            return MyBindService.this;
        }
    }
    public MyBindService() {
    }
    public void onCreate(){
        Log.i(TAG,"onCreate.............");
        super.onCreate();
        iBinder=new MyBinder();
        mGenerator=new Random();
    }

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

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

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

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG,"onBind.............");
        // TODO: Return the communication channel to the service.
        return iBinder;
    }
public int getRandomNumber(){
        return mGenerator.nextInt(100);
}

}
2020-12-12 14:28:29.594 30209-30209/com.example.bindingdemo I/MyBindService: onCreate.............
2020-12-12 14:28:29.597 30209-30209/com.example.bindingdemo I/MyBindService: onBind.............
2020-12-12 14:28:29.606 30209-30209/com.example.bindingdemo I/MyBindService: onServiceConnected.............
2020-12-12 14:28:41.740 30209-30223/com.example.bindingdemo I/zygote: Do partial code cache collection, code=27KB, data=27KB
2020-12-12 14:28:41.740 30209-30223/com.example.bindingdemo I/zygote: After code cache collection, code=27KB, data=27KB
2020-12-12 14:28:41.740 30209-30223/com.example.bindingdemo I/zygote: Increasing code cache capacity to 128KB
2020-12-12 14:28:43.958 30209-30209/com.example.bindingdemo I/MyBindService: onUnbind............
2020-12-12 14:28:43.958 30209-30209/com.example.bindingdemo I/MyBindService: onDestroy.............

创建启动类型服务

通过startService()方法创建一个启动型的Service,并且调用服务的onStartCommand()方法启动服务。并调用onStartCommand()方法启动服务

启动服务的时候需要通过intent显示或隐式启动,Intent可以携带一部分的数据,在Service的onStartCommand中可以使用其数据。

默认启动的服务存在于主线程中,会导致主线程阻塞,故通常采用新线程模式来启动服务。

(1)继承Service

(2)继承IntentService

在AndroidMainfest.xml文件中,配置该Service,有两种的配置方式。

(1)显式配置,只需要使用<Service/>标签声明Service的名称。

<service android:name="Service1">

<!--Service名称-->

</service>

(2)隐式配置,除了声明Service名称之外,还要为Service配置<intent-filter.../>子标签。通过匹配的Action属性,说明Service可以被哪些Intent启动。

<service android:name="Service1">

    <intent-filter>

        <action android:name="android.service"/>

        <category android:name="android.intent.category.LAUNCHER">

    </intent-filter>

</service>

服务线程通过继承Service类来实现

当一个组件通过调用StartService(intent)启动一个服务,系统就会调用该服务的onStartCommand()方法。

对于一个启动Service的请求,都会产生一条带有一条StartID和Intent的Message,并发送到MessageQueue中。

Service实现服务可以同时执行多个请求,每个请求都是一个全新的线程,都会被立即的执行,无需等待前一个请求的完成。
注意,不论有多少个请求都只会执行一次onCreat()和一次onDestroy()

操作步骤:

(1)在MainActivity中通过intent启动服务

(2)定义服务类Myservice继承Service,完成menifest注册

(3)重写系统方法

onCreate()

onStartCommand()

onDestory()

根绝情况决定是否启动onBind和onUnbind,onRebind等方法。

MainActivity.java

package com.example.servicelifecycledemo;

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {
    TextView info=null;
    Intent intent=null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        info=findViewById(R.id.info);
        Button btn_start=findViewById(R.id.btn_start1);
        Button btn_stop=findViewById(R.id.btn_stop);
        btn_start.setOnClickListener(new MClick());
        btn_stop.setOnClickListener(new MClick());
        intent=new Intent(this,MyService.class);
    }
    class MClick implements View.OnClickListener{
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.btn_start1:
                    MainActivity.this.startService(intent);
                    break;
                case R.id.btn_stop:
                    MainActivity.this.stopService(intent);
                    break;
            }
        }
    }
}

manifest.xml

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

    <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/Theme.ServiceLifeCycleDemo">
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MyService

package com.example.servicelifecycledemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public void onRebind(Intent intent) {
        Toast.makeText(this,"再次绑定后台的服务",Toast.LENGTH_LONG).show();
        Log.i("hello","onRebind is running.....");
        super.onRebind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Toast.makeText(this,"解绑后台的服务",Toast.LENGTH_LONG).show();
        Log.i("hello","onUnabind is running.....");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this,"销毁后台的服务",Toast.LENGTH_LONG).show();
        Log.i("hello","onDestory is running.....");
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this,"开始后台的服务",Toast.LENGTH_LONG).show();
        Log.i("hello","onStartCommand is running.....");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onCreate() {
        Toast.makeText(this,"创建后台的服务",Toast.LENGTH_LONG).show();
        Log.i("hello","onCreate is running.....");
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(this,"绑定后台的服务",Toast.LENGTH_LONG).show();
        Log.i("hello","onBind is running.....");
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

猜你喜欢

转载自blog.csdn.net/a15929748502/article/details/111007591
今日推荐