Android组件Service学习


1、Android提供Service类来专门创建用来处理长生命周期操作的应用程序组件以及包括不需要用户界面的功能。Android赋予Service比处于非活动状态的Activity更高的优先级,因此当系统请求资源时,他们被终止的可能性更小。
    通过使用Service,使得在UI不可见的时候也可以保证应用程序的持续运行。
    Service运行在应用程序进程的主线程中(和Activity、Brocast Receiver一样)
2、Service没有运行界面,可以执行Intent查找,处理数据,更新Content Provider,激活Intent,和激发Notification等;
     Service被设计为长生命周期的,用来执行一些持续性的,可能耗时的操作。
3、Service生命周期
技术分享
Service启动形式:
1、显式起动:
 Intent intent = new Intent(MainActivity.this, MyService.class);
 startService(intent);
2、隐式启动:

 Intent intent = new Intent(MyService.SERVICE_INTENT);
 startService(intent);
//  @value public static final String SERVICE_INTENT = "com.example.service_ex.SERVICE_INTENT";
同时应当在Mainfest中添加Intent Filter:

 <service
       android:name=".MyService"
       android:enabled="true"
       android:permission="com.example.MY_SERVICE_PERMISSION">
       <intent-filter>
           <action android:name="com.example.service_ex.SERVICE_INTENT"/>
           <category android:name="android.intent.category.DEFAULT"/>
       </intent-filter>           
   </service>

终止形式:
1、显式终止:
 stopService(new Intent(MainActivity.this ,MyService.class));
2、隐式终止:

//  stopService(new Intent(MyService.SERVICE_INTENT));
    stopService(new Intent().setAction(MyService.SERVICE_INTENT));
3、Service内部终止

    stopSelf(startId);
或者stopSelf();
生命周期:
startService(无论显式、隐式)启动后,会调用onCreate()--onStartCommand()
启动之后,再次startService,则会调用onStartCommand();

调用stopService或者stopSelf终止,调用onDestroy(),无论startService调用多少次,终止只会调用一次。
终止后再次调用stopService或者stopSelf,则无响应。

内部调用stopSelf终止,无论是放在onCreate(),或者onStartCommand()中,都会按
onCreate()--onStartCommand()--onDestroy()执行,不会因为放在onCreate()中而跳过onStartCommand()直接终止。

Service简单代码实现:
public class MyService extends Service{

    public static final String SERVICE_INTENT = "com.example.service_ex.SERVICE_INTENT";
   
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
 
    @Override
    public void onCreate()
    {
        Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
        //即是放在onCreate中,Service也是会按onCreate--onStartCommand--onDestory顺序执行
        //stopSelf();
    }
   
    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
        //内部调用自终止
//      stopSelf(startId);
        return Service.START_STICKY;
    }
   
    @Override
    public void onDestroy()
    {
        Toast.makeText(this, "ENDService", Toast.LENGTH_SHORT).show();
    }   
}
4、onStartCommand返回值问题:
onStartCommand源码
 /**
     * Called by the system every time a client explicitly starts the service by calling
     * {@link android.content.Context#startService}, providing the arguments it supplied and a
     * unique integer token representing the start request.  Do not call this method directly.
     *
     * <p>For backwards compatibility, the default implementation calls
     * {@link #onStart} and returns either {@link #START_STICKY}
     * or {@link #START_STICKY_COMPATIBILITY}.
     *
     * <p>If you need your application to run on platform versions prior to API
     * level 5, you can use the following model to handle the older {@link #onStart}
     * callback in that case.  The <code>handleCommand</code> method is implemented by
     * you as appropriate:
     *
     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
     *   start_compatibility}
     *
     * <p class="caution">Note that the system calls this on your
     * service's main thread.  A service's main thread is the same
     * thread where UI operations take place for Activities running in the
     * same process.  You should always avoid stalling the main
     * thread's event loop.  When doing long-running operations,
     * network calls, or heavy disk I/O, you should kick off a new
     * thread, or use {@link android.os.AsyncTask}.</p>
     *
     * @param intent The Intent supplied to {@link android.content.Context#startService},
     * as given.  This may be null if the service is being restarted after
     * its process has gone away, and it had previously returned anything
     * except {@link #START_STICKY_COMPATIBILITY}.
     * @param flags Additional data about this start request.  Currently either
     * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
     * @param startId A unique integer representing this specific request to
     * start.  Use with {@link #stopSelfResult(int)}.
     *
     * @return The return value indicates what semantics the system should
     * use for the service's current started state.  It may be one of the
     * constants associated with the {@link #START_CONTINUATION_MASK} bits.
     *
     * @see #stopSelfResult(int)
     */
    publicint onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
    }

