您的位置:首页 > 移动开发 > Android开发

简述Android四大组件之一的Service(一)

2016-09-29 09:27 302 查看
Service作为Android的四大组件之一,就像它的名字一样,是一种服务,不过是在后台默默地服务,它不仅可以实现进程内的服务,还可以实现进程之间的服务,下面我们来看看分类:

1.按照作用范围来分类(图片引用的其他文章的 )

下图中的IPC和AIDL大家可以去推酷中查查,原理比较简单,在后面的博文中的我会写一下关于它们的简述。



2.按照运行类型分类



服务是在调用 startForeground(android 2.0 及其以后版本)使服务成为前台服务。这样做的好处在于,当服务被外部强制终止掉的时候,ONGOING
的 Notification 会被移除掉。

service的启动方式有两种:



下面来看看两种启动方式的启动的service的生命周期



service主要是用来独立完成一些任务的,比如在一个APP中可以使用service在后台一直更新系统时间,检查网络状况,或者更新天气情况,可能大家就要说了,用Thread、AsynTask、TimerTask也可以完成的嘛,那我们来看看区别:
1.AsynTask、TimerTask三者其实都是要开启新的线程来执行任务,也相当于后台执行,不影响主进程的执行,Thrad是开启新的进程来执行任务,它需要分配CPU(Thread是分配CPU的最小单位),所以三者的方式差不多,我们可以归于一类。
2.而service是Android的一种机制,

如果运行的是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStartCommand这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。

如果运行是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。

为什么 Thread替代不了Service 呢?

一方面,Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行,因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另

如果创建的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。

另一方面,因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题,因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例。

因此可以把 Service 想象成一种消息服务,在任何有 Context 的地方调用方法来控制它,你也可以在 Service 里注册BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

3.startService

被启动的服务的生命周期:onCreate -> onStartCommand -> onDestroy

如果Service被startService方法启动多次,其中只会调用一次onCreate方法,但是会调用多次onStartCommand,此时系统只会创建一个Service实例,因此只需要调用一次stopService方法就可以停掉服务。

如果Service被某个Activity 调用startService方法启动,不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。

startService启动的Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService、或自身的stopSelf方法、或系统资源不足android系统也可能结束该服务。

如何创建一个service呢?你可以创建自己的service类来继承Service,也可以及时创建一个Service对象,实现里面的方法就可以了,但是建议使用前者进行创建。

下面给出一篇文章的代码例子(自己比较懒,直接引用了)
public class service1 extends Service {
private final String TAG = "service1";

//Service被创建时调用
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate方法被调用");
}

//必须要实现的方法
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onCreate方法被调用");
return null;
}

//Service被启动时调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand方法被调用!");
return super.onStartCommand(intent, flags, startId);
}

//Service被关闭之前回调
@Override
public void onDestroy() {
Log.i(TAG, "onDestroy方法被调用!");
super.onDestroy();
}
}


public class demo1 extends AppCompatActivity {

private Button start;
private Button stop;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo1);

start = (Button) findViewById(R.id.start_Service1);
stop = (Button) findViewById(R.id.stop_Service1);

//1.创建启动Service的Intent
final Intent intent = new Intent(demo1.this, service1.class);

start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//2.启动service
startService(intent);
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//3.停止service
stopService(intent);
}
});

}
}


需要值得注意的一点是,当你创建完自己的service类的时候,如果要使用的话要在AndroidManifest.xml文件中的application标签内进行注册一下:

<service android:name=".Service.service1"/>

当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称。

当Service需要对其他App开放时,android:exported属性值需要设置为true(当然在有intent-filter时默认值就是true)。

4.bindService

被绑定的服务的生命周期:onCreate-> onBind-> onUnbind

如果Service被某个Activity调用bindService方法绑定启动,不管调用bindService几次,只会调用一次onCreate方法,同时始终不会调用onStartCommand方法。

当连接建立之后,Service将会一直运行,除非调用unbindService断开连接、或之前调用bindService的Context 不存在了,如Activity被finish的时候,系统将会自动停止Service,对应的将被调用onDestroy方法。

根据onBind(Intentintent)方法放回的Binder对象的定义方式不同,又可以将其分为以下三种方式,这里,先写第一种方式,此方式Clinet与Service必须同属于同一个进程,不能实现进程间通信(IPC)。否则会出现类似于“android.os.BinderProxycannot be cast to xxx”错误。
public class service2 extends Service {

private final String TAG = "Service2";
private myBinder binder = new myBinder();
public class myBinder extends Binder {
service2 getgetService() {
return service2.this;
}
}

@Override
public void onCreate() {
Log.i(TAG, "onCreate方法被调用");
super.onCreate();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind方法被调用");
return binder;
}

@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind方法被调用");
return super.onUnbind(intent);
}

@Override
public void onRebind(Intent intent) {
Log.i(TAG, "onRebind方法被调用");
super.onRebind(intent);
}

@Override
public void onDestroy() {
Log.i(TAG, "onDestroy方法被调用");
super.onDestroy();
}
}

