关于Service的一些总结

一: 什么是Service? Service 的使用

二:Service的生命周期

三:Service和Thread的区别?为什么要用Service而不是Thread呢?

四:Service 和 Activity 在同一个线程吗? 关于InterService

五:Activity和Service的通信

六:service被kill之后怎么让它重启

七:Service 里面可以弹吐司么

八:说说 Activity、Intent、Service 是什么关系


一: 什么是Service? Service 的使用

Service是用于后台服务的,当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作而引入了Service这个概念。

那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR,为了解决这样的问题,引入了IntentService

服务可以通过StartService()和bindService() 开启,绑定

创建MyService服务,并且在清单文件里配置

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

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("MyService-->","onBind");
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("MyService-->","onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("MyService-->","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("MyService-->","onDestroy");

清单文件

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

StartService()

 button3?.setOnClickListener {
            var intent = Intent(this@Main2Activity, MyService::class.java)
            startService(intent)

        }

看看StartService()的方式的生命周期

//打开Activity
D/MainActivity-->: onCreate
D/MainActivity-->: onStart
D/MainActivity-->: onResume
//点击开启服务
D/MyService-->: onCreate
D/MyService-->: onStartCommand
//点击back,关闭Activity
D/MainActivity-->: onPause
D/MainActivity-->: onStop
D/MainActivity-->: onDestroy

点击back,退出Activity,发现Service 并没有调用onDestroy,看后台正在运行的服务列表,确实有MyService,这说明通过StartService开启的服务,不受Activity启动的生命周期管理,自行运行在后台,如果关闭服务可以通过StopService,或者服务自身调用stopSelf()

 @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService-->","onStartCommand");
        //调用自身的方法
        stopSelf();
        return super.onStartCommand(intent, flags, startId);
    }
D/MyService-->: onCreate
D/MyService-->: onStartCommand
//直接调用了关闭方法
D/MyService-->: onDestroy
var intent = Intent(this@Main2Activity, MyService::class.java)
button3?.setOnClickListener {
        //开启服务
        startService(intent)

 }
  button4?.setOnClickListener {
       //关闭服务
        stopService(intent)

  }
//开启
D/MyService-->: onCreate
D/MyService-->: onStartCommand
//关闭
D/MyService-->: onDestroy

如果我多次开启服务:

D/MyService-->: onCreate
D/MyService-->: onStartCommand
D/MyService-->: onStartCommand
D/MyService-->: onStartCommand
D/MyService-->: onStartCommand
D/MyService-->: onStartCommand
D/MyService-->: onStartCommand
D/MyService-->: onStartCommand

总结 startService的生命周期:

onCreate:只会调用一次,

多次开启服务,会调用多次 onStartCommand()

onDestroy() 也是只调用一次


BindService()

var conn: ServiceConnection = MyServiceConnection()

var intent = Intent(this@Main2Activity, MyService::class.java)

 button5?.setOnClickListener {
            //绑定服务
            bindService(intent, conn, Context.BIND_AUTO_CREATE)

        }
  button6?.setOnClickListener {
            //解绑服务
            unbindService(conn)
        }
class MyServiceConnection : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        }

    }

生命周期:

//点击绑定服务
D/MyService-->: onCreate
D/MyService-->: onBind
//点击解绑服务
D/MyService-->: onUnbind
D/MyService-->: onDestroy

注意:

当我点击绑定服务时会调用 onCreate和onBind(),当我多次点击绑定服务时,onCreate和onBind方法只调用一次.

当我点击解绑服务时,调用onUnbind()和onDestroy(),但是需要注意的是不能多次点击解绑操作,会崩溃,提示 

 java.lang.IllegalArgumentException: Service not registered:

通过BindService,调服务里面的方法()

Activity的代码:

class Main2Activity : AppCompatActivity() {
   //内部类引用
    var conn: ServiceConnection = MyServiceConnection()
   //接口返回的binder的接口引用
    var iService: IService? = null

    override
    fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Log.d("MainActivity-->", "onCreate")
       
       
        var intent = Intent(this@Main2Activity, MyService::class.java)
        button3?.setOnClickListener {
            //开启服务
            startService(intent)

        }
        button4?.setOnClickListener {
            //关闭服务
            stopService(intent)

        }
        button5?.setOnClickListener {
            //绑定服务
            bindService(intent, conn, Context.BIND_AUTO_CREATE)

        }
        button6?.setOnClickListener {
            //解绑服务
            unbindService(conn)
        }
        button7?.setOnClickListener {
            //调用服务里的方法
            iService?.callServiceMethod()
        }

    }

    inner class MyServiceConnection : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            iService = service as IService
        }

    }

}

MyService代码:

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

    class MyBinder extends Binder implements IService {

        @Override
        public void callServiceMethod() {
            call();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d("MyService-->", "onBind");
        return new MyBinder();
    }

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

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

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

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

    public void call() {
       Log.d("MyService-->", "我是服务里面 方法,我被调用了");
    }
}

IService接口

public interface IService {
    void callServiceMethod();
}

//点击调用service的方法,打印:“我是服务里面 方法,我被调用了”


三:Service和Thread的区别?为什么要用Service而不是Thread呢?

 Thread:Thread 是程序执行的最小单元,可以用 Thread 来执行一些异步的操作。

 Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。

例子:在Service里,我开一个子线程执行一个耗时操作,和我在Activity里开一个子线程执行耗时操作,他们俩个都可以实现耗时操作,可以执行相同的逻辑,那么,他们俩个有什么区别呢?

是有区别的。这里涉及到进程的级别:

1、前台进程

用户当前正在做的事情需要这个进程。如果满足下面的条件之一,一个进程就被认为是前台进程:

这个进程拥有一个正在与用户交互的Activity(这个Activity的onResume()方法被调用)。

这个进程拥有一个绑定到正在与用户交互的activity上的Service。

这个进程拥有一个前台运行的Service(service调用了方法startForeground()).

这个进程拥有一个正在执行其任何一个生命周期回调方法(onCreate(),onStart(),或onDestroy())的Service。

这个进程拥有正在执行其onReceive()方法的BroadcastReceiver。


通常,在任何时间点,只有很少的前台进程存在。它们只有在达到无法调合的矛盾时才会被杀--如内存太小而不能继续运行时。通常,到了这时,设备就达到了一个内存分页调度状态,所以需要杀一些前台进程来保证用户界面的反应

2、可见进程

一个进程不拥有运行于前台的组件,但是依然能影响用户所见。满足下列条件时,进程即为可见:

这个进程拥有一个不在前台但仍可见的Activity(它的onPause()方法被调用)。当一个前台activity启动一个对话框时,就出了这种情况。

3、服务进程

一个可见进程被认为是极其重要的。并且,除非只有杀掉它才可以保证所有前台进程的运行,否则是不能动它的。

这个进程拥有一个绑定到可见activity的Service。

一个进程不在上述两种之内,但它运行着一个被startService()所启动的service。

尽管一个服务进程不直接影响用户所见,但是它们通常做一些用户关心的事情(比如播放音乐或下载数据),所以系统不到前台进程和可见进程活不下去时不会杀它。

4、后台进程

一个进程拥有一个当前不可见的activity(activity的onStop()方法被调用)。

这样的进程们不会直接影响到用户体验,所以系统可以在任意时刻杀了它们从而为前台、可见、以及服务进程们提供存储空间。通常有很多后台进程在运行。它们被保存在一个LRU(最近最少使用)列表中来确保拥有最近刚被看到的activity的进程最后被杀。如果一个activity正确的实现了它的生命周期方法,并保存了它的当前状态,那么杀死它的进程将不会对用户的可视化体验造成影响。因为当用户返回到这个activity时,这个activity会恢复它所有的可见状态。

5、空进程

一个进程不拥有入何active组件。

保留这类进程的唯一理由是高速缓存,这样可以提高下一次一个组件要运行它时的启动速度。系统经常为了平衡在进程高速缓存和底层的内核高速缓存之间的整体系统资源而杀死它们。

注意:

如上边说的,在服务里和单独开一个子线程,如果当前应用程序内存不足是,和首先销毁单独开启的子线程的进程,而开启服务的进程优先级比较高,更好执行我没的异步任务,这就是为什么选择Service的原因


四:Service 和 Activity 在同一个线程吗? 关于InterService?

是的,同在一个Activity的mainThrea,也就是UI线程,所以在服务里,也不能执行耗时操作,如果执行会出现ANR

InterService

为了可以简单地创建一个异步的、会自动停止的服务,Android专门提供了一个IntentService类,这个类就很好的解决在服务里不能执行耗时操作。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent()回调方法中执行,并且每次只会执行一个工作线程,执行完第一个后,再执行第二个,以此类推。

public class MyIntentService2 extends IntentService {


    //调用父类有参构造函数。这里我们手动给服务起个名字为:MyIntentService2
    public MyIntentService2() {
        super("MyIntentService2");
    }


    //该方法在会在一个单独的线程中执行,来完成工作任务。任务结束后,该Service自动停止
    @Override
    protected void onHandleIntent(Intent intent) {
    //直接执行耗时的操作
    }

    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.d("MyIntentService2", "onDestroy");
    }
}

//清单文件

 <service
            android:name=".MyIntentService2"
            android:exported="false"></service>

//开启IntentService

  var intent = Intent(this@Main2Activity, MyIntentService2::class.java)
        startService(intent)

IntentService分析:

//继承于Service的特性
public abstract class IntentService extends Service {

    //looper对象
    private volatile Looper mServiceLooper;

   //创建一个handle 用来接受和处理Startcomment传过来的intent
    private volatile ServiceHandler mServiceHandler;


    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
           //因为handler队列的关系,他会一个一个的执行
            onHandleIntent((Intent)msg.obj);
           //如果没有了,就调用自己的关闭方法
            stopSelf(msg.arg1);
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }

   
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }

    @Override
    public void onCreate() {
       
        super.onCreate();
        //初始化的时候 创建一个Handler继承Threa,里面有Handle
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        //执行HandlerThread中run()方法,里面的looper.loop()开启无线循环
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
       //发送到Handler中
        mServiceHandler.sendMessage(msg);
    }

    
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        //接受传过来的intent
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

(1)  它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。

(2)  创建了一个工作队列,来逐个发送intent给onHandleIntent()。

(3)  不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。

(4)  默认实现的onBind()返回null

(5)  默认实现的onStartCommand()的目的是将intent插入到工作队列中


五:Activity和Service的通信

1.可以通过bindService 返回MyBinder的引用,就行通讯

2.可以通过Messenger实现通讯

https://blog.csdn.net/iispring/article/details/48329925


六:service被kill之后怎么让它重启

  • 在onStartCommand方法中将flag设置为START_STICKY;
  • 在xml中设置了android:priority
  • 在onStartCommand方法中设置为前台进程
  • 在onDestroy方法中重启service
  • 用AlarmManager.setRepeating(...)方法循环发送闹钟广播,接收的时候调用service的onstart方法

七:Service 里面可以弹吐司么


可以的。弹吐司有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类,因此在 Service 里面弹吐司是完全可以的。比如我们在 Service 中完成下载任务后可以弹一个吐司通知用户


八:说说 Activity、Intent、Service 是什么关系

  • 他们都是 Android 开发中使用频率最高的类。

  • 其中 Activity 和 Service 都是 Android 四大组件
    之一。他俩都是 Context 类的子类 ContextWrapper 的子类,因此他俩可以算是兄弟关系吧。

  • 不过
    兄弟俩各有各自的本领,Activity 负责用户界面的显示和交互,Service 负责后台任务的处理。Activity
    和 Service 之间可以通过 Intent 传递数据,

  • 因此可以把 Intent 看作是通信使者。


九:进程间通信的方式 ?  讲讲 AIDL。Binder的使用

问题一:什么是:进程间通信?

IPC,全称Inter-Process Communication,字面意思就是进程间通信或者跨进程通信。

那什么是进程呢?它和线程有什么关系?
进程是系统进行资源分配和调度的基本单位,是操作系统结构的基础;早期表现为一个程序,现在可以看作线程的容器。

线程是CPU调度的最小单位。一个进程可以包含一个或者多个线程,进程向系统申请资源,线程使用进程拥有的资源。
IPC不是Android所独有的,是现代操作系统都存在的机制,对于Android来说。它是一种基于Linux内核的移动OS,他的进程通信方式不仅仅包含信号量、套接字、管道等等,还包括了Android独有的、特色的Binder机制。

Parcelable与Serializable的性能比较

序列化:内存中的对象->磁盘

反序列化:磁盘中对象->内存

  •  在内存的使用中,前者在性能方面要强于后者
  •  后者在序列化操作的时候会产生大量的临时变量,(原因是使用了反射机制)从而导致GC的频繁调用,因此在性能上会稍微逊色
  • Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小,因此在内存之间进行数据传递的时候,Android推荐使用Parcelable,既然是内存方面比价有优势,那么自然就要优先选择.
  • 在读写数据的时候,Parcelable是在内存中直接进行读写,而Serializable是通过使用IO流的形式将数据读写入在硬盘上.

但是:虽然Parcelable的性能要强于Serializable,但是仍然有特殊的情况需要使用Serializable,而不去使用Parcelable,因为Parcelable无法将数据进行持久化,因此在将数据保存在磁盘的时候,仍然需要使用后者,因为前者无法很好的将数据进行持久化.(原因是在不同的Android版本当中,Parcelable可能会不同,因此数据的持久化方面仍然是使用Serializable)

问题二:讲讲AIDl

AIDL(Android Interface Definition Language)是Android系统自定义的接口描述语言。可以用来实现进程间的通讯方式之一,底层主要用到Binder。

AIDL 编写:

模拟demo 底层binder实现客户端与服务端通信,binder里面又用到内存映射 mmap()方法

1.创建一个项目textService

创建一个MySrvice 集成Service 清单文件配置下,

并且指定意图过滤器--》最好是当前应用的包名

android:enabled="true"

android:exported="true"

这俩个必须有个为true,才可以被其他应用远程调用

public class MyService extends Service {

public MyService() {

}


private class MyBinder extends IService.Stub {

@Override

public void callMethod() throws RemoteException {

show();

}

}


@Override

public IBinder onBind(Intent intent) {

return new MyBinder();

}


@Override

public void onCreate() {

Log.i("远程", "我是远程服务我创建了");

super.onCreate();

}


@Override

public void onDestroy() {

super.onDestroy();

}

//服务里面的方法,可以被远程调用

void show() {

Log.i("远程", "我是远程,我方法别调用了");

}

}

IService.Stub

首先创建一个aidl文件夹,光标☞到app-src-main上,点击右键,选择aidl,输入aidl的文件名

里面不可以有public 等修饰符

build下项目,或着同步一下,会在app-build-generated-source-debug-包名下生产aidl文件

远程服务到此就ok了


客户段

public class MainActivity extends AppCompatActivity {

IService mIService;

ServiceConnection conn;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}


//点击绑定服务

public void bind(View view) {

Intent intent = new Intent();

//指定同样意图过滤器

intent.setAction("mall.kotlin.com.textservice");

//指定远程服务的包名(必须指定,不然就会报错)

intent.setPackage(getPackageName());

conn = new conn();

bindService(intent, conn, BIND_AUTO_CREATE);

}


//调用远程服务里面的方法

public void call(View view) {

try {

mIService.callMethod();

} catch (RemoteException e) {

e.printStackTrace();

}

}


private class conn implements ServiceConnection {

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

mIService = IService.Stub.asInterface(service);

}



@Override

public void onServiceDisconnected(ComponentName name) {


}

};

}

mIService = IService.Stub.asInterface(service);

这个是怎么生成的?

首先吧远程服务的aidl文件夹,复制到当前项目main下面,并且里面的包名和远程服务的aidl里面的包名一致,build下项目,同样在当前source里面生产一个IService.stub类

mIService = IService.Stub.asInterface(service);这个mIservice就是当前本地的远程服务的接口,嗲用他就可以调用远程服务的里面的方法


 

Binder 

这里不在细致分析,提供几个链接供大家分享

https://www.jianshu.com/p/4ee3fd07da14

https://www.jianshu.com/p/719fc4758813

开发艺术-->

 

在Android开发中,Service是一个非常重要的组件,用于在后台执行长时间运行的操作,不与用户交互。以下是本次实验的总结: 1. Service生命周期 Service的生命周期包括:onCreate()、onStartCommand()、onBind()、onUnbind()、onRebind()和onDestroy()。开发者可以根据不同的业务需求实现这些生命周期函数。 2. Service的启动和停止 Service的启动和停止有两种方式:使用startService()和stopService()方法来启动和停止Service使用bindService()和unbindService()方法来绑定和解绑Service。需要注意的是,使用startService()方法启动的Service会一直运行,直到调用stopService()方法或者Service自己调用stopSelf()方法;使用bindService()方法启动的Service会在与之绑定的Activity销毁时自动停止。 3. Service的通信 Service可以和Activity之间进行通信,可以使用Intent传递数据,也可以使用Messenger进行通信。如果需要在Service中执行耗时操作,需要在Service中开启一个新的线程来执行,否则会阻塞主线程。 4. Service的注册 在AndroidManifest.xml文件中注册Service,可以使用以下代码: ``` <service android:name=".MyService" /> ``` 5. Service注意事项使用Service时,需要注意以下几点: - Service是在主线程中运行的,不能在Service中执行耗时操作,否则会阻塞主线程。 - Service一旦启动就会一直运行,需要在适当的时候停止Service。 - Service可以和Activity之间进行通信,需要根据具体的业务需求选择合适的通信方式。 总之,Service是Android开发中非常重要的组件,掌握其使用方法和生命周期函数对于开发高质量的Android应用程序非常有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值