Android复习——Service

service前言

service是什么?

	1.四大组件之一
	2.没有与任何活动页面牵连
	3.可以在后台进行跨度时间长的工作
	4.在创建他的进程进行,开启耗费时间的工作的时候在分线程

可以干什么?

1.访问网络,文件读写,播放音乐,大数据的数据库操作

特点:

1.不用于页面交互
2.应用退出之后他不会退出
3.默认情况下,在ui线程创建
4.可以开启分线程来应对网络堵塞

理解:

1.与活动区别:
	1.是否与页面交互:       服务:不     活动:交互
	2.应用退出之后的状态:服务:活着  活动:销毁
	3.应用再次进入的状态:服务:不变  活动:重建
2.与分线程区别
	1.时间耗费:服务:时间耗费跨度大。 线程:所耗时间长
	2.应用退出之后的状态:服务:存在 线程:存在
	3.应用再次进入的状态:服务:不变 线程:不是前一个了
	4.所属线程:服务:UI 线程:workthread

PS:分线程属性isBackground:默认为false,当true时候:会与UI同生共死

多线程编程

线程基本用法:3种

1.new Thread(new Runnable(){run{ }})
2.new Thread(new Runnable(){ })
3.new Thread(new Runnable(){ })
        //a.
        new Thread(new Runnable() {
            @Override
            public void run() {
 
            }
        }).start();
 
        //b.
        //service service = new service();
        new service().start();
  public class service extends Thread{
        @Override
        public void run() {
            super.run();
        }
    }
 
        //c.
        service2  service2 = new service2();
        new Thread(service2).start();*/
  public class service2 implements Runnable{
        @Override
        public void run() {
 
   }

子线程中更新UI:

1.Handler:

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    tv_service.setText("nice to meet you");
                    break;
                default:
                    break;
            }
 
        }
    };
  tv_service = findViewById(R.id.tv_service);
        btn_service = findViewById(R.id.btn_service);
        btn_service.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = new Message();
                message.what = 1;
                handler.sendMessage(message);
            }
        });
 

2.AsyncTask:

new Asy().execute();
class Asy extends AsyncTask<Void, Integer, Boolean> {
        @Override
        protected void onPreExecute() {//ui
            super.onPreExecute();
            progressDialog.show();
        }
        @Override
        protected Boolean doInBackground(Void... voids) {//worker
            while (true){
                int down = 10;
                publishProgress(10);
                if(down >= 100)
                    break;
            }
            return true;
        }
 
        @Override
        protected void onPostExecute(Boolean aBoolean) {
            super.onPostExecute(aBoolean);
            progressDialog.dismiss();
        }
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            progressDialog.setMessage(values[0]+"%");
        }
    }
 
3.异步消息处理机制
	1.Message:就是上面handler使用方法
	2.AysncTask:上面那种

服务基本用法

定义一个Service:

1.startService

Intent i = new Intent(MainActivity.this, MyService.class);//启动                
startService(i);

2.stopservie:

Intent i = new Intent(MainActivity.this, MyService.class);//stop
stopService(i);

3.启动停止:
3.1.启动bindservice:

Intent i = new Intent(MainActivity.this, MyService.class);
                //bind
                bindService(i,conn,BIND_AUTO_CREATE);

3.2.停止unbindservice:

Intent i = new Intent(MainActivity.this, MyService.class);
                //unbindService
                unbindService(conn);
 

4.活动和服务通信:通过service中的OnBind

conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                MyService.DownBinder downBinder = (MyService.DownBinder) service;
                downBinder.start();
                downBinder.getprogress();
            }
 
            @Override
            public void onServiceDisconnected(ComponentName name) {
                //
            }
        };
btn_bind_service.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(MainActivity.this, MyService.class);
                //bind
                bindService(i,conn,BIND_AUTO_CREATE);
            }
        });
    private DownBinder mbinder;
    public IBinder onBind(Intent intent) {
        return mbinder;
    }
    class DownBinder extends Binder{
        public void start(){
            Log.d("DownBinder", "start:DownBinder ");
        }
        public int getprogress(){
            Log.d("DownBinder", "start:stop ");
            return 0;
        }
    }

5.前台服务:startForeground

