欢迎光临散文网 会员登陆 & 注册

第七章 后台服务(本地服务)

2018-11-11 23:43 作者:swiss126  | 我要投稿

参考资料:

《Android应用程序开发》ISBN 9787302283164

参考软件:

Android Studio、Eclipse+ADT、Android SDK、JDK

本地服务

本地服务的调用者和服务都在同一个程序中,是不需要跨进程就可以实现服务的调用

  • 步骤1:新建子类继承Service类

    需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法

  • 步骤2:构建用于启动Service的Intent对象

  • 步骤3:调用startService()启动Service、调用stopService()停止服务


步骤4:在AndroidManifest.xml里注册Service

一、实现启动服务(1)界面实现


<?xml version="1.0"  encoding="utf-8"?>

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

 

     android:orientation="vertical"

 

     android:layout_width="fill_parent"

 

     android:layout_height="fill_parent"

 

     >

 

  <TextView   android:id="@+id/label"

 

     android:layout_width="fill_parent"  

 

     android:layout_height="wrap_content"  

 

     android:text="@string/hello">

 

  </TextView>

 

  <Button android:id="@+id/start"  

 

     android:layout_width="wrap_content"

 

     android:layout_height="wrap_content"

 

     android:text="启动Service" >

 

  </Button>

 

  <Button android:id="@+id/stop"  

 

     android:layout_width="wrap_content"

 

     android:layout_height="wrap_content"

 

     android:text="停止Service" >

 

  </Button>

 

</LinearLayout>

 

 

 

(2)建立Service类

 

 

package  edu.hrbeu.SimpleRandomServiceDemo;

 

 

 

import android.app.Service;

 

import android.content.Intent;

 

import android.os.IBinder;

 

import android.widget.Toast;

 

 

 

public class RandomService extends  Service{

 

        

 

         @Override

 

         public  void onCreate() {

 

             super.onCreate();

 

             Toast.makeText(this, "(1) 调用onCreate()",

 

                                Toast.LENGTH_LONG).show();   

 

         }

 

        

 

         @Override

 

         public  void onStart(Intent intent, int startId) {

 

               super.onStart(intent, startId);

 

               Toast.makeText(this, "(2) 调用onStart()",

 

                                  Toast.LENGTH_SHORT).show();

 

 

 

               double randomDouble = Math.random();

 

               String msg = "随机数:"+ String.valueOf(randomDouble);

 

               Toast.makeText(this,msg,  Toast.LENGTH_SHORT).show();

 

         }

 

        

 

         @Override

 

         public  void onDestroy() {

 

              super.onDestroy();

 

              Toast.makeText(this, "(3) 调用onDestroy()",

 

                                 Toast.LENGTH_SHORT).show();    

 

         }

 

          

 

        

 

         @Override

 

         public  IBinder onBind(Intent intent) {

 

                   return  null;

 

         }

 

 

 

}

 

(3)注册Service

 

 

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

 

(4)实现启动和停止

显示启动

1     final Intent serviceIntent = new Intent(this, RandomService.class);

 

2     startService(serviceIntent);

 

 

 

 

 

隐式启动

 

 

 

1     <service android:name=".RandomService">

 

2         <intent-filter>

 

3            <action  android:name="edu.hrbeu.RandomService" />

 

4         </intent-filter>

 

5     </service>

 

 

 

 

 

 

 

 

 

package edu.hrbeu.SimpleRandomServiceDemo;

 

 

 

import android.app.Activity;

 

import android.content.Intent;

 

import android.os.Bundle;

 

import android.view.View;

 

import android.widget.Button;

 

 

 

public class  SimpleRandomServiceDemoActivity extends Activity {

 

     /** Called when the activity is first created. */

 

     @Override

 

     public void onCreate(Bundle savedInstanceState) {

 

         super.onCreate(savedInstanceState);

 

         setContentView(R.layout.main);

 

         

 

         Button startButton = (Button)findViewById(R.id.start);

 

         Button stopButton = (Button)findViewById(R.id.stop);

 

         

 

         final Intent serviceIntent = new Intent(this, RandomService.class);

 

         

 

         startButton.setOnClickListener(new Button.OnClickListener(){

 

                  public void onClick(View  view){

 

                            startService(serviceIntent);

 

                  }

 

         });

 

         

 

         stopButton.setOnClickListener(new Button.OnClickListener(){

 

                  public void onClick(View  view){

 

                            stopService(serviceIntent);

 

                  }

 

         });

 

    }

 

}

 

