Android的Service相关问题

Service知识点

目录

Service知识点

Service的启动

Service的生命周期?

Activity如何与Service通信

IntentService是什么

说说 Activity、Intent 和 Service 是什么关系

Service优先级如何提高

Service 里面可以弹Toast吗?

是否可以在Service内进行耗时操作,会有什么后果?

一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory()方法?

前台服务是什么?和普通服务的不同?如何去开启一个前台服务?

ActivityManagerService

Service 和 Thread 的区别

Service 的 onStartCommand 方法有几种返回值?各代表什么意思?

Service使用场景?


Service的启动

Service 是 Android 中实现程序后台运行的解决方案,非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务。Service默认运行在UI主线程中,所以不能做耗时操作,只能在Service中创建子线程来完成耗时操作。

补充说明:Service有两种启动方式,startService()和bindService(),它们之间的区别是:

* startService()启动后无返回结果,startService()的生命周期有三个函数,分别是onCreate()、onStartCommand()和onDestory()。当我们首次startSerivce()启动一个service的时候,会调用service的onCreate函数创建该服务,然后调用onStartCommand函数执行操作,可以调用stopSevice/stopSelf来结束一个Service(多次调用都不会有异常)。(注:多次通过startService启动服务,onCreate只执行1次,都会调用onStartCommand。)启动后,它就独立于调用者而运行,因此任务结束后,Service需要stopSevice/stopSelf函数来停止该服务,避免消耗系统资源或电量。

* bindService()绑定Service后可以进行交互操作(发请求、获取结果或IPC通信),bindService的生命周期有四个函数,分别是onCreate()、onBind() 、onUnBind()和onDestory(),首次启动会先执行onCreate()方法创建服务,onBind() 会将调用者和服务绑定在一起,调用者退出时可以调用unbindService()进行解绑操作(方法中会调用onUnBind和onDestory)。(注:多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。)

Service的生命周期?

Service 的生命周期

* 回调方法含义:

    * onCreate:服务第一次被创建时调用;

    * onStartComand:服务启动时调用;

    * onBind:服务被绑定时调用;

    * onUnBind:服务被解绑时调用;

    * onDestroy:服务停止时调用;

* 生命周期:

    * 只调用 startService() 启动服务:onCreate() -> onStartCommand() -> onDestory()

    * 只调用 bindService() 绑定服务:onCreate() -> onBind() -> onUnBind() -> onDestory()

    * 同时使用startService()与bindService():onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory。

* 种类:

    * startService():开启Service,调用者退出后Service仍然存在。

    * bindService():开启Service,调用者退出后Service也随即退出。

Service的调用方式?

// startService

* 第一步:新建类并继承Service且必须重写onBind()方法,有选择的重写onCreate()、onStartCommand()及onDestroy()方法。

* 第二步:在配置文件AndroidManifest.xml中进行注册,否则不能生效。

* 第三步:在 Activity 中利用 startService(Intent) 可实现 Service 的启动。

* 第四步:在 Activity 中 stopService(Intent) 停止服务,或者在Service任意位置调用stopSelf();

public class MyService extends Service {





    public MyService() {

    }

    @Override

    public void onCreate() {

        super.onCreate();

    }

    @Override

    public int onStartCommand(Intent intent, int flags, int startId) {

        new Thread(new Runnable() {

            @Override

            public void run() {

                //处理具体的逻辑

                //必须调用stopService或者stopSelf方法才能停止

                stopSelf();

            }

        }).start();

        return super.onStartCommand(intent, flags, startId);

    }

    @Override

    public void onDestroy() {

        super.onDestroy();

    }

    @Override

    public IBinder onBind(Intent intent) {

        throw new UnsupportedOperationException("Not yet implemented");

    }

}

//在配置文件AndroidManifest.xml中进行注册

<service

    android:name=".MyService"

    android:enabled="true"

    android:exported="true" />

//启动

Intent intent = new Intent(this, MyService.class);

startService(intent);

//停止

Intent intent = new Intent(this, MyService.class);

stopService(intent);

//bindService

* 第一步:创建BindService服务端,继承自Service,并在类中创建一个实例IBinder接口实现对象并提供公共方法给客户端调用。

* 第二步:从 onBind() 回调方法返回此Binder实例;

* 第三步:在客户端中,从onServiceConnected()回调方法接收Binder,并使用提供的方法调用绑定服务。

* 绑定服务提供了客户端和服务端接口,进行数据的交互(发送请求、获取结果、进程间通信)

public class TestService extends Service {

    private Mybinder mBinder = new Mybinder();