Intent i = new Intent(MyService.this,MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(MyService.this,REQUEST_CODE,i,FLAG);
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("title")
                .setContentText("text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round))
                .setContentIntent(pi)
                .build();
        startForeground(ID,notification);
 

6.IntentService:main里 目的:自动提供开启分线程和自动解绑的

  public class MyIntentService extends IntentService{
//原理:把ibinder包装成了一个msg,oncreate里面自己创建了looper,handler,HandlerThread之类,handlermsg中onHandleIntent,所以onHandleIntent是在分线程工作。
privatefinalclassServiceHandlerextendsHandler{
publicServiceHandler(Looperlooper){
super(looper);
}
 


@Override
publicvoidhandleMessage(Messagemsg){
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
 
        /**
         * Creates an IntentService.  Invoked by your subclass's constructor.
         *
         * @param name Used to name the worker thread, important only for debugging.
         */
        public MyIntentService(String name) {
            super(name);
        }
 
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {//这个是
//耗时
        }
 
        @Override
        public void onCreate() {
            super.onCreate();
        }
 
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    }

服务生命周期

生命周期:

1.Call to startService - >oncreate->onstartCommand->serviceRunning->onDestory

2.Call to bindService - >oncreate->onBind->serviceRunning->onUnbind->onDestory

3.开启startservice+bindService时候怎么完全关:(stopself/stopservice) + unbindservice
startservice:为了长时间开启后台服务,bindService:为了通信
同时开启的生命周期:
手动Startservice->oncreate->onstartcommand->手动bindService->onBind->手动unBindService->onUnbind->手动stopService->onDestory

服务实例–下载

main中

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final int WRITE_REQUEST = 1;
    private Button btn_start;
    private Button btn_pause;
    private Button btn_cancel;
    //private DownloadService downloadService;
 
    private DownloadService.DownloadBinder downloadBinder ;//为了调用service里面的方法,onbind传输数据
 
    private ServiceConnection conn = new ServiceConnection() {//bindservice要传的参数conn,在这从写匿名内部类
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {//活动与服务成功绑定时
            downloadBinder = (DownloadService.DownloadBinder) service;//service向下转型,得到downloadBinder实例
            //绑定成功后在这样得到实例,使活动和服务更加关系紧密
            //没绑定成功如果使用一般的new可能会报错吧
        }
 
        @Override
        public void onServiceDisconnected(ComponentName name) {//活动与服务没有成功绑定时
//
        }
    };
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化
        init();
        btn_start.setOnClickListener(this);
        btn_pause.setOnClickListener(this);
        btn_cancel.setOnClickListener(this);
 
        //创建服务
        Intent i = new Intent(this,DownloadService.class);
        startService(i);//启动服务,为了一直在后台运行
        bindService(i,conn,BIND_AUTO_CREATE);//绑定服务,为了通信  记住!!!第一次都忘写了
 
        //权限申请
        //先判断是否有这个权限
        if(ContextCompat.checkSelfPermission(MainActivity.this
                , Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
        //没有的话,申请一下权限看他同意吗,结果直接跳转到方法onRequestPermissionsResult
            ActivityCompat.requestPermissions(MainActivity.this
                    , new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}
                    ,WRITE_REQUEST);
        }
 
    }
 
    //权限申请结束后自动调用的方法
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
       // super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case WRITE_REQUEST:
                if(grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED ){
                    Toast.makeText(this,"拒绝了",Toast.LENGTH_SHORT).show();
                    //finish();
                }else {
                    Toast.makeText(this,"接受了",Toast.LENGTH_SHORT).show();
                }
            default:
                break;
        }
    }
 
    private void init() {
        btn_start = findViewById(R.id.btn_start);
        btn_pause = findViewById(R.id.btn_pause);
        btn_cancel = findViewById(R.id.btn_cancel);
    }
 
    //活动销毁时记得关绑定
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }
 
    @Override
    public void onClick(View v) {
        if(downloadBinder== null)//..
            return ;
        switch (v.getId()){
            case R.id.btn_start://自己创建一个下载地址,后台服务下载,调用服务的startDownload方法
                String url = "https://raw.githubusercontent.com/guolindev/eclipse/master/eclipse-inst-win64.exe";
                downloadBinder.startDownload(url);
                break;
            case R.id.btn_pause://后台服务停止
                downloadBinder.pauseDownload();
                break;
            case R.id.btn_cancel://后台服务取消
                downloadBinder.cancelDownload();
                break;
            default:
                break;
        }
    }
}

DownloadService中

public class DownloadService extends Service {//控制下载进程,前台通知是否展现,新建通知
    public NotificationManager getNotificationManager(){//为了得到NotificationManager,进行通知的notify
        return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    }
    //NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    private DownloadInterface downloadlistener = new DownloadInterface() {//重写接口方法,这个接口是为了更好的反应下载的结果
        @Override
        public void OnProgress(int progress) {//更新通知,下载的进度
            /*Intent i = new Intent(DownloadService.this,MainActivity.class);
            PendingIntent pi = PendingIntent.getActivity(DownloadService.this,0,i,0);
            Notification notification = new NotificationCompat
                    .Builder(DownloadService.this)
                    .setContentTitle("title")
                    .setContentIntent(pi)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                    .setWhen(System.currentTimeMillis())
                    .build();*/
            getNotificationManager().notify(DOWNLOAD,getNotification("downloading",progress));
        }
        //控制下载进程,前台通知是否展现,新建通知
        @Override
        public void OnSuccess() {//下载结果是成功:
            downloadTask = null;//线程关闭
            stopForeground(true);//停止前台服务
            getNotificationManager().notify(1,getNotification("onsuccess",-1));//更新通知
        }
 
        @Override
        public void OnFailed() {
            downloadTask = null;//线程关闭
            stopForeground(true);//停止前台服务
            getNotificationManager().notify(1,getNotification("onfailed",-1));//更新通知
        }
 
        @Override
        public void OnCanceled() {
            downloadTask = null;//线程关闭
            stopForeground(true);//停止前台服务
            getNotificationManager().notify(1,getNotification("oncanceled",-1));//更新通知
        }
 
