Android 面试题之Service干货篇

简介: 一、Service是什么二、Service启动方式startService1.启动Service2.停止servicebindService1.使用bindService()方法启动Service2.使用unbindService()方法取消绑定startService样例bindService样例三、Service生命周期startService启动的生命周期bindService启动的生命周期四、Service和Thread的区别五、使用IntentServiceIntentService的特点:IntentService实例

本文前面先看看针对这个知识点会有哪些会在面试中出现,先对题目了解一下。后面会针对Service没有被问到的内容再次进行系统的学习。


微信图片_20220520110044.png

一、Service是什么


       Service是Android四大组件之一,它可以在后台执行长时间运行操作而没有用户界面的应用组件。


       Service的启动方式有两种:startService启动和bindService启动。


      注意:服务与其他应用程序对象一样,在其托管进程的主线程中运行。这意味着,如果你的服务要执行任何CPU密集型(例如 MP3 播放)或阻塞(例如网络)操作,它应该在Service中再创建一个子线程,然后在这里去处理耗时操作就没问题了。


二、Service启动方式


startService


1.启动Service


       显式启动通过类名称来启动,需要在Intent中指明Service所在的类,并调用startService (lntent)启动service,显式启动代码如下:


final Intent intentStart = new Intent(ServiceActivity.this, StartService.class);
 startService(intentStart);


在上面的代码中,Intent指明了启动的Service所在类为StartService。


      「通过该方式启动Service,访问者与Service之间没有关联,即使访问者退出了,Service也仍然运行。」

2.停止service


       显式启动停止Service,需要将启动Service的Intent传递给stopService (Intent)函数,代码如下:


stopService(intentStart);


「因Android5.0开始,Google要求必须使用显示Intent启动Service,所以隐式启动咱就不介绍了。」


bindService


1.使用bindService()方法启动Service


绑定模式使用bindService()方法启动Service,其格式如下:

其中的参数说明如下:


service:该参数通过Intent指定需要启动的service。


conn:该参数是ServiceConnnection对象,当绑定成功后,系统将调用serviceConnnection的onServiceConnected ()方法,当绑定意外断开后,系统将调用ServiceConnnection中的onServiceDisconnected方法。


flags:该参数指定绑定时是否自动创建Service。如果指定为BIND_AUTO_CREATE,则自动创建,指定为0,则不自动创建。


       绑定方式中,当调用者通过bindService()函数绑定Service时,onCreate()函数和onBinde ( )函数将被先后调用。


「通过该方式启动Service,访问者与Service绑定在一起,访问者一旦退出了,Service也就终止了。」


2.使用unbindService()方法取消绑定


       取消绑定仅需要使用unbindService()方法,并将ServiceConnnection传递给unbindService()方法。


       但需要注意的是,unbindService()方法成功后,系统并不会调用onServiceConnected(),因为onServiceConnected()仅在意外断开绑定时才被调用。


       当调用者通过unbindService()函数取消绑定Service时,onUnbind()函数将被调用。如果onUnbind()函数返回true,则表示重新绑定服务时,onRebind ()函数将被调用。


startService样例


1.创建StartService.java继承自Service类,重写onCreate()方法、onStartCommand()方法、onBind()方法、onDestroy()方法,其代码如下:


public class StartService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        MLog.e(getClass().getName(), "onCreate");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MLog.e(getClass().getName(), "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public void onDestroy() {
        MLog.e(getClass().getName(), "onDestroy");
        super.onDestroy();
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}


  • 2.创建ServiceActivity.java和配套的activity_service.xml文件,其代码如下:


1.public class ServiceActivity extends ActivityBase {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service);
        Intent intentStart = new Intent(ServiceActivity.this, StartService.class);
        findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startService(intentStart);
            }
        });
        findViewById(R.id.btn_stop).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intentStart);
            }
        });
    }
}


配套的activity_service.xml文件


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_bg"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/color_666666">
    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start启动服务"/>
    <Button
        android:id="@+id/btn_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start停止服务"/>
</LinearLayout>


3.添加Service组件声明,在AndroidManifest.xml文件中声明一个Service组件,其代码如下:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.scc.demo">
    <application
        ...>
        <activity
           ...>
            <intent-filter>
                ...
            </intent-filter>
        </activity>
        <service android:name=".service.StartService"/>
    </application>