    public TestService() {

    }

    @Override

    public IBinder onBind(Intent intent) {

        return mBinder;

    }

    public class Mybinder extends Binder {

        public void showToast() {

            Toast.makeText(getApplicationContext(), "BindService", Toast.LENGTH_SHORT).show();

        }

    }

}





public class MainActivity extends AppCompatActivity {

    private TestService.Mybinder mBinder;

    private ServiceConnection mConnection = new ServiceConnection() {

        @Override

        public void onServiceConnected(ComponentName name, IBinder service) {

            //成功绑定

            mBinder = (TestService.Mybinder) service;

            mBinder.showToast();

        }

        @Override

        public void onServiceDisconnected(ComponentName name) {

            //断开连接

        }

    };

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        //绑定服务

        Intent bindIntent = new Intent(this, TestService.class);

        bindService(bindIntent, mConnection, BIND_AUTO_CREATE);

        //解绑服务

        unbindService(mConnection);

    }

}

 

// IntentService
第一步:新建类并继承IntentService,在这里需要提供一个无参的构造函数且必须在其内部调用父类的有参构造函数,然后具体实现在onHandleIntent()方法,这里可以去处理一些耗时操作而不用担心 ANR 的问题,因为这个方法已经是在子线程中运行的了。 
第二步:在配置文件中进行注册。 
第三步:在活动中利用startService(Intent)实现IntentService的启动,和Service用的方法是完全一样的。

public class MyIntentService extends IntentService {


    public MyIntentService() {
        super("MyIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        //子线程 耗时操作
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}
//调用方法
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);

Activity如何与Service通信

在 Activity 中可以通过 startService 和 bindService 方法启动 Service。一般情况下如果想获取 Service 的服务对象那么肯定需要通过bindService()方法,比如音乐播放器,第三方支付等。如果仅仅只是为了开启一个后台任务那么可以使用 startService() 方法。

1. 首先定义 MyService 来指定具体的操作。

2. 先在 Activity 里实现一个ServiceConnection类 connection,重写 onServiceConnected 和 onServiceDisconnected 方法,分别表示绑定成功与断开;

3. 并将 connection 传递给 bindService() 方法去启动 Service;

4. 在ServiceConnection的onServiceConnected()方法里启动 MyService 里的方法。

5. 最后通过 unbindService 来解绑服务。

IntentService是什么

IntentService是Service的子类,是一个异步的、会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题。

* IntentService 是一个特殊的 Service,它继承了 Service 并且它是一个抽象类,因此必须创建它的子类才能使用 IntentService。

* 它封装了 HandlerThread 和 Handler,可用于执行后台耗时的任务,当任务全部执行完毕后自动停止。

* 它的优先级比普通线程要高,所以适合执行高优先级的后台任务。

* (HandlerThread是继承了Thread,他的作用是不用每次创建线程,他内部有循环机制可以重复利用,不用的时候要quit或者quitSafely。)

说说 Activity、Intent 和 Service 是什么关系

他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都是 Android 四大组件之一。他俩都是 Context 类的子类 ContextWrapper 的子类,因此他俩可以算是兄弟关系吧。不过兄弟俩各有各自的本领,Activity 负责用户界面的显示和交互,Service 负责后台任务的处理。Activity 和 Service 之间可以通过 Intent 传递数据,因此可以把 Intent 看作是通信使者。

Service优先级如何提高

* 在AndroidManifest.xml配置文件设置android:priority 属性,和有序广播一样。

* 在onStartCommand里面调用 startForeground()方法把Service提升为前台进程级别,然后再onDestroy里面要记得调用stopForeground()方法。

* onStartCommand方法,手动返回START_STICKY。

* 在onDestroy方法里发广播重启service。service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service。(第三方应用或是在setting里-应用-强制停止时,APP进程就直接被干掉了,onDestroy方法都进不来,所以无法保证会执行)

* 监听系统广播判断Service状态。通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活。

Service 里面可以弹Toast吗?

可以弹 1.Service是跑在主线程的,可以进行UI刷新。 2.Service本身就是context的子类,携带者需要的上下文信息


是否可以在Service内进行耗时操作,会有什么后果?

不可以,因为Service是在主线程的,耗时操作可能会导致ANR的产生,可以在其中创建子线程然后去处理耗时操作

但是最好的方案是 通过 IntentService进行做


一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory()方法?

当对一个服务既调用 startService() 方法,又调用了bindService()方法,根据Android系统的机制,一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被销毁。所以,这种情况要同时调用是stopService()和unbindService方法,onDestroy才会执行。


前台服务是什么?和普通服务的不同?如何去开启一个前台服务?

前台服务和普通服务最大的区别是:前者会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。使用前台服务或者为了防止服务被回收掉,比如听歌,或者由于特殊的需求,比如实时天气状况。

想要实现一个前台服务非常简单,它和之前学过的发送一个通知非常类似,只不过在构建好一个Notification之后,不需要NotificationManager将通知显示出来,而是调用了startForeground()方法。

// 在Android8.0及以上的版本,需要准备channel



class MyService: Service() {





