Android学习笔记之Service

Service在程序的后台运行

Service

Service是Context的子类

UI控件是线程不安全的,所有的UI操作必须在主线程中

Service并不会自动开启线程,所有代码默认运行在主线程,要手动开启子线程

在服务里开的子线程(IntentService)比在活动里开的子线程(AsyncTask)重要性更高更不容易被杀死

Service的使用

右击New→Service→Service

Export属性表示是否允许其它程序访问这个Service

Enabled属性表示是否启用这个Service

在任何一个位置都可以调用stopSelf()方法使Service停止

普通使用

启动Service

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

结束Service

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

与Activity绑定

public class MyService extends Service {
​
    class MyBinder extends Binder{
        public void startSomething(){
            ...//可以在这里开IntentService
        }
    }
​
    public MyService() { }
​
    @Override
    public void onCreate() {
        super.onCreate();
    }
​
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
​
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();//把连接器暴露给外部,活动就可以使用连接器里的方法,在Service中执行
    }
​
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

在活动中使用ServiceConnection获得Service返回回来的连接器

实现了指挥服务去干什么服务就去干什么的功能

private ServiceConnection connection=new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MyService.MyBinder myBinder=(MyService.MyBinder) service;//获得连接器
        myBinder.startSomething();//执行连接器中的方法
    }
​
    @Override
    public void onServiceDisconnected(ComponentName name) { }
};

启动绑定

Intent intent=new Intent(this,MyService.class);
bindService(intent,connection,BIND_AUTO_CREATE);//通过ServiceConnection与后台某项特定服务绑定

结束绑定

unbindService(connection);

Service的生命周期

若进程里的Service正在执行生命周期回调,那么这个进程属于前台进程

若进程里的Service与目前处于前台的活动绑定,那么这个进程属于前台进程

使用startService()方式启动

只有第1次启动执行onCreate()->每次启动都执行onStartCommand()->stopService()/自己stopSelf()则执行onDestroy()

  • 适用于长期执行进行某项任务

  • 不管是否有Activity使用bindService()/unbindService()到该Service,该Service一直在后台运行,直到被调用stopService()/自己stopSelf()

  • 不管startService()多少次,stopService()1次就会停止服务

  • Service启动之后就和Activity没什么关联了,不要求在Activity退出时手动退出Service

使用bindService()方式启动

只有第1次启动执行onCreate()->只有第1次启动执行onBind()->unbindService()则执行onUnBind()->onDestroy()

  • 适用于与正在运行的Service取得联系/类似懒汉式的思路,开始先不创建,在需要用到的时候去bind一下,节约资源

  • 该Service一直在后台运行,直到被调用unbindService()解绑/绑定了该Service的Context不存在了

  • Service生命周期依附于启动它的Context,因此当前台调用bindService()的Context销毁,Service也会自动调用onUnbind()和onDestory()

使用混合型方式启动

Service被startService()的同时又被bindService(),该Service将会一直在后台运行,并且不管调用几次,onCreate()方法始终只会调用一次,onStartCommand()的调用次数与startService()调用的次数一致(使用bindService()方法不会调用onStartCommand())。同时,调用unBindService()将不会停止Service,必须调用stopService()或Service自身的stopSelf()来停止服务

前台Service

8.0+Service运行在后台时随时会被系统回收,只有应用前台可见时(以类似通知的形式存在),Service才能稳定运行

渠道一旦建立,修改渠道属性将不再生效,除非卸载重装/更改渠道id

9.0+需要添加一条普通权限

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

在Service的onCreate()方法

@Override
    public void onCreate() {
        super.onCreate();
​
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("foreground", "前台Service", NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(channel);
        }
        
        Intent intent = new Intent(this, MainActivity.class);
        //这里也可以使用taskStackBuilder的方式获得pendingIntent
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
        
        //使用compat可以兼容所有安卓版本,参数为(上下文,渠道id)
        Notification notification= new NotificationCompat.Builder(this,"foreground")
            .setContentTitle("通知标题")
            .setContentText("通知内容")
            .setSmallIcon(R.drawable.xxx)
            .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.xxx))//将图片解析为Bitmap
            .setShowWhen(false)//是否显示时间
            .setNotificationSilent()//静默通知
            .setVisibility(NotificationCompat.VISIBILITY_SECRET)//锁屏不可见
            .setContentIntent(pending)//点击通知后跳转到的页面
            .build();//创建通知对象
​
        //注意启动通知的方式不是通过管理器发送通知,而是启动前台
        startForeground(1, notification);
    }

取消

  • 将前台服务降为后台服务,可以让它从任务栏消失

//此时服务并没有停止,直到调用stopService()
stopForeground(true);
  • 直接stopService(),无论Service在前/后台都会直接结束啦

IntentService

是Service的子类

Service本身是在主线程中运行,如果执行耗时操作需要自己手动开启子线程并且在运行结束后调用stopSelf或者stopService来停止,这样可行,但是自己去管理Service的生命周期和子线程并不是一个好的选择,因此android提供了IntentService来实现自动开启子线程并关闭

新建一个继承了IntentService的类

public class MyIntentService extends IntentService {
​
    public MyIntentService() {
        super("MyIntentService");
    }
​
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        //这个方法已经是在子线程中运行的了,可以处理一些耗时逻辑
    }
}

使用方法

Intent intent=new Intent(this,MyIntentService.class);
startService(intent);

既然是Service就要在Manifest文件里注册

<service
        android:name=".MyIntentService"
        android:enabled="true"
        android:exported="true" />

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值