public class demo2 extends AppCompatActivity {

private Button bind;
private Button cancel;
private Intent intent;
private service2 service2;
private service2.myBinder myBinder;
private ServiceConnection conn = new myServiceConnection();
private boolean mBound;

//保持所启动的service2的IBinder对象,同时定义一个ServiceConnection对象。
private class myServiceConnection implements ServiceConnection {

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("----Service Connected----");
myBinder = (com.guofeng.demo4.Service.service2.myBinder) service;
service2 = myBinder.getgetService();
mBound = true;
}

@Override
public void onServiceDisconnected(ComponentName name) {
System.out.println("----Service DisConnected----");
mBound = false;

}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo2);
bind = (Button) findViewById(R.id.bind_service2);
cancel = (Button) findViewById(R.id.cancel_service2);
intent = new Intent(demo2.this, service2.class);

bind.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent, conn, BIND_AUTO_CREATE);

}
});

cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
excuteUnbindService();
}
});

}

private void excuteUnbindService() {
if (mBound) {
unbindService(conn);
mBound = false;
}
}

@Override
protected void onDestroy() {
super.onDestroy();
excuteUnbindService();
}
}


注意:

1.自定义Service继承基类Service,并重写onBind(Intentintent)方法,此方法中需要返回具体的Binder对象;

2.Client通过实现ServiceConnection接口来自定义ServiceConnection,并通过bindService(Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;

3.自定义的ServiceConnection中实现onServiceConnected(ComponentNamename, IBinder binder)方法,获取Service端Binder实例;

4.通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;

5.当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnectionsc)。

其他

1.如果Service又被启动又被绑定,则该Service将会一直在后台运行。不管如何调用,始终只会调用一次onCreate,对应调用多少次startService,Service便会调用多少次onStartCommand。

调用unbindService将不会停止Service,而必须调用stopService 、或Service的stopSelf 来停止服务。

2.当服务的onDestroy方法被调用时,应做一些清除工作,如:停止在Service中创建并运行的线程。

3. 想要用startService启动服务,不管Local还是Remote记得在Androidmanifest.xml 中注册service。

4. Service本身都是运行在其所在进程的主线程(如果Service与Clinet同属于一个进程,则是运行于UI线程),但Service一般都是需要进行“长期”操作,所以经常写法是在自定义Service中处理“长期”操作时需要新建线程,以免阻塞UI线程或导致ANR。

5.IntentService

IntentService是系统提供给我们的一个已经继承自Service类的特殊子类,主要用于防止线程阻塞,处理异步请求。所有的请求将在一个工作线程HandlerThread中处理,工作完成了,线程也就结束了。

1.默认直接实现了onBind方法,直接返回null,并定义了抽象方法onHandlerIntent,用户自定义子类时,需要实现此方法。

2.onHandlerIntent主要就是用来处于相应的”长期“任务的,并且已经自动在新的线程中,用户无语自定义新线程;

3.当”长期“任务执行完毕后,也就是onHandlerIntent执行完毕后,此IntentService将自动结束,无需人为调用方法使其结束。

4.IntentService处于任务时,也是按照队列的方式一个个去处理,并非真正意义上的多线程并发方式。
public class service3 extends IntentService {
private final String TAG = "IntentService:";

//必须实现父类的构造方法
public service3() {
super("guofeng");
}

public service3(String name) {
super(name);
}

//必须重写的核心方法
@Override
protected void onHandleIntent(Intent intent) {
String str = intent.getExtras().getString("param");
if (str.equals("s1"))
Log.i(TAG, "启动service1");
else if (str.equals("s2"))
Log.i(TAG, "启动service2");
else if (str.equals("s3"))
Log.i(TAG, "启动service3");

try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}

}

//重写其他方法,用于查看方法的调用顺序
@Override
public void onCreate() {
Log.i(TAG, "onCreate");
super.onCreate();
}

@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return super.onBind(intent);
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}

@Override
public void setIntentRedelivery(boolean enabled) {
Log.i(TAG, "setIntentRedelivery");
super.setIntentRedelivery(enabled);
}

@Override
public void onDestroy() {
Log.i(TAG, "onDestroy");
super.onDestroy();
}
}

public class demo3 extends AppCompatActivity {
private Context mContext;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo3);

mContext = this;
Button btn = (Button) findViewById(R.id.btn3);
assert btn != null;
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent1 = new Intent(mContext, service3.class);
Bundle bundle1 = new Bundle();
bundle1.putString("param", "s1");
intent1.putExtras(bundle1);

Intent intent2 = new Intent(mContext, service3.class);
Bundle bundle2 = new Bundle();
bundle2.putString("param", "s2");
intent2.putExtras(bundle2);

Intent intent3 = new Intent(mContext, service3.class);
Bundle bundle3 = new Bundle();
bundle3.putString("param", "s3");
intent3.putExtras(bundle3);

//接着启动多次IntentService,每次启动,都会创建一个新工作线程
//但是始终只有一个IntentService实例
startService(intent1);
startService(intent2);
startService(intent3);
}
});
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: