Android service

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类就可以了


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.注册接收系统开机广播的接收者


            
                
            
        

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来进行过滤

      
            
                
            
        
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)