美文网首页
Android service

Android service

作者: 编程_书恨少 | 来源:发表于2020-09-16 15:17 被阅读0次

    1.创建一个简单的服务

    1.创建一个类,继承自service

    public class SimpleService extends Service {
    
        public SimpleService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            Log.v("myApp", "SimpleService onCreate");
    
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.v("myApp", "SimpleService onDestroy");
        }
    }
    

    2.在Manifest中只需要注册service类就可以了

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

    3.在activity中启动或者停止服务

    private void initButton1() {
            Button button1 = (Button) findViewById(R.id.button1);
            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, SimpleService.class);
                    startService(intent);
                }
            });
        }
    
        private void initButton2() {
            Button button2 = (Button) findViewById(R.id.button2);
            button2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, SimpleService.class);
                    stopService(intent);
                }
            });
        }
    

    2.服务和子线程的区别
    1.线程是需要依赖app进程而存在的,如果app进程被杀死了,那么线程的内存也就被回收了,线程也会死
    2.服务咋爱杀死app的时候也会被杀死,但是之后会重新启动

    1.现象:同样应用程序被关闭了 线程同时被杀死 如果是服务(先被杀死 然后重新启动)
    2.本质:服务是一个安卓组件 (先被杀死 然后重新启动):
    系统认为服务之所以被杀死 是因为当前应用的进程被杀死 可能是因为内存不足而造成 它会重新启动服务

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            new Thread(){
                @Override
                public void run() {
                    super.run();
    
                    while (true) {
                        SystemClock.sleep(3000);
                        Log.v("myApp", "线程还在运行中...");
                    }
                }
            }.start();
    }
    
    public class SimpleService extends Service {
        int i = 0;
    
        public SimpleService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
    
    
            new Timer().schedule(new TimerTask() {
                @Override
                public void run() {
    
                    i = i + 1;
                    Log.v("myApp", "服务还在进行着...." + i);
    
                }
            }, 2000, 3000);
    
        }
    }
    

    3.接收开机广播,开启监听手机服务

    1.注册接收系统开机广播的接收者

    <receiver
                android:name=".BootReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
            </receiver>
    

    2.接收到广播的时候,开启监听服务

    public class BootReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            
            Intent serviceIntent = new Intent(context, CallService.class);
            context.startService(serviceIntent);
        }
    }
    
    

    3.服务开始监听手机通话并录音

    public class CallService extends Service {
    
        private MediaRecorder mRecorder;
    
    
        public CallService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
    
            Log.v("myApp", "开机启动监听服务");
    
    
            final TelephonyManager manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            manager.listen(new PhoneStateListener() {
    
                private String mIncomingNumber="";
                private boolean mIsRecording;
    
                @Override
                public void onCallStateChanged(int state, String incomingNumber) {
                    super.onCallStateChanged(state, incomingNumber);
    
                    switch (manager.getCallState()) {
                        case TelephonyManager.CALL_STATE_IDLE:
                            Log.v("myApp", "休闲(没有电话)/挂断:" + incomingNumber);
                            if (mRecorder!=null&&mIsRecording) {
                                mRecorder.stop();
                                mRecorder.release();
                                mRecorder = null;
                                mIsRecording=false;
                            }
                            break;
                        case TelephonyManager.CALL_STATE_OFFHOOK:
                            Log.v("myApp", "接通 :" + incomingNumber);
                            //MediaRecorder 录音
                            mRecorder = new MediaRecorder();
                            //设置音频的来源     MIC DEFAULT开发的时候
                            //真实打电话  VOICE_DOWNLINK/VOICE_UPLINK
                            //VOICE_CALL既能听到自己的声音 也能听到别人的声音
                            mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                            //录音之后要形成一个音频文件 音频的后缀是   .3gp   .mp3  .mp4
                            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                            //设置录音的文件保存到什么地方
                            mRecorder.setOutputFile(getRecordFilePath(mIncomingNumber));
                            //设置音频内部解码
                            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                            try {
                                mRecorder.prepare();
                            } catch (IOException e) {
    
                            }
                            mRecorder.start();
                            mIsRecording=true;
                            break;
                        case TelephonyManager.CALL_STATE_RINGING:
                            Log.v("myApp", "来电:" + incomingNumber);
                            mIncomingNumber=incomingNumber;
                            break;
                    }
                }
            }, 1);
        }
    
        /**
         * 获取文件的路径
         */
        private String getRecordFilePath(String phone){
            //文件名的格式    电话号码+"#"时间+".3gp"
            SimpleDateFormat formatter=new SimpleDateFormat("yy-MM-dd hh:mm");
            String fileName=phone+"#"+formatter.format(new Date())+".3gp";
            File file=new File(getFilesDir(),fileName);
            return file.getAbsolutePath();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    }
    

    4.动态注册广播接收者,监听开屏和锁屏

    动态注册锁屏开屏的广播接收者

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            ScreenReceiver screenReceiver = new ScreenReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(Intent.ACTION_SCREEN_ON);
            intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
            intentFilter.addAction(Intent.ACTION_USER_PRESENT);
    
            registerReceiver(screenReceiver, intentFilter);
        }
    }
    
    
    public class ScreenReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO: This method is called when the BroadcastReceiver is receiving
            // an Intent broadcast.
    
            Log.v("myApp", "000");
    
            if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
                Log.v("myApp", "开屏");
            } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())){
                Log.v("myApp", "锁屏");
            }
        }
    }
    

    5.进程等级
    Android系统会尽量的长期保存每一个进程不被回收。

    • 这样 第二次开启界面后就会发现启动速度比以前快了 这是因为系统已经创建了一个进程 没有被杀死 这次启动就不用再重新创建。
    • 但是 当内存不足的时候 系统就要杀掉一些老的进程 就要考虑杀进程的策略了。

    系统定义了进程的优先级
    1.Foreground progress 前台进程
    用户在操作的应用程序所在的进程是前台进程
    2.Visible progress 可见进程
    用户仍然可以看到界面 但是里面的按钮点击不了了
    3.Service progress 服务进程
    进程里面有一个服务处于运行的状态
    4.Background progress 后台进程
    如果一个应用程序没有服务处于运行状态 界面最小化
    5.Empty progress 空进程
    应用程序没有任何活动的组件(界面或者服务)

    6.使用绑定服务的方式和service进行通信
    原因:因为在activity中启动服务时,是系统利用反射的方式将service实例化之后启动的,所以如果在activity中需要和service进行交互,那么是得不到service的实例的。这样的情况下就有了onBindService绑定服务。绑定服务会在service中创建一个类似管家是内部类在activity绑定service的时候,返回给activity使用,用来和service进行通讯。

    public class MainActivity extends AppCompatActivity {
    
        private MyService.MyBinder myBinder;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initButtonStartService();
            initButtonConnService();
        }
    
    
        private void initButtonStartService() {
            Button button = (Button) findViewById(R.id.button_startService);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    Intent intent = new Intent(MainActivity.this, MyService.class);
                    bindService(intent, new ServiceConnection() {
    
                        // 绑定成功之后,回调的方法
                        @Override
                        public void onServiceConnected(ComponentName name, IBinder service) {
                            myBinder = (MyService.MyBinder) service;
                        }
    
                        // 解绑成功之后,回调的方法
                        @Override
                        public void onServiceDisconnected(ComponentName name) {
    
                        }
                    }, BIND_AUTO_CREATE);
                }
            });
        }
    
        private void initButtonConnService() {
            Button button = (Button) findViewById(R.id.button_connService);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    myBinder.showToast();
                }
            });
        }
    }
    
    public class MyService extends Service {
        public MyService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.v("myApp", "服务创建");
        }
    
        // 服务开启
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.v("myApp", "服务开始");
    
            return super.onStartCommand(intent, flags, startId);
        }
    
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.v("myApp", "服务销毁");
    
        }
    
    
        // 进行外部通讯的内部类
        public class MyBinder extends Binder{
            public void showToast(){
    
                // 这里可以调用服务的方法,实现和服务的交互和通讯
                MyService.this.showToast();
            }
        }
    
        // 服务绑定
        @Override
        public IBinder onBind(Intent intent) {
    
            Log.v("myApp", "服务绑定");
    
            return new MyBinder();
        }
    
    
        private void showToast() {
    
            Toast.makeText(MyService.this, "调用了服务里的方法", Toast.LENGTH_SHORT).show();
        }
    }
    

    使用代理来进行限制
    上面这样写其实是不规范的,因为MyBinder这个类中还可以偷偷实现其他的方法供外部调用,而无法规范MyBinder的行为,这种情况下就需要使用到接口来限制MyBinder的权限,让外部的activity不能随意调用MyBinder中的方法。
    这样将MyBinder这个内部类私有化,让外部调用时只能通过接口来调用方法,起到了对外部的限制

    public class MainActivity extends AppCompatActivity {
    
        private IMyService myBinder;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initButtonStartService();
            initButtonConnService();
        }
    
    
        private void initButtonStartService() {
            Button button = (Button) findViewById(R.id.button_startService);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    Log.v("myApp", "点击开始绑定按钮");
    
                    Intent intent = new Intent(MainActivity.this, MyService.class);
                    bindService(intent, new ServiceConnection() {
    
                        // 绑定成功之后,回调的方法
                        @Override
                        public void onServiceConnected(ComponentName name, IBinder service) {
                            myBinder = (IMyService) service;
                        }
    
                        // 解绑成功之后,回调的方法
                        @Override
                        public void onServiceDisconnected(ComponentName name) {
    
                        }
                    }, BIND_AUTO_CREATE);
                }
            });
        }
    
        private void initButtonConnService() {
            Button button = (Button) findViewById(R.id.button_connService);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    myBinder.callShowToast();
                }
            });
        }
    }
    
    // 用来限制MyService中MyBinder的协议
    public interface IMyService {
        void callShowToast();
    }
    
    
    public class MyService extends Service {
        public MyService() {
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.v("myApp", "服务创建");
        }
    
        // 服务开启
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.v("myApp", "服务开始");
    
            return super.onStartCommand(intent, flags, startId);
        }
    
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.v("myApp", "服务销毁");
    
        }
    
    
        // 进行外部通讯的内部类
        private class MyBinder extends Binder implements IMyService {
    
            @Override
            public void callShowToast() {
                // 这里可以调用服务的方法,实现和服务的交互和通讯
                MyService.this.showToast();
            }
        }
    
        // 服务绑定
        @Override
        public IBinder onBind(Intent intent) {
    
            Log.v("myApp", "服务绑定");
    
            return new MyBinder();
        }
    
    
        private void showToast() {
    
            Toast.makeText(MyService.this, "调用了服务里的方法", Toast.LENGTH_SHORT).show();
        }
    }
    

    7.service的生命周期

    public class MyService extends Service {
        
        @Override
        public void onCreate() {
            super.onCreate();
            Log.v("myApp", "MyService onCreate在服务创建的时候调用");
        }
        
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.v("myApp", "MyService onStartCommand在服务开启的时候调用");
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return new MyBinder();
        }
        
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.v("myApp", "MyService onDestroy在服务销毁的时候调用");
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
    
            Log.v("myApp", "服务解绑");
    
            return super.onUnbind(intent);
        }
    }
    

    生命周期方法就这几个,但是在startService和bindService这两种模式下,调用的方法还是不一样的
    在startService时,调用的是onCreate,onStartCommand,onDestroy
    在bindService时,调用的是onCreate,onBind,onUnbind,onDestroy

    服务有两个特性,
    1.后台一直运行 2.没有界面,能够与界面交互
    startService:后台一直运行,但是不能与界面交互
    bindService:当启动服务的组件被销毁时,服务也跟着销毁,能够与界面交互
    所以在项目中,我们会将两种方式一起使用,先startService来启动服务,这种启动方式下只要不是stopService,service是不会停止的,然后使用bindService来绑定服务,实现service与界面的交互,当不需要交互时可以调用unBindService来解除绑定,但是服务还是存活的,如果连service都不需要了,那么调用stopService,服务就会被销毁了

    8.远程服务创建和aidl使用
    举例:淘宝下单,调用支付宝的支付功能

    1.创建支付service并且注册对应的action,淘宝启动service的时候需要根据action android:name来进行过滤

          <service
                android:name=".AlipayService"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.mazhan.alipay.action.SAFEPAY"/>
                </intent-filter>
            </service>
    
    public class AlipayService extends Service {
        public AlipayService() {
        }
    
    
        @Override
        public IBinder onBind(Intent intent) {
            return new MyAlipayAgent();
        }
    
    
        int callSafePay(String account, String pwd, String payPwd, double price) {
            if (!payPwd.equals("123")) {
                return 2;
            }
            if (price > 1000) {
                return 3;
            }
            return 1;
        }
    
        class MyAlipayAgent extends IAlipayService.Stub {
    
            @Override
            public int callSafePay(String account, String pwd, String payPwd, double price) throws RemoteException {
                return AlipayService.this.callSafePay(account, pwd, payPwd, price);
            }
        }
    
    }
    

    这里在本地调用的时候MyAlipayAgent继承的是Binder并且实现IAlipayService接口,这里使用的是aidl文件,创建IAlipayService的aidl文件,然后 build->clean project,就会自动生成IAlipayService.java文件,在其中有一个内部类Stub已经继承了android.os.Binder 并且实现了com.mazhan.alipayservice接口,所以我们的代理MyAlipayAgent 只需要继承IAlipayService.Stub就可以了

    public static abstract class Stub extends android.os.Binder implements com.mazhan.alipayservice.IAlipayService
    
    

    IAlipayService的aidl文件

    package com.mazhan.alipayservice;
    interface IAlipayService {
    
        /*
        * 返回值:1,支付成功,2,账号错误或密码错误,3,余额不足
        *
        * */
        int callSafePay(String account, String pwd, String payPwd, double price);
    }
    

    *在淘宝项目中,下单时调用IAlipayService 接口,那么就需要将IAlipayService.aidl文件拷贝到淘宝项目中,然后生成IAlipayService.java,这样就可以调用IAlipayService 接口中的方法了

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            Button button = (Button) findViewById(R.id.button_pay);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    Intent intent = new Intent();
                    intent.setAction("com.mazhan.alipay.action.SAFEPAY");
                    intent.setPackage("com.mazhan.alipayservice");
                    startService(intent);
    
    
                    bindService(intent, new ServiceConnection() {
                        @Override
                        public void onServiceConnected(ComponentName name, IBinder service) {
                            
                            IAlipayService iAlipayService = IAlipayService.Stub.asInterface(service);
                            
                            try {
                                int i = iAlipayService.callSafePay("zhangsan", "123", "123", 100);
                                
                                switch (i) {
                                    case 1 :
                                        Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
                                        break;
                                    case 2 :
                                        Toast.makeText(MainActivity.this, "支付密码错误", Toast.LENGTH_SHORT).show();
    
                                        break;
                                    case 3 :
                                        Toast.makeText(MainActivity.this, "余额不足", Toast.LENGTH_SHORT).show();
    
                                        break;
                                    default:
                                        break;
    
                                }
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
    
                        @Override
                        public void onServiceDisconnected(ComponentName name) {
    
                        }
                    }, BIND_AUTO_CREATE);
                }
            });
        }
    }
    

    注意点

    1.在淘宝项目中复制aidl文件时,需要连包名一起复制


    image.png

    2.在淘宝的mainActivity中,启动支付宝的service时,在安卓5.0之后隐式启动时,需要设置包名


    3.在IAlipayService.Stub中提供了将IBinder转换为IAlipayService的方法

     IAlipayService iAlipayService = IAlipayService.Stub.asInterface(service);
    
    

    相关文章

      网友评论

          本文标题:Android service

          本文链接:https://www.haomeiwen.com/subject/knqeektx.html