停止一个started服务有两种方法:

(1)在外部使用stopService()

(2)在服务内部(onStartCommand方法内部)使用stopSelf()方法。

 

(5)查看

我们还可以在正在“设置--应用---运行”中找到这个服务,如下图所示:

点开上图中的红框部分,可以看到:


Android获取手机状态和监听手机来电状态例子

获取手机状态:


import android.content.Context;  



import android.telephony.TelephonyManager;  



  



//获得相应的系统服务  



TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);  



       /** 



        * 返回电话状态 



        *  



        * CALL_STATE_IDLE 无任何状态时  



        * CALL_STATE_OFFHOOK 接起电话时 



        * CALL_STATE_RINGING 电话进来时  



        */  



       tm.getCallState();  



       if(tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {  



        Log.d("test""call state idle...");  



       } else if(tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) {  



        Log.d("test""call state offhook...");  



       } else if(tm.getCallState() == TelephonyManager.CALL_STATE_RINGING) {  



        Log.d("test""call state ringing...");  



       }  


监听手机来电状态:


TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);  



  



//使用TelephonyManager对象的listen(PhoneStateListener listener, int events)  



  



  



//实现PhoneStateListener listener并实现相应的方法  



  



public class MyPhoneCallListener extends PhoneStateListener  



{  



  



@Override  



public void onCallStateChanged(int state, String incomingNumber)  



{  



  



  switch (state) {  



    case TelephonyManager.CALL_STATE_OFFHOOK:                   //电话通话的状态  



        Toast.makeText(Main.this"正在通话...", Toast.LENGTH_SHORT).show();  



        break;  



  



    case TelephonyManager.CALL_STATE_RINGING:                   //电话响铃的状态  



        Toast.makeText(Main.this, incomingNumber, Toast.LENGTH_SHORT).show();  



        break;  



  }  



  super.onCallStateChanged(state, incomingNumber);  



}  


第一个参数需要实现PhoneStateListener listener并实现相应的方法,第二个参数是PhoneStateListener的静态常量,此处由于是监听电话状态,所以需要传入LISTEN_CALL_STATE,而同时也需要在AndroidManifest中注册相应的权限

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


二、实现绑定服务

以绑定方式使用Service,能够获取到Service实例,不仅能够正常启动Service,还能够调用Service中的公有方法和属性


应用程序组件(客户端)通过调用bindService()方法能够绑定服务,然后Android系统会调用服务的onBind()回调方法,则个方法会返回一个跟服务器端交互的Binder对象。

这个绑定是异步的,bindService()方法立即返回,并且不给客户端返回IBinder对象。要接收IBinder对象,客户端必须创建一个ServiceConnection类的实例,并且把这个实例传递给bindService()方法。ServiceConnection对象包含了一个系统调用的传递IBinder对象的回调方法。

注意:只有Activity、Service、Content Provider能够绑定服务;BroadcastReceiver广播接收器不能绑定服务。

 

(1)界面实现

 

 

<?xml version="1.0"  encoding="utf-8"?>

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

 

     android:orientation="vertical"

 

     android:layout_width="fill_parent"

 

     android:layout_height="fill_parent"

 

     >

 

  <TextView   android:id="@+id/label"

 

     android:layout_width="fill_parent"  

 

     android:layout_height="wrap_content"  

 

     android:text="@string/hello">

 

  </TextView>

 

  <Button android:id="@+id/bind"  

 

     android:layout_width="wrap_content"

 

     android:layout_height="wrap_content"

 

     android:text="服务绑定" >

 

  </Button>

 

     <Button android:id="@+id/unbind"  

 

     android:layout_width="wrap_content"

 

     android:layout_height="wrap_content"

 

     android:text="取消绑定" >

 

  </Button>

 

  <Button android:id="@+id/compute"  

 