</manifest>


运行结果


07-07 16:41:11.474 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonCreate
07-07 16:41:11.481 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonStart
07-07 16:41:11.482 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonResume
07-07 16:41:13.313 E/-SCC-com.scc.demo.service.StartService: onCreate
07-07 16:41:13.334 E/-SCC-com.scc.demo.service.StartService: onStartCommand
07-07 16:41:16.705 E/-SCC-com.scc.demo.service.StartService: onDestroy


bindService样例


  • 1.创建BindService.java继承自Service类,重写onCreate()方法、onBind()方法、onUnbind()方法、onDestroy()方法,实现本地通知栏显示,其代码如下:


1.public class BindService extends Service {
    //声明IBinder接口的一个接口变量mBinder
    public final IBinder mBinder = new LocalBinder();
    private NotificationManager mNM;
    private int NOTIFICATION = R.string.local_service_started;
    //LocalBinder是继承Binder的一个内部类
    public class LocalBinder extends Binder {
        public BindService getService() {
            return BindService.this;
        }
    }
    @Override
    public void onCreate() {
        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
        MLog.e(getClass().getName(), "onCreate");
        showNotification();
    }
    @Override
    public void onDestroy() {
        MLog.e(getClass().getName(), "onDestroy");
        mNM.cancel(NOTIFICATION);
        Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
    }
    @Override
    public IBinder onBind(Intent intent) {
        MLog.e(getClass().getName(), "onBind");
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        MLog.e(getClass().getName(), "onUnbind");
        return super.onUnbind(intent);
    }
    private void showNotification() {
        CharSequence text = getText(R.string.local_service_started);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, ServiceActivity.class), 0);
        Notification notification = new Notification.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setTicker(text)
                .setWhen(System.currentTimeMillis())
                .setContentTitle(getText(R.string.local_service_label))
                .setContentText(text)
                .setContentIntent(contentIntent)
                .build();
        mNM.notify(NOTIFICATION, notification);
        MLog.e(getClass().getName(), "通知栏已出");
    }
}


  • 2.创建ServiceActivity.java和配套的activity_service.xml文件,其代码如下:


1.public class ServiceActivity extends ActivityBase {
    private BindService bindService;
    private boolean isBind = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service);
        findViewById(R.id.btn_bind).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isBind) {
                    Intent intentBind = new Intent(ServiceActivity.this, BindService.class);
                    bindService(intentBind, serviceConnection, Context.BIND_AUTO_CREATE);
                    isBind = true;
                }
            }
        });
        findViewById(R.id.btn_unbing).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isBind) {
                    isBind = false;
                    unbindService(serviceConnection);
                    bindService = null;
                }
            }
        });
    }
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MLog.e(getClass().getName(), "onServiceConnected");
            bindService = ((BindService.LocalBinder) service).getService();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            MLog.e(getClass().getName(), "onServiceDisconnected");
            bindService = null;
        }
    };
}


配套的activity_service.xml文件


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll_bg"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/color_666666">
    <Button
        android:id="@+id/btn_bind"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="bind服务绑定"/>
    <Button
        android:id="@+id/btn_unbing"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="bind解除绑定"/>
</LinearLayout>


3.添加Service组件声明,在AndroidManifest.xml文件中声明一个Service组件,其代码如下:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.scc.demo">
    <application
        ...>
        <activity
           ...>
            <intent-filter>
                ...
            </intent-filter>
        </activity>
        <service android:name=".service.BindService"/>
    </application>
</manifest>


4运行结果


07-07 17:00:04.309 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonCreate
07-07 17:00:04.350 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonStart
07-07 17:00:04.350 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonResume
07-07 17:00:10.088 E/-SCC-com.scc.demo.service.BindService: onCreate
07-07 17:00:10.120 E/-SCC-com.scc.demo.service.BindService: 通知栏已出
07-07 17:00:10.145 E/-SCC-com.scc.demo.service.BindService: onBind
07-07 17:00:10.164 E/-SCC-com.scc.demo.actvitiy.ServiceActivity$5: onServiceConnected
07-07 17:00:39.111 E/-SCC-com.scc.demo.service.BindService: onUnbind
07-07 17:00:39.134 E/-SCC-com.scc.demo.service.BindService: onDestroy


