android四大组件之service总结

Service通常总是称之为“后台服务”,其中“后台”一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件:
1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的);
2.具有较长时间的运行特性。 常见于下载等耗时任务。
一,service 和其他三个组件一样,在应用时首先需要在AndroidMainfest文件中注册。
<service android:enabled=[“true” | “false”]
android:exported=[“true” | “false”]
android:icon=“drawable resource”
android:isolatedProcess=[“true” | “false”]
android:label=“string resource”
android:name=“string”
android:permission=“string”
android:process=“string” >

android:name对应Service类名,android:permission是权限声明,android:process设置具体的进程名称,android:exported 是service是否可以被外部引用。
二,service的使用
service有两种使用方式
1,startService 和stopService
开始service
intentService = new Intent(MainActivity.this,MyService.class);
intentService.putExtra(“name”,“我是 service!”);
startService(intentService);
关闭service stopService(intentService);在Service内部,也可以通过stopSelf(…)方式停止其本身。
涉及的service生命周期方法有
@Override
public void onCreate() {
super.onCreate();
Log.e(tag,“in onCreate”);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w(tag, “in onStartCommand”);
String name = intent.getStringExtra(“name”);
Log.w(tag, “name:” + name);
return START_STICKY;
}
@Override
public void onDestroy() {
Log.e(tag,“onDestroy”);
super.onDestroy();
}
第一次启动startService 生命周期方法调用情况如下:
2018-12-23 22:13:41.156 2276-2276/com.example.lcq.myapp E/MyService: in onCreate
2018-12-23 22:13:41.156 2276-2276/com.example.lcq.myapp W/MyService: in onStartCommand
2018-12-23 22:13:41.157 2276-2276/com.example.lcq.myapp W/MyService: name:我是 service!
再次点击 start后调用如下
2018-12-23 22:16:01.469 2276-2276/com.example.lcq.myapp W/MyService: in onStartCommand
2018-12-23 22:16:01.469 2276-2276/com.example.lcq.myapp W/MyService: name:我是 service!
由此可见 oncreate 方法只调用一次,而onStartCommand 可多次调用。
执行stopService方法调用方法如下:
2018-12-23 22:18:28.528 2276-2276/com.example.lcq.myapp E/MyService: onDestroy
public int onStartCommand(Intent intent, int flags, int startId) 返回一个int型的值
具体的可选值及含义如下:
START_NOT_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中Client明确再次调用startService(…)启动此Service。
START_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand(…)方法,但其中的Intent将是null,pendingintent除外。
START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(…)方法时,其中的Intent将是非空,将是最后一次调用startService(…)中的intent。
2,bind 和unbind方式
这种方式要借助于ServiceConnection 这个接口将用户绑定后台服务后,可获取后台服务代理对象的回调,我们可以通过该回调,拿到后台服务的代理对象,并调用后台服务定义的方法,也就实现了后台服务和前台的交互,代码试下如下:
private class MyServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.w(tag, “in MyServiceConnection onServiceConnected”);
myBinder = (MyService.MyBinder) service;
myService = myBinder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.w(tag, “in MyServiceConnection onServiceDisConnected”);
mBound = false;
}
}