     android:layout_width="wrap_content"

 

     android:layout_height="wrap_content"

 

     android:text="加法运算" >

 

  </Button>

 

</LinearLayout>

 

 

 

 

(2)建立服务类

 

 

package edu.hrbeu.SimpleMathServiceDemo;

 

 

 

import android.app.Service;

 

import android.content.Intent;

 

import android.os.Binder;

 

import android.os.IBinder;

 

import android.widget.Toast;

 

 

 

public class MathService extends Service{

 

 

 

         private  final IBinder mBinder = new LocalBinder();

 

 

 

         public  class LocalBinder extends Binder{

 

                   MathService  getService() {

 

                            return  MathService.this;

 

             }

 

         }

 

 

 

         @Override

 

         public  IBinder onBind(Intent intent) {

 

                    Toast.makeText(this, "本地绑定:MathService",

 

                                Toast.LENGTH_SHORT).show();

 

                   return  mBinder;

 

         }

 

        

 

         @Override

 

         public  boolean onUnbind(Intent intent){

 

                     Toast.makeText(this, "取消本地绑定:MathService",

 

                                           Toast.LENGTH_SHORT).show(); 

 

                   return  false;

 

         }

 

        

 

 

 

         public  long Add(long a, long b){

 

                   return  a+b;

 

         }

 

        

 

}

 

 

(3)注册

 

 

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

 

(4)实现启动和停止

 

 

package edu.hrbeu.SimpleMathServiceDemo;

 

 

 

import android.app.Activity;

 

import android.content.ComponentName;

 

import android.content.Context;

 

import android.content.Intent;

 

import android.content.ServiceConnection;

 

import android.os.Bundle;

 

import android.os.IBinder;

 

import android.view.View;

 

import android.widget.Button;

 

import android.widget.TextView;

 

 

 

public class SimpleMathServiceDemoActivity  extends Activity {

 

         private  MathService mathService;

 

         private  boolean isBound = false;

 

         TextView  labelView;

 

     @Override

 

     public void onCreate(Bundle savedInstanceState) {

 

         super.onCreate(savedInstanceState);

 

         setContentView(R.layout.main);

 

         

 

         labelView = (TextView)findViewById(R.id.label);

 

         Button bindButton = (Button)findViewById(R.id.bind);

 

         Button unbindButton = (Button)findViewById(R.id.unbind);

 

         Button computButton = (Button)findViewById(R.id.compute);

 

         

 

         bindButton.setOnClickListener(new View.OnClickListener(){

 

                            @Override

 

                            public  void onClick(View v) {

 

                                     if(!isBound){

 

                                               final  Intent serviceIntent = new  Intent(SimpleMathServiceDemoActivity.this,MathService.class);

 

                                               bindService(serviceIntent,mConnection,Context.BIND_AUTO_CREATE);

 

                                               isBound  = true;

 

                                     }

 

                            }    

 

         });

 

         

 

         unbindButton.setOnClickListener(new View.OnClickListener(){

 

                            @Override

 

                            public  void onClick(View v) {

 

                                     if(isBound){

 

                                               isBound  = false;

 

                                               unbindService(mConnection);

 

                                               mathService  = null;

 

                                     }

 

                            }           

 

         });

 

         

 

         computButton.setOnClickListener(new View.OnClickListener(){

 

                            @Override

 

                            public  void onClick(View v) {

 

                                               if  (mathService == null){

 

                                                        labelView.setText("未绑定服务");

 

                                                        return;

 

                                               }

 

                                               long  a = Math.round(Math.random()*100);

 

                                               long  b = Math.round(Math.random()*100);

 

                                               long  result = mathService.Add(a, b);

 

                                               String  msg = String.valueOf(a)+" + "+String.valueOf(b)+

 

                                                                                    "  = "+String.valueOf(result);

 

                                               labelView.setText(msg);

 

                            }       

 

         });

 

 

 

     }

 

     

 

     private ServiceConnection mConnection = new ServiceConnection() {

 

                   @Override

 

                   public  void onServiceConnected(ComponentName name, IBinder service) {

 

                            mathService =  ((MathService.LocalBinder)service).getService();

 

                   }

 

 

 

                   @Override

 

                   public  void onServiceDisconnected(ComponentName name) {

 

                            mathService  = null; 

 

                   }

 

     };

 

}

 三、IntentService(多线程)

IntentService是Android里面的一个封装类,继承自四大组件之一的Service。

作用是:处理异步请求,实现多线程

1. 工作流程

工作流程

注意:若启动IntentService 多次,那么每个耗时操作则以队列的方式在 IntentService的onHandleIntent回调方法中依次执行,执行完自动结束。

2. 实现步骤

·        步骤1:定义IntentService的子类:传入线程名称、复写onHandleIntent()方法

·        步骤2:在Manifest.xml中注册服务

·        步骤3:在Activity中开启Service服务

3. 例子

服务中的代码默认运行在主线程中,如果直接在服务里执行一些耗时操作,容易造成ANR(Application NotResponding)异常,所以就需要用到多线程的知识了。

一个比较标准的服务可以这样写

 

 

package com.example.servicetest;

 

 

 

import android.app.Service;

 

import android.content.Intent;

 

import android.os.IBinder;

 

 

 

public class MyService extends Service  { 

 

       

 

     public static final String TAG = "MyService";  

 

 

 

     //服务执行的操作

 

     @Override 

 

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

 

         new Thread(new Runnable() {

 

            public void run() {

 

                //处理具体的逻辑

 

                stopSelf();  //服务执行完毕后自动停止

 

            }

 

         }).start();       

 

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

 

     }

 

 

 

     @Override

 

     public IBinder onBind(Intent intent) {

 

         // TODO Auto-generated method stub

 

         return null;

 

     }     

 

 

 

}

 

(1)新建一个MyIntentService类

 

 

package com.example.servicetest;

 

 

 

import android.app.IntentService;

 

import android.content.Intent;

 

import android.util.Log;

 

 

 

public class MyIntentService extends  IntentService{

 

 

 

     public MyIntentService() {

 

         super("MyIntentService");//调用父类有参构造函数。这里我们手动给服务起个名字为:MyIntentService

 

         // TODO Auto-generated constructor stub

 

     }

 

 

 

     //该方法在会在一个单独的线程中执行,来完成工作任务。任务结束后,该Service自动停止

 

     @Override

 

     protected void onHandleIntent(Intent intent) {

 

         // TODO Auto-generated method stub

 

         for(int i = 0;i<3;i++) {

 

            //打印当前线程的id

 

             Log.d("MyIntentService","IntentService线程的id是:"+Thread.currentThread().getId());

 

            try {

 

                 Thread.sleep(1000);

 

            } catch (InterruptedException e)  {

 

                // TODO Auto-generated catch  block

 

                e.printStackTrace();

 

            }

 

         }       

 

     }

 

 

 

     @Override

 

     public void onDestroy() {

 

         // TODO Auto-generated method stub

 

         super.onDestroy();

 

         Log.d("MyIntentService","onDestroy");

 

     }

 

}

 

(2)在清单文件中对服务进行注册服务

 

 

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

 

 

 

(3)实现启动

在activity_main.xml中添加一个按钮button3_stop_intentservice,用于启动MyIntentService服务,代码略

 

 

case R.id.button3_stop_intentservice:

2             Log.d("MainActivity","主线程的id是:"+Thread.currentThread().getId());

3             Intent intentService = new Intent(this,MyIntentService.class);

4             startService(intentService);

5         default:

 

 

 

3. 总结


  • 从上面源码可以看出,IntentService本质是采用Handler & HandlerThread方式:

    1. 通过HandlerThread单独开启一个名为IntentService的线程

    2. 创建一个名叫ServiceHandler的内部Handler

    3. 把内部Handler与HandlerThread所对应的子线程进行绑定

    4. 通过onStartCommand()传递给服务intent,依次插入到工作队列中,并逐个发送给onHandleIntent()

    5. 通过onHandleIntent()来依次处理所有Intent请求对象所对应的任务

因此我们通过复写方法onHandleIntent(),再在里面根据Intent的不同进行不同的线程操作就可以了


第七章 后台服务(本地服务)的评论 (共 条)

分享到微博请遵守国家法律