    var CHANNEL_ONE_ID = "com.primedu.cn"

    var CHANNEL_ONE_NAME = "Channel One"





    override fun onCreate() {





        var notificationChannel: NotificationChannel? = null

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

            notificationChannel = NotificationChannel(

                CHANNEL_ONE_ID,

                CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_HIGH

            )

            notificationChannel.enableLights(true)

            notificationChannel.lightColor = Color.RED

            notificationChannel.setShowBadge(true)

            notificationChannel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC

            val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager

            manager.createNotificationChannel(notificationChannel)

        }

        val intent = Intent(this, MainActivity::class.java)

        val pi = PendingIntent.getActivity(this, 0, intent, 0)

        val notification: Notification = NotificationCompat.Builder(this).

        setChannelId(CHANNEL_ONE_ID)

            .setContentTitle("This is content title")

            .setContentText("This is content text")

            .setWhen(System.currentTimeMillis())

            .setSmallIcon(R.mipmap.ic_launcher)

            .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))

            .setContentIntent(pi)

            .build()

        startForeground(BIND_AUTO_CREATE, notification)

    }





    override fun onBind(intent: Intent?): IBinder? {

        throw UnsupportedOperationException("Not yet implemented");

    }

}

ActivityManagerService

ActivityManagerService是Android中最核心的服务 , 主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块类似。


Service 和 Thread 的区别

* 定义:

    * Thread 是程序执行的最小单元,它是分配CPU的最小单位。可以执行异步操作,是相对独立的。

    * Service 是 Android 的一种特殊机制,是运行在主线程当中的,是依托于所在的主线程。是由系统进程托管,也是一种轻量级IPC通信方式(Activity 和 Service 绑定,然后数据通信,并处于不同进程。)

* 关系:Service 和 Thread 之间并没有什么关联,Service 翻译成中文是服务,同时服务可以理解为后台。Thread 是开启子线程执行耗时操作,而 Service 是在主线程中执行,但总被认为可以在后台处理耗时任务,容易混淆了两者之间的概念。

* 实际开发中:在Android系统当中,线程一般指的是工作线程,主线程主要负责UI绘制,而Service 就是运行在主线程当中的。

* 应用场景:

    * 当需要耗时的操作,比如网络请求,图片加载等等都应该使用工作线程。

    * 当需要在后台播放音乐、开启定位、数据统计等等应该使用Service。

* 区分

    * 1.不要把后台和子线程联系在一起;

    * 2.服务和后台是不同的概念;

    * 3.Android的后台是指它的运行不依赖与UI线程,即使程序被销毁了、程序被关闭了,服务进程仍然在后台进行计算、统计等等。

    * 4.如果在 Service 执行耗时,也需要创建子线程,然后去做耗时逻辑。

    * 5.Service是为了弥补 Activity 被销毁之后,无法获取之前所创建的子线程实例,并对后台进行控制的情况而产生的。


Service 的 onStartCommand 方法有几种返回值?各代表什么意思?

有四种返回值,不同值代表的意思如下:

* START_STICKY:如果 service 进程被 kill 掉,保留 service 的状态为开始状态,但不保留递送的 intent 对象。随 后系统会尝试重新创建 service,由于服务状态为开始状态,所以创建服务后一定会调用 onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到 service,那么参数 Intent 将为 null。

* START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异常 kill 掉,系统不会自动重启该服务。

* START_REDELIVER_INTENT:重传 Intent。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异 常 kill 掉,系统会自动重启该服务,并将 Intent 的值传入。

* START_STICKY_COMPATIBILITY: START_STICKY 的兼容版本,但不保证服务被 kill 后一定能重启


Service使用场景?

当需要长期在后台进行的工作我们需要将其放在Service中去做,比如音乐播放、下载、上传大文件、定时关闭应用等功能。这样做的原因是如果放在Activity当中去执行的话,当Activity销毁后,那这些功能也就停止了,这显然是不符合我们的设计要求的,所以要将他们放在Service中去执行。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

quchen528

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值