Android四大组件之 Service
一 Service简介
Service是运行在后台的,没有界面的,用来处理耗时比较长的。Service不是一个单独的进程,不是一个单独的线程。
Service有两种类型:
- 本地服务(Local Service):用于应用程序内部
- 远程服务(Remote Sercie):用于android系统内部的应用程序之间
前者用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较 好。
后者可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
二 Service的生命周期
Service有startService()和bindService()两种启动Service方法,每种方法Service的生命周期是不一样的。
1 通过startService()
Service会经历 onCreate --> onStartCommand()
stopService的时候直接onDestroy
如果是 调用者 直接退出而没有调用stopService的话,Service会一直在后台运行。
下次调用者再起来仍然可以stopService。
Service只会运行onCreate()-->onBind()
这个时候 调用者和Service绑定在一起
unbindService的时候 onUnbind()-->onDestroyed()
调用者退出了,Srevice就会调用onUnbind()-->onDestroyed()
所谓绑定在一起就共存亡了。
注意:Service的onCreate的方法只会被调用一次,
就是你无论多少次的startService又 bindService,Service只被创建一次。
如果先是bind了,那么start的时候就直接运行Service的onStart方法,
如果先是start,那么bind的时候就直接运行onBind方法。如果你先bind上了,就stop不掉了,
只能先UnbindService, 再StopService,所以是先start还是先bind行为是有区别的。
Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的 程序。
服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。
这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,调用者与服务之间没有关连,
即使调用者退出了,服务仍然运行。使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同 时生,必须同时死”的特点。
如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次 创建服务,
但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用Context.stopService()方法结 束服务,服务结束时会调用onDestroy()方法。
如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的onUnbind()方法,
接着调用onDestroy()方法。如果调用bindService()方法前服务已经被绑定,
多次调用bindService()方法并不会导致多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用)。
如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的 onUnbind()-->onDestroy()方法.
1,service.java
package com.duopin.app;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class PlayService extends Service {
boolean mEnableThread = true;
int mCount = 0;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
Log.d("pin", "onCreate ....run");
creatThread();
super.onCreate();
}
private void creatThread() {
// TODO Auto-generated method stub
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (mEnableThread) {
Log.d("pin", "thread count->" + mCount++);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
Log.d("pin", "onStart ....run");
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.d("pin", "onStartCommand ....run*****************************");
// do something
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
Log.d("pin", "onDestroy ....run*****************************");
mEnableThread = false;
super.onDestroy();
}
}
2,receiver.java
package com.duopin.app;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootPlayBroadCastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.d("pin", "BootPlayBroadCastReceiver ....run");
doStartService(context);
}
private void doStartService(Context context) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setClass(context, PlayService.class);
context.startService(intent);
}
}
3,main.java
package com.duopin.app;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.ImageView;
public class BitmapTestActivity extends Activity {
/** Called when the activity is first created. */
ImageView mImageView = null;
ImageButton mImageButton = null;
String[] mImages = null;
int mCurrentImg = 0;
AssetManager assetManager = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
doStartService();
setupView();
}
public void setupView() {
// TODO Auto-generated method stub
mImageView = (ImageView) this.findViewById(R.id.imgv);
mImageView.setImageResource(R.drawable.ic_launcher);
mImageButton = (ImageButton) this.findViewById(R.id.ibtn);
assetManager = getAssets();
try {
mImages = assetManager.list("");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mImageButton.setOnClickListener(mNextPhotoOnClickListener);
}
View.OnClickListener mNextPhotoOnClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (mCurrentImg >= mImages.length) {
mCurrentImg = 0;
}
// whether if image
while (!mImages[mCurrentImg].endsWith(".png") &&
!mImages[mCurrentImg].endsWith(".jpg") &&
!mImages[mCurrentImg].endsWith(".JPG") &&
!mImages[mCurrentImg].endsWith(".gif")) {
mCurrentImg++;
if (mCurrentImg >= mImages.length) {
mCurrentImg = 0;
}
}
//
InputStream is = null;
try {
is = assetManager.open(mImages[mCurrentImg]);
// get next image
mCurrentImg++;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BitmapDrawable biMapDrawable = (BitmapDrawable) mImageView.getDrawable();
// recycle image
if (biMapDrawable != null && !biMapDrawable.getBitmap().isRecycled()) {
biMapDrawable.getBitmap().recycle();
}
mImageView.setImageBitmap(BitmapFactory.decodeStream(is));
}
};
private void doStartService() {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setClass(getApplicationContext(), PlayService.class);
this.startService(intent);
}
private void doStopService() {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setClass(getApplicationContext(), PlayService.class);
this.stopService(intent);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
doStopService();
super.onDestroy();
}
}
4,manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.duopin.app"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".BitmapTestActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".BootPlayBroadCastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
></receiver>
<service
android:name=".PlayService">
<!--<intent-filter >
<action
/>
</intent-filter>
--></service>
</application>
</manifest>
结果:
( 1951): ******************************Shared.context().startActivity(intent);
D/pin ( 3088): onCreate ....run
D/pin ( 3088): onStartCommand ....run*****************************
D/pin ( 3088): onStart ....run
D/pin ( 3088): thread count->0
D/pin ( 3088): thread count->1
D/pin ( 3088): thread count->2
D/pin ( 3088): thread count->3
D/pin ( 3088): thread count->4
D/pin ( 3088): thread count->5
D/pin ( 3088): thread count->6
[87792596 ERROR-demux]:DMX_OsiOpenChannel[5777]:invalid u32PortId -1!
D/pin ( 3088): thread count->7
onDestroy ....run*****************************