微信图片_20220520111005.png


三、Service生命周期


微信图片_20220520111040.png


「onBind()」 是Service必须实现的方法,返回的IBinder对象相当于Service组件的代理对象,Service允许其他程序组件通过IBinder对象来访问Service内部数据,这样即可实现其他程序组件与Service之间的通信。


startService启动的生命周期


「onCreate()」 当Service第一次被创建时,由系统调用。


「onStartCommand()」 当startService方法启动Service时,该方法被调用。


「onDestroy()」 当Service不再使用时,由系统调用。


注意:一个startService只会创建一次,销毁一次,但可以开始多次,因此,onCreate()和onDestroy()方法只会被调用一次,而onStart()方法会被调用多次。


bindService启动的生命周期


「onCreate()」 当Service被创建时,由系统调用。


「onBind()」 当bindService方法启动Service时,该方法被调用。


「onUnbind()」 当unbindService方法解除绑定时,该方法被调用。


「onDestroy()」 当Service不再使用时,由系统调用。


注意:一个bindService可以创建多次,销毁多次,重复使用。


四、Service和Thread的区别


Service是安卓中系统的组件,它运行在独立进程的主线程中,不可以执行耗时操作。


Thread是程序执行的最小单元,分配CPU的基本单位,可以开启子线程执行耗时操作。


Service在不同Activity中可以获取自身实例,可以方便的对Service进行操作。


Thread在不同的Activity中难以获取自身实例,如果Activity被销毁,Thread实例就很难再获取得到。


五、使用IntentService


IntentService是 Scrvice 的子类,因此它不是普通的Service,它比普通的Service增加了额外的功能。


先看Service本身存在的两个问题。


  • Service不会专门启动一个单独的进程,Service与它所在应用位于同一个进程中。


  • Service不是一条新的线程,因此不应该在Service中直接处理耗时的任务。


IntentService正好弥补了Service的不足。


IntentService的特点:


  • IntentService会创建单独的worker线程来处理所有的Intent请求。


  • IntentService会创建单独的worker线程来处理onHandleIntent()方法实现的代码,因此开发者无须处理多线程问题。


IntentService实例


  • 1.创建SccIntentService.java继承自IntentService类,重写onHandleIntent()方法、创建一个无参构造函数,其代码如下:


public class SccIntentService extends IntentService {
    public SccIntentService() {
        super("SccIntentService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        MLog.e(getClass().getName(), "onHandleWork");
        for (int i = 0; i < 3; i++) {
            try {
                MLog.e(getClass().getName(), "Number:开始"+i);
                Thread.sleep(10000);
                MLog.e(getClass().getName(), "Number:结束"+i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        MLog.e(getClass().getName(), "onDestroy");
    }
}


  • 2、添加IntentService组件声明,在AndroidManifest.xml文件中声明一个Service组件,其代码如下:



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


  • 3、启动SccIntentService


startService(new Intent(ServiceActivity.this, SccIntentService.class));


  • 4、运行结果


07-07 18:00:39.505 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonCreate
07-07 18:00:39.531 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonStart
07-07 18:00:39.531 E/-SCC-: com.scc.demo.actvitiy.ServiceActivityonResume
07-07 18:01:12.690 E/-SCC-com.scc.demo.service.SccIntentService: onHandleWork
07-07 18:01:12.690 E/-SCC-com.scc.demo.service.SccIntentService: Number:开始0
07-07 18:01:22.691 E/-SCC-com.scc.demo.service.SccIntentService: Number:结束0
07-07 18:01:22.697 E/-SCC-com.scc.demo.service.SccIntentService: Number:开始1
07-07 18:01:32.698 E/-SCC-com.scc.demo.service.SccIntentService: Number:结束1
07-07 18:01:32.698 E/-SCC-com.scc.demo.service.SccIntentService: Number:开始2
07-07 18:01:42.699 E/-SCC-com.scc.demo.service.SccIntentService: Number:结束2
07-07 18:01:42.716 E/-SCC-com.scc.demo.service.SccIntentService: onDestroy


普通Service直接执行20S的的耗时操作,会阻塞主线程,造成ANR(程序无响应)异常。


  • IntentService执行30S的耗时操作,不会阻塞主线程,更不会产生ANR。如上图开始18:01:12>18:01:42长达30S,正常运行未产生ANR。


  • IntentService还有个好处就是 「用完即走」。执行完onHandleIntent()方法里面的耗时操作后,自行调用onDestroy()方法,进行关闭。


相关文章
|
18天前
|
Android开发 Kotlin
Android经典面试题之Kotlin的==和===有什么区别?
本文介绍了 Kotlin 中 `==` 和 `===` 操作符的区别:`==` 用于比较值是否相等,而 `===` 用于检查对象身份。对于基本类型,两者行为相似;对于对象引用,`==` 比较值相等性,`===` 检查引用是否指向同一实例。此外,还列举了其他常用比较操作符及其应用场景。
171 93
|
21天前
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
40 20
Android经典面试题之图片Bitmap怎么做优化
|
9天前
|
消息中间件 Android开发 索引
Android面试高频知识点(4) 详解Activity的启动流程
讲解Activity的启动流程了,Activity的启动流程相对复杂一下,涉及到了Activity中的生命周期方法,涉及到了Android体系的CS模式,涉及到了Android中进程通讯Binder机制等等, 首先介绍一下Activity,这里引用一下Android guide中对Activity的介绍:
25 4
|
15天前
|
缓存 Android开发 开发者
Android RecycleView 深度解析与面试题梳理
本文详细介绍了Android开发中高效且功能强大的`RecyclerView`,包括其架构概览、工作流程及滑动优化机制,并解析了常见的面试题。通过理解`RecyclerView`的核心组件及其优化技巧,帮助开发者提升应用性能并应对技术面试。
40 8
|
15天前
|
存储 缓存 Android开发
Android RecyclerView 缓存机制深度解析与面试题
本文首发于公众号“AntDream”,详细解析了 `RecyclerView` 的缓存机制,包括多级缓存的原理与流程,并提供了常见面试题及答案。通过本文,你将深入了解 `RecyclerView` 的高性能秘诀,提升列表和网格的开发技能。
39 8
|
12天前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
30 2
|
9天前
|
Android开发 开发者
Android面试之Activity启动流程简述
每个Android开发者都熟悉的Activity,但你是否了解它的启动流程呢?本文将带你深入了解。启动流程涉及四个关键角色:Launcher进程、SystemServer的AMS、应用程序的ActivityThread及Zygote进程。核心在于AMS与ActivityThread间的通信。文章详细解析了从Launcher启动Activity的过程,包括通过AIDL获取AMS、Zygote进程启动以及ActivityThread与AMS的通信机制。接着介绍了如何创建Application及Activity的具体步骤。整体流程清晰明了,帮助你更深入理解Activity的工作原理。
16 0
|
2月前
|
消息中间件 存储 Java
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
Android 消息处理机制估计都被写烂了,但是依然还是要写一下,因为Android应用程序是通过消息来驱动的,Android某种意义上也可以说成是一个以消息驱动的系统,UI、事件、生命周期都和消息处理机制息息相关,并且消息处理机制在整个Android知识体系中也是尤其重要,在太多的源码分析的文章讲得比较繁琐,很多人对整个消息处理机制依然是懵懵懂懂,这篇文章通过一些问答的模式结合Android主线程(UI线程)的工作原理来讲解,源码注释很全,还有结合流程图,如果你对Android 消息处理机制还不是很理解,我相信只要你静下心来耐心的看,肯定会有不少的收获的。
118 3
Android面试高频知识点(2) 详解Android消息处理机制(Handler)
|
2月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
View的绘制和事件处理是两个重要的主题,上一篇《图解 Android事件分发机制》已经把事件的分发机制讲得比较详细了,这一篇是针对View的绘制,View的绘制如果你有所了解,基本分为measure、layout、draw 过程,其中比较难理解就是measure过程,所以本篇文章大幅笔地分析measure过程,相对讲得比较详细,文章也比较长,如果你对View的绘制还不是很懂,对measure过程掌握得不是很深刻,那么耐心点,看完这篇文章,相信你会有所收获的。
80 2
下一篇
无影云桌面