Android官方文档中,我们知道onStartCommand4种返回值:

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_COMPATIBILITYSTART_STICKY的兼容版本,但不保证服务被kill后一定能重启。


模拟实现:在运行Service后将其kill掉再重启,观察其startID及Intent参数实参值如下:

1.  START_STICKY

技术分享

可以看出,再次调用 onCreateonStartCommand,并且 startId = 2, 但是 intent = null

2.  START_NOT_STICKY

技术分享

这次并没有重启。

3.  START_STICKY_COMPATIBILITY

技术分享

只调用了oncreate 方法,没有调用 onStartCommand 

4.  START_REDELIVER_INTENT

技术分享

可以看出,再次调用 onCreateonStartCommand,并且 startId = 1, 但是 intent 不为 null

说明该 int 可以保留上次的 startId  intent

5、绑定服务(Service的绑定形式)

    一个绑定服务是客户端与服务端之间的一个接口。一个绑定服务允许组件和其进行绑定,并通过这个绑定服务,可以接受请求,发送请求,甚至完成进程间的通信。绑定服务的生命周期以来其绑定的客户端,并非无限期的运行下去。

基本原理

    一个绑定服务,就是一个实现了类Service,并允许其它应用程序与其绑定及与之交互的的组件。提供一个绑定服务,你必须实现onBind()方法,这个方法返回一个IBinder对象,这个对象就是定义用来客户端与服务交互的接口。

    客户端通过bindService()方法绑定服务。另外,客户端还必须提供一个ServiceConnection的实现对象,用以监控与服务Service间的连接情况。bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法,并传递一个客户端与服务端可以交互的IBinder接口。

    多个客户端同时连接Service时,系统只在第一个客户端连接时调用你的onBind()方法并返回一个IBinder对象,系统在其他客户端进行连接时返回相同的IBinder对象,而不再去调用onBind().

    当最后一个客户端调用与服务解除绑定时,系统将销毁服务,除非这个服务启动时,也调用了startService()方法.

 

如何创建绑定服务

3种方式进行服务绑定:

1、  继承Binder

如果你的服务只针对你自己的应用程序,且与客户端处于同一个进程当中,那么可以使用继承这种方式。此时,你应该创建一个继续与Binder接口的类,并实现其onBind(),然后返回一个你创建的服务的实例。然后客户端就可以接收到Binder,并可以使用这个Binder访问Binderpublic方法及Servicepublic方法。

2、  使用信使者Messenger

如果你的Service要求跨越不同的进程,那么你需要为你的Service创建一个Messenger成员,同时定义一个可以响应不同类型消息Messge对象Handler对象。

Hander对象是为Messenger对象提供基础的,这样Hander就可以共享一个IBinder对象给客户端了,并允许客户端使用Message对象给服务发送命令。此外,客户端也可以定义一个自己的Messenger,这样客户端就可以将消息发送到服务端了。

3、  使用AIDL

比较复杂的一种,在Messenger基础上支持多线程并发处理。使用AIDL(Android Interface Definition Language),使得Service可以跨应用绑定,AIDL使用系统级的原语定义了Service的接口,允许Android跨进程传递对象。


1、继承Binder类方式实现:

自定义MyBindService继承Service:

/*绑定形式的Service*/
public class MyBindService extends Service{
   
    //为client提供使用的Binder
    public final IBinder binder = new MyBinder();
   
    public class MyBinder extends Binder
    {
        MyBindService getServiceInstance()
        {
            return MyBindService.this;
        }
    }
   
    /*Service生命周期*/
    @Override
    public void onCreate() {
        Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show();
    }
   
    @Override
    public IBinder onBind(Intent intent){
        Toast.makeText(this, "onBind", Toast.LENGTH_SHORT).show();
        //stopSelf();//使用stopSelf貌似没用
        return binder;
    }
   
    @Override
    public boolean onUnbind(Intent intent) {
        Toast.makeText(this, "onUnbind", Toast.LENGTH_SHORT).show();
        return false;
    }
   
    @Override
    public void onDestroy() {
        Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
    }
   
    /*提供相应服务*/
    public String provideService()
    {
        return "provideService";
    } 
}
 
在Client里面通过bindService与unBindService调用Service:
public class MainActivity extends Activity {
 
    private Button myBind, myUnBind , myUse;
   
    //标志是否绑定,判断myBindService=null的方法行不通
    private booleanmBind;
    private MyBindService myBindService;
   
    //用以处理client和service
    private ServiceConnection mConnection = new ServiceConnection() {
        //调用bindService时系统会调用此函数
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //在这里获取MyBindService实例,则可以在Activity中调用Service中的方法
            myBindService = ((MyBindService.MyBinder)service).getServiceInstance();
            mBind = true;
        }
       
        //当Service意外断开时接收
        @Override
        public void onServiceDisconnected(ComponentName name) {
            myBindService = null;
            mBind = false;
        }
       
    };
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        myBind   = (Button) findViewById(R.id.myBind);
        myUnBind = (Button) findViewById(R.id.myUnBind);
        myUse    = (Button) findViewById(R.id.myUse);
       
        /*************************绑定Service形式******************************/
        myBind.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MyBindService.class);
                bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
                /**bind执行流程   onCreate()--onBind(),onBind中需要返回IBinder的实例
                   bindService调用过程中会自动调用ServiceConnection。onServiceConnected()获得对应的Service实例
                         通过Service实例调用其提供的服务,并加以控制*/
            }
        });
       
        myUnBind.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                /*如果Service没有bind,调用此函数程序将会崩溃
                     故应当先作判断*/
                if (mBind) {
                    unbindService(mConnection);
                    //unBind执行流程   onUnbind--onDestory
                    mBind = false;
                }
                else {
                    Toast.makeText(MainActivity.this, "请先bind", Toast.LENGTH_SHORT).show();
                }
            }
        });
       
        myUse.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mBind && myBindService != null) {
                    Toast.makeText(MainActivity.this, myBindService.provideService(), Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}
2、  使用信使者Messenger



public class MessengerService extends Service {
 
    /** 自定义消息类型 */
    static final intMSG_SAY_HELLO = 1;
 
    /**自定义Handler来处理来自client的messages*/
 
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            caseMSG_SAY_HELLO:
                Toast.makeText(getApplicationContext(), "MessengerService!",Toast.LENGTH_SHORT).show();
                break;
            default:
                super.handleMessage(msg);
            }
        }
    }
 
    /**
     * 为IncomingHandler创建Messenger
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());
 
    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
 
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        return mMessenger.getBinder();
    }
}

在clients端使用得:

public class MainActivity extends Activity {
 
    private Button myMessengerBind, myMessengerUnBind, myMessengerUse;
    private Messenger messenger;
    private booleanmBindFlag;
    private ServiceConnection mMessengerConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
        messenger = new Messenger(service);
            mBindFlag = true;
        }

        public void onServiceDisconnected(ComponentName className) {
        messenger = null;
        mBindFlag = false;
        }
    };
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        myMessengerBind   = (Button) findViewById(R.id.myMessengerBind);
        myMessengerUnBind = (Button) findViewById(R.id.myMessengerUnBind);
        myMessengerUse    = (Button) findViewById(R.id.myMessengerUse);
       
        myMessengerBind.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, MessengerService.class);
                bindService(intent, mMessengerConnection, Context.BIND_AUTO_CREATE);   
            }
        });
       
        myMessengerUnBind.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mBindFlag) {
                    unbindService(mMessengerConnection);
                    //unBind执行流程   onUnbind--onDestory
                    mBindFlag = false;
                }
                else {
                    Toast.makeText(MainActivity.this, "请先bind", Toast.LENGTH_SHORT).show();
                }
            }
        });
       
        myMessengerUse.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mBindFlag)
                {
                    Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
                    try {
                        messenger.send(msg);
                    } catch (Exception e) {
 
                    }
                }
            }
        });
    }
}

看一下Messenger的源码:


/**
 * Reference to a Handler, which others can use to send messages to it.
 * This allows for the implementation of message-based communication across
 * processes, by creating a Messenger pointing to a Handler in one process,
 * and handing that Messenger to another process.
 */