        @Override
        public void OnPaused() {
            downloadTask = null;//线程关闭
            //不用停止前台,可能之后会重启下载任务之类的
            getNotificationManager().notify(1,getNotification("oncanceled",-1));//更新通知
        }
    };
    private DownloadTask downloadTask  ;//在AsyncTask中进行耗时任务
    private DownloadBinder mbinder = new DownloadBinder();//自己创建一个类exendsbinder,之后使得活动能调用这个类的方法
    private int DOWNLOAD = 1;
    private String lasturl = null;//下载地址
 
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {//通信
        return mbinder;
    }
 
    public class DownloadBinder extends Binder {//自己创建的类,为了返给onbind方法
        public void startDownload(String url) {//他的点击前的下载状态:暂停/没开始下载。点完btn_start之后调用这个,参数是下载的地址
            if(downloadTask == null){//暂停/没开始下载
                lasturl = url;
                downloadTask = new DownloadTask(downloadlistener);//创建异步任务
                downloadTask.execute(lasturl);//执行
                startForeground(DOWNLOAD,getNotification("startDownload",0));//开启前台服务
            }
        }
 
        public void pauseDownload() {//他的点击前的下载状态:开始。点完btn_pause之后调用这个
            if(downloadTask != null){//下载当前状态不为null,暂停才有意义
                /*downloadTask = new DownloadTask(downloadlistener);
                downloadTask*/
                downloadTask.pauseDownload();//这时候已经经历过上面的startDownload了,所以可以直接调用异步任务的pauseDownload方法
            }
        }
 
        public void cancelDownload() {//他的点击前的下载状态:开始/暂停/没开始下载/下载完的
            if(downloadTask == null){//现在下载状态是   没开始下载/暂停/下载完的  ,则要删除文件
                if(lasturl != null){//下载地址为空说明不用删除啥,现在不为空,进行下面的
                    //得到下载的名字和地址
                    String filename = lasturl.substring(lasturl.lastIndexOf("/"));//名字
                    String path = Environment
                            .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                            .getPath();//地址:在SD卡中,可通过这个语句找到
                    File file = new File(path+filename);//创建文件用这个名字
                    if(file.exists()){//存在就删除,不存在就说明 当前状态是 未开始 就被取消了
                        file.delete();
                    }
                    getNotificationManager().cancel(DOWNLOAD);//这个方法是 通知被取消
                    stopForeground(true);//移除前台服务
                }
            }else{//说明当前下载状态是downloadTask != null正开始之后在下载中
                downloadTask.cancelDownload();
               // stopForeground();
            }
        }
    }
    private Notification getNotification(String title,int progress){//通知,为了简化代码
        Intent i = new Intent(DownloadService.this, MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(DownloadService.this
                ,0,i,0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        builder.setContentTitle(title);//每个调用的地方可能title不同,所以作为参数传入
        builder.setContentIntent(pi);
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
        builder.setWhen(System.currentTimeMillis());
        if(progress > 0){//进度
            builder.setContentText(progress+"%");
            builder.setProgress(100,progress,false);//(最大,现在进度,是否模糊化)
        }
        return builder.build();
    }
 
}

接口中:

public interface DownloadInterface {
    //接口的作用是:规范化代码
    //这几个方法是对结果的回应
 
    void OnProgress(int progress);//显示当前进度
 
    void OnSuccess();//结果是成功
 
    void OnFailed();
 
    void OnCanceled();
 
    void OnPaused();
}

DownloadTask中:

public class DownloadTask extends AsyncTask<String,Integer,Integer> {//异步任务,处理耗时操作
    private DownloadInterface listener;//为了接收服务传入的监听器
   // private DownloadService downloadService;
    private int lastprogress;//最新进度
    public static final int TYPE_SUCEESS = 1;
    public static final  int TYPE_FAILED = 2;
    public static final  int TYPE_CANCELED = 3;
    public static final  int TYPE_PAUSED = 4;
    public DownloadTask(DownloadInterface listener) {//为了传入监听器做的有参
        this.listener = listener;
    }
 
    private boolean isPause = false;//先定义为假
    public void pauseDownload() {//当异步任务在服务中调用了这个方法时,说明main活动按了btn_pause
        isPause = true;//在doInBackground下载任务中就可以暂停了,暂时就不用下载了
    }
    private boolean isCancel = false;//先定义为假
    public void cancelDownload() {//当异步任务在服务中调用了这个方法时,说明main活动按了btn_cancel
        isCancel = true;//在doInBackground下载任务中就可以取消了,就不用下载了
    }
 
    @Override
    protected Integer doInBackground(String... strings) {
        InputStream is = null;//电脑<----别的  所以用is
        RandomAccessFile randomAccessFile = null;//这个是保存下载的文件
        File file = null;//这个是为了判断的文件
        try {
            String downurl = strings[0];//下载地址
            String downurlname = downurl.substring(downurl.lastIndexOf("/"));//名字
            String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();//
 
            file = new File(path + downurlname);
            long correntlength = 0;//当前文件长度
            if(file.exists()){
                //判断之前是否下载过一点,获取当前长度
                correntlength = file.length();
            }//没有文件的话,correntlength就还是0
 
            long successlength = 0;//成功的文件长度,后面在赋正确的值用OkHttpClient
            OkHttpClient okHttpClient = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(downurl)
                    .build();
            Response response = okHttpClient.newCall(request).execute();
            if(response != null && response.isSuccessful()){
                successlength = response.body().contentLength();//得到成功的文件长度
                response.close();//关流
            }
            //现在成功的文件长度不为0了
 
            //对长度进行判断
            if(correntlength == successlength){//下载完了
                return TYPE_SUCEESS;
            }else if(successlength == 0){//没获取的到正确的下载地址,下载的东西没获取到
                return TYPE_FAILED;
            }
 
            //正常下载中 的情况
            OkHttpClient okHttpClient1 = new OkHttpClient();
            Request request1 = new Request.Builder()
                    .url(downurl)
                    .addHeader("RANGE","bytes="+correntlength+"-")//断点处下载
                    .build();
            Response response1 = okHttpClient1.newCall(request1).execute();
            if(response1 != null){//说明获取到了正确的response,可以正常下载了
                is = response1.body().byteStream();
                randomAccessFile = new RandomAccessFile(file,"rw");
                randomAccessFile.seek(correntlength);//找到当前位置下载
 
                //下载
                long total = 0;//这次下载的总长度(不包括correntlength)。每次读取的长度是不一样的
                int len = 0;
                byte[] arr = new byte[1024];
                while ((len = is.read(arr)) != -1){
                    if(isPause){//点了btn_pause
                        return  TYPE_PAUSED;
                    }else if(isCancel){//点了btn_cancel
                        return TYPE_CANCELED;
                    }else{//啥也没点正常运行
                        total += len;
                        randomAccessFile.write(arr,0,len);//写入
                        int progress = (int) ((total + correntlength) *100 / successlength);
                       // listener.OnProgress(progress);
                        publishProgress(progress);//发布进度,这个会自动调用onProgressUpdate方法
                    }
                }
                //下载完了后
                response1.body().close();//关流
                return TYPE_SUCEESS;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{//最后
            try {
                if(is != null){//关流
                    is.close();
                }
                if(randomAccessFile != null){//关流
                    randomAccessFile.close();
                }
                if(isCancel && file != null){//点击btn_cancel的,删除文件
                    file.delete();
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
        return TYPE_FAILED ;
    }
 
    @Override
    protected void onPostExecute(Integer integer) {//对doInBackground的return的处理
        super.onPostExecute(integer);
        switch (integer){//创造新通知,接口通知方法在service里面
            case TYPE_SUCEESS:
                listener.OnSuccess();
                break;
            case TYPE_FAILED:
                listener.OnFailed();
                break;
            case TYPE_CANCELED:
                listener.OnCanceled();
                //break;
            case TYPE_PAUSED:
                listener.OnPaused();//
                break;
            default:
                break;
        }
    }
 
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        int progress = values[0];//values[0]中存在传过来的参数publishProgress(progress);
        if(progress > lastprogress){//!!!
            //更新通知,接口方法在service里面
            //为什么在service中是因为,他要对异步任务进行null,在本类的重写的话不能进行这个操作
            listener.OnProgress(progress);//发布任务,服务的OnProgress那边会更新通知
            lastprogress = progress;//最新进度更新为 传来的最新进度
        }
    }
}

面试

1.1 注册Service需要注意什么
Service还是运行在主线程当中的,所以如果需要执行一些复杂的逻辑操作,最好在服务的内部手动创建子线程(AysncTask)进行处理,否则会出现UI线程被阻塞的问题

1.2 Service与Activity怎么实现通信:类extends Binder 这个类的对象给onbind
第一种方式:通过MyBinder方式调用Service方法:serviceconnection那向下转型变成的是MyBinder类型
第二种方式:通过接口Iservice调用Service方法 多了个接口:serviceconnection那向下转型变成的是Iservice类型

1.3 介绍源码中Binder机制(了解)(不太懂)
面试问到这个,其实就是让你说一下binder是干什么的,Service Manager是如何成为一个守护进程的
Binder是干什么的
Binder – 一种进程间通信(IPC)机制, 基于OpenBinder
1.Client、Server和Service Manager实现在用户空间中,Binder驱动程序实现在内核空间中
2.Binder驱动程序和Service Manager在Android平台中已经实现,开发者只需要在用户空间实现自己的Client和Server
3.Binder驱动程序提供设备文件/dev/binder与用户空间交互,Client、Server和Service Manager通过open和ioctl文件操作函数与Binder驱动程序进行通信
4.Client和Server之间的进程间通信通过Binder驱动程序间接实现
5.Service Manager是一个守护进程,用来管理Server,并向Client提供查询Server接口的能力

1.Service Manager是如何成为一个守护进程的?即Service Manager是如何告知Binder驱动程序它是Binder机制的上下文管理者。
Service Manager,它是整个Binder机制的守护进程,用来管理开发者创建的各种Server,并且向Client提供查询Server远程接口的功能
既然Service Manager组件是用来管理Server并且向Client提供查询Server远程接口的功能,那么,Service Manager就必然要和Server以及Client进行通信了。我们知道,Service Manger、Client和Server三者分别是运行在独立的进程当中,这样它们之间的通信也属于进程间通信了,而且也是采用Binder机制进行进程间通信,因此,Service Manager在充当Binder机制的守护进程的角色的同时,也在充当Server的角色,然而,它是一种特殊的Server,下面我们将会看到它的特殊之处
Service Manager在用户空间的源代码位于frameworks/base/cmds/servicemanager目录下,主要是由binder.h、binder.c和service_manager.c三个文件组成。Service Manager的入口位于service_manager.c文件中的main函数:
int main(int argc, char **argv)
{
struct binder_state *bs;
void svcmgr = BINDER_SERVICE_MANAGER;
bs = binder_open(128
1024);
if (binder_become_context_manager(bs)) {
LOGE(“cannot become context manager (%s)\n”, strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}
main函数主要有三个功能:一是打开Binder设备文件;二是告诉Binder驱动程序自己是Binder上下文管理者,即我们前面所说的守护进程;三是进入一个无穷循环,充当Server的角色,等待Client的请求

2.Server和Client是如何获得Service Manager接口的?即defaultServiceManager接口是如何实现的。
ServiceManager 作为守护进程,Service Manager的职责当然就是为Server和Client服务了。那么,Server和Client如何获得Service Manager接口,进而享受它提供的服务呢?
Service Manager在Binder机制中既充当守护进程的角色,同时它也充当着Server角色,然而它又与一般的Server不一样。对于普通的Server来说,Client如果想要获得Server的远程接口,那么必须通过Service Manager远程接口提供的getService接口来获得,这本身就是一个使用Binder机制来进行进程间通信的过程。而对于Service Manager这个Server来说,Client如果想要获得Service Manager远程接口,却不必通过进程间通信机制来获得,因为Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0。
经过一系列的调用…
回到defaultServiceManager函数中,最终结果为:
gDefaultServiceManager = new BpServiceManager(new BpBinder(0));
这样,Service Manager远程接口就创建完成了,它本质上是一个BpServiceManager,包含了一个句柄值为0的Binder引用。
在Android系统的Binder机制中,Server和Client拿到这个Service Manager远程接口之后怎么用呢?
对Server来说,就是调用IServiceManager::addService这个接口来和Binder驱动程序交互了,即调用BpServiceManager::addService 。而BpServiceManager::addService又会调用通过其基类BpRefBase的成员函数remote获得原先创建的BpBinder实例,接着调用BpBinder::transact成员函数。在BpBinder::transact函数中,又会调用IPCThreadState::transact成员函数,这里就是最终与Binder驱动程序交互的地方了。回忆一下前面的类图,IPCThreadState有一个PorcessState类型的成中变量mProcess,而mProcess有一个成员变量mDriverFD,它是设备文件/dev/binder的打开文件描述符,因此,IPCThreadState就相当于间接在拥有了设备文件/dev/binder的打开文件描述符,于是,便可以与Binder驱动程序交互了。
对Client来说,就是调用IServiceManager::getService这个接口来和Binder驱动程序交互了。具体过程上述Server使用Service Manager的方法是一样的,这里就不再累述了。

1.4 IntentService与Service的区别(intentservice的优点)
IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
会创建独立的worker线程来处理所有的Intent请求;
会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
为Service的onBind()提供默认实现,返回null;
为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;
IntentService不会阻塞UI线程,而普通Serveice会导致ANR异常
Intentservice若未执行完成上一次的任务,将不会新开一个线程,是等待之前的任务完成后,再执行新的任务,等任务完成后再次调用stopSelf()

1.5 Service 是否在 main thread 中执行, service 里面是否 能执行耗时的操作?
默认情况,如果没有显示的指 service 所运行的进程, Service 和 activity 是运 行在当前 app 所在进程的 main thread(UI 主线程)里面。

service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )

特殊情况 ,可以在清单文件配置 service 执行所在的进程 ,让 service 在另 外的进程中执行

1.6 Service的生命周期
Service 有绑定模式和非绑定模式,以及这两种模式的混合使用方式。不同 的使用方法生命周期方法也不同。

非绑定模式:当第一次调用 startService 的时候执行的方法依次为 onCreate()、onStartCommand(),当 Service 关闭的时候调用 onDestory 方 法。

绑定模式:第一次 bindService()的时候,执行的方法为 onCreate()、 onBind()解除绑定的时候会执行 onUnbind()、onDestory()。

上面的两种生命周期是在相对单纯的模式下的情形。我们在开发的过程中还 必须注意 Service 实例只会有一个,也就是说如果当前要启动的 Service 已经存在了那么就不会再次创建该 Service 当然也不会调用 onCreate()方法。

一个 Service 可以被多个客户进行绑定,只有所有的绑定对象都执行了unBind()方法后该 Service才会销毁,不过如果有一个客户执行了onStart方法,那么这个时候如果所有的 bind 客户都执行了 unBind()该Service也不会销毁。

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

1.8 Service 和 Activity 在同一个线程吗?
对于同一 app 来说默认情况下是在同一个线程中的,main Thread (UI Thread)。

1.9 在 service 的生命周期方法 onstartConmand()可不可以执行网络操作?如何在 service 中执行网络操作?(在service如何执行耗时操作)
可以直接在 Service 中执行网络操作,在 onStartCommand()方法中可以执行网络操作
如果需要在服务中进行耗时操作,可以选择IntentService, IntentService是Service的子类,用来处理异步请求。
IntentService在onCreate()方法中通过HandlerThread单独开启一个线程来处理Intent请求对象所对应的任务,这样可以避免事务处理阻塞主线程。
onHandleIntent()函数针对Intent的不同进行不同的事务处理就可以,执行完一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动停止Service; 否则ServiceHandler会取得下一个Intent请求
传入该函数来处理其所对应的任务。

2.0 如何提高service的优先级? (理解,说出两三条就很nB了)
参考文章

1、在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时实用于广播。

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

3、onStartCommand方法,手动返回START_STICKY。

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

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

6、Application加上Persistent(持久的)属性。

2.1 Service 的 onStartCommand 方法有几种返回值?各代表什么意思?
有4种返回值,不同值代表的意思如下:

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 后一定能重启。

2.2 Service 的 onRebind(Intent)重新绑定方法在什么情况下会执行?
如果在 onUnbind()方法返回 true 的情况下会执行,否则不执行。

2.3 Activity 调用 Service 中的方法都有哪些方式?
Binder:
通过 Binder 接口的形式实现,当 Activity 绑定 Service 成功的时候 Activity 会在 ServiceConnection 的类 的 onServiceConnected()回调方法中获取到 Service 的 onBind()方法 return 过来的 Binder 的子类,然后通过对象调用方法。
Aidl:
aidl 比较适合当客户端和服务端不在同一个应用下的场景。
Messegener:
它引用了一个Handler对象,以便others能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通信(即两个进程间可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。一个Messeger不能同时双向发送,两个就就能双向发送了

Service里面可以弹Toast么?
面试经验:
可以弹Toast还能弹出对话框,把Service看成Activity就行,所有的界面都是展示到Window窗体上面的。
答案解析:
可以的。弹吐司有个条件就是得有一个Context上下文,而Service本身就是Context的子类,因此在Service里面弹Toast是完全可以的。比如我们在Service中完成下载任务后可以弹一个Toast通知用户。

你一般在什么情况下会使用Service?
经验总结:

Service其实就是背地搞事情,又不想让别人知道,你想知道一件事情不需要直接去问,你可以通过侧面了解。这就是Service设计的初衷

Service为什么被设计出来?

根据Service的定义,我们可以知道需要长期在后台进行的工作我们需要将其放在Service中去做。说得再通熟易懂一点,就是不能放在Activity中来执行的工作就必须得放到Service中去做。如:音乐播放、下载、上传大文件、定时关闭应用等功能。这些功能如果放到Activity中做的话,那Activity退出被销毁了的话,那这些功能也就停止了,这显然是不符合我们的设计要求的,所以要将他们放在Service中去执行。

Activity怎么和service绑定,怎么在activity中启动自己对应的service?
答案解析:

Activity通过bindService(Intent service, ServiceConnection conn, int flags)跟Service进行绑定。
绑定成功以后,Service会将代理对象通过回调的形式传递给ServiceConnection,这样我们就获取Service提供的代理对象
在Activity中可以通过startService和bindService方法启动Service。
注意: 如果想获取Service中提供的代理对象,那么必须通过bindService方法,进行绑定服务。
使用场景比如:音乐播放器,第三方支付等。

如果仅仅只是为了开启一个后台任务,那么可以使用startService方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值