private MyBinder myBinder = new MyBinder();
public class MyBinder extends Binder {
public MyService getService() {
Log.e(tag,“getService”);
return MyService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.e(tag,“in onBind”);
return myBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(tag,“unbind”);
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.e(tag,“onDestroy”);
super.onDestroy();
}
首次点击onbind log显示如下:
2018-12-23 22:39:24.093 2276-2276/com.example.lcq.myapp E/MyService: in onCreate
2018-12-23 22:39:24.093 2276-2276/com.example.lcq.myapp E/MyService: in onBind
2018-12-23 22:39:24.094 2276-2276/com.example.lcq.myapp W/MainActivity: in MyServiceConnection onServiceConnected
2018-12-23 22:39:24.094 2276-2276/com.example.lcq.myapp E/MyService: getService
再次点击bind 不再执行 周期函数方法,说明MyBindService没有进行任何回调。
点击unbind 执行如下:
2018-12-23 22:42:01.418 2276-2276/com.example.lcq.myapp E/MyService: unbind
2018-12-23 22:42:01.418 2276-2276/com.example.lcq.myapp E/MyService: onDestroy
通过bind和unbind方法我们可以使用Messager来进行通信,通过Messenger方式返回Binder对象可以不用考虑Clinet - Service是否属于同一个进程的问题,并且,可以实现Client - Service之间的双向通信。极大方便了此类业务需求的实现。
public class SecondActivity extends BaseActivity {
private static final String tag =“SecondActivity”;
private boolean mBound;
private Messenger mServerMessager;
private Handler mClientHander = new MyClientHandler();
private Messenger mClientMessager = new Messenger(mClientHander);
class MyClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
if(msg.what == MyMessagerService.MSG_FROM_SERVER_TO_CLIENT) {
Log.e(tag,“receive msg from server”);
Toast.makeText(SecondActivity.this,“从server 传过来的消息”,Toast.LENGTH_SHORT).show();
}
}
}
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(tag,“onServiceConnected”);
mServerMessager = new Messenger(service);
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBound= false;
}
};
public void bindService(View view) {
Log.e(tag,“bindService”);
Intent intent = new Intent(SecondActivity.this,MyMessagerService.class);
bindService(intent,sc,Context.BIND_AUTO_CREATE);
}
public void unbindService(View view) {
Log.e(tag,“unbindService”);
excuteUnbindService();
}
public void sendMessager(View view) {
Log.e(tag,“sendMessager”);
sendMsg();
}
private void sendMsg() {
if(!mBound) {
return;
}
Message msg = Message.obtain(null, MyMessagerService.MSG_FROM_CLIENT_TO_SERVER,0,0);
msg.replyTo = mClientMessager;
try {
mServerMessager.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void excuteUnbindService() {
if (mBound) {
unbindService(sc);
mBound = false;
}
}
}
service类中的代码如下:
public class MyMessagerService extends Service {
public static final String TAG = “MyMessengerService”;
public static final int MSG_FROM_CLIENT_TO_SERVER = 1;
public static final int MSG_FROM_SERVER_TO_CLIENT = 2;
private Messenger mClientMessager;
private Messenger mSericeMessager = new Messenger(new ServerBinder());
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG,“onBind”);
return mSericeMessager.getBinder();
}
public class ServerBinder extends Handler {
@Override
public void handleMessage(Message msg) {
Log.w(TAG, “thread name:” + Thread.currentThread().getName());
switch (msg.what) {
case MSG_FROM_CLIENT_TO_SERVER:
mClientMessager = msg.replyTo;
Message toClinetMsg = Message.obtain(null,MSG_FROM_SERVER_TO_CLIENT);
try {
Log.w(TAG, “server begin send msg to client”);
Toast.makeText(MyMessagerService.this,“从Client 传过来的消息”,Toast.LENGTH_SHORT).show();
mClientMessager.send(toClinetMsg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
break;
}
super.handleMessage(msg);
}
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG,“onUnbind”);
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.e(TAG,“onDestroy”);
super.onDestroy();
}
}
首先在service 和activity各定义了一个messager,然后通过bindService 将mServerMessager 通过ServiceConnection 绑定到activity,再点击sendMsg时又将activity的mClientMessager通过mServerMessager send到service,service 获取到mClientMessager后又将mServerMessager send到activity 从而实现了activity和activity的双向通信。
3,IntentService
IntentService是专门用来解决Service中不能执行耗时操作这一问题的,创建一个IntentService也很简单,只要继承IntentService并覆写onHandlerIntent函数,在该函数中就可以执行耗时操作了。
class MyIntentService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass’s constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService(String name) {
super(name);
}
@Override
protected void onHandleIntent(Intent intent) {
//TODO 在这里执行耗时操作
}
}
4,常见系统服务
系统服务提供了很多便捷服务,比如查询Wifi、网络状态、查询电量、查询音量、查询包名、查询Application信息等等等相关多的服务,
1,判断手机是否开启wifi服务
WifiManager wifi = (WifiManager) getSystemService(WIFI_SERVICE);
boolean enabled = wm.isWifiEnabled();
2,获取当前音量和最大音量
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
int current = am.getStreamMaxVolume(AudioManager.STREAM_RING);
int max = am.getStreamMaxVolume(AudioManager.STREAM_SYSTEM);
3,判断网络是否连接
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
boolean isAvailable = info.isAvailable();

猜你喜欢

转载自blog.csdn.net/weixin_42042620/article/details/85227601