public final class Messenger implements Parcelable {
    private final IMessenger mTarget;
 
    /**
     * Create a new Messenger pointing to the given Handler.  Any Message
     * objects sent through this Messenger will appear in the Handler as if
     * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
     * been called directly.
     *
     * @param target The Handler that will receive sent messages.
     */
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
   
    /**
     * Send a Message to this Messenger's Handler.
     *
     * @param message The Message to send.  Usually retrieved through
     * {@link Message#obtain() Message.obtain()}.
     *
     * @throws RemoteException Throws DeadObjectException if the target
     * Handler no longer exists.
     */
    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
   
    /**
     * Retrieve the IBinder that this Messenger is using to communicate with
     * its associated Handler.
     *
     * @return Returns the IBinder backing this Messenger.
     */
    public IBinder getBinder() {
        return mTarget.asBinder();
    }
   
    /**
     * Comparison operator on two Messenger objects, such that true
     * is returned then they both point to the same Handler.
     */
    public boolean equals(Object otherObj) {
        if (otherObj == null) {
            return false;
        }
        try {
            return mTarget.asBinder().equals(((Messenger)otherObj)
                    .mTarget.asBinder());
        } catch (ClassCastException e) {
        }
        return false;
    }
 
    public int hashCode() {
        return mTarget.asBinder().hashCode();
    }
   
    public int describeContents() {
        return 0;
    }
 
    public void writeToParcel(Parcel out, intflags) {
        out.writeStrongBinder(mTarget.asBinder());
    }
 
    public static final Parcelable.Creator<Messenger> CREATOR
            = new Parcelable.Creator<Messenger>() {
        public Messenger createFromParcel(Parcel in) {
            IBinder target = in.readStrongBinder();
            return target != null ? new Messenger(target) : null;
        }
 
        public Messenger[] newArray(int size) {
            return new Messenger[size];
        }
    };
 
    /**
     * Convenience function for writing either a Messenger or null pointer to
     * a Parcel.  You must use this with {@link #readMessengerOrNullFromParcel}
     * for later reading it.
     *
     * @param messenger The Messenger to write, or null.
     * @param out Where to write the Messenger.
     */
    public static void writeMessengerOrNullToParcel(Messenger messenger,
            Parcel out) {
        out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder() : null);
    }
   
    /**
     * Convenience function for reading either a Messenger or null pointer from
     * a Parcel.  You must have previously written the Messenger with
     * {@link #writeMessengerOrNullToParcel}.
     *
     * @param in The Parcel containing the written Messenger.
     *
     * @return Returns the Messenger read from the Parcel, or null if null had
     * been written.
     */
    public static Messenger readMessengerOrNullFromParcel(Parcel in) {
        IBinder b = in.readStrongBinder();
        return b != null ? new Messenger(b) : null;
    }
   
    /**
     * Create a Messenger from a raw IBinder, which had previously been
     * retrieved with {@link #getBinder}.
     *
     * @param target The IBinder this Messenger should communicate with.
     */
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }
}

3、使用AIDL实现进程间通信IPC

http://blog.csdn.net/wangkuifeng0118/article/details/7277680










郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。