1.Service是Android四大组件之一,下面对Service进行一个简单的介绍,什么生命周期一些基础那些就直接跳过了
1.直接启动(startService) 2.绑定启动(bindService)。
1)具体在什么情况下用直接启动还是用绑定启动呢?
如果你只是想要启动一个后台服务长期进行某项任务那么使用 startService 便可以了。如果你想要与正在运行的 Service 取得联系,那么有两种方法,一种是使用 broadcast ,另外是使用 bindService ,前者的缺点是如果交流较为频繁,容易造成性能上的问题,并且 BroadcastReceiver 本身执行代码的时间是很短的(也许执行到一半,后面的代码便不会执行),而后者则没有这些问题,因此我们肯定选择bindService(这个时候你便同时在使用 startService 和 bindService 了,这在 Activity 中更新 Service 的某些运行状态是相当有用的)。另外如果你的服务只是公开一个远程接口,供连接上的客服端(android 的 Service 是C/S架构)远程调用执行方法。这个时候你可以不让服务一开始就运行,而只用 bindService ,这样在第一次 bindService 的时候才会创建服务的实例运行它,这会节约很多系统资源,特别是如果你的服务是Remote Service,那么该效果会越明显(当然在 Service 创建的时候会花去一定时间,你应当注意到这点)。
2.Activity和Service通信方式一
1)采用IBinder来进行通信,IBinder是Android专门用来进程通讯的。
别忘了对Service在AndroidManifest.xml进行注册)
Service:(这里应该将MyBinder中的方法全部定义在接口里面,来继承接口实现)
1 public class MyService extends Service {
2
3 @Override
4 public IBinder onBind(Intent intent) {
5 // intent获取从Activity传来的数据
6 // 别忘了要返回定义binder实例, 如果返回就不能建立连接
7 return new MyBinder();
8 }
9
10 public class MyBinder extends Binder {
11
12 // 加法
13 public int add(int a, int b) {
14 return a + b;
15 }
16
17 public MyService getService() {
18 return MyService.this;
19 }
20
21 }
22
23 @Override
24 public void onCreate() {
25 super.onCreate();
26 }
27
28 @Override
29 public void onDestroy() {
30 super.onDestroy();
31 }
32
33 }
Activity:
1 public class MainActivity extends Activity {
2
3 private MyService.MyBinder binder;
4 ServiceConnection connection;
5
6 @Override
7 protected void onCreate(Bundle savedInstanceState) {
8 super.onCreate(savedInstanceState);
9 setContentView(R.layout.activity_main);
10
11 connection = new ServiceConnection() {
12
13 @Override
14 public void onServiceDisconnected(ComponentName name) {
15
16 }
17
18 @Override
19 public void onServiceConnected(ComponentName name, IBinder service) {
20 // 获取被绑定service中的binder
21 binder = (MyService.MyBinder) service;
22
23 System.out.println("从service返回来的数据->" + binder.add(5, 3));
24
25 }
26 };
27
28 Intent intent = new Intent("android.intent.mysecondservice");
29 bindService(intent, connection, BIND_AUTO_CREATE);
30
31 }
32
33 }
最后打印出的结果:
2)在Service中开启一个线程模拟网络下载,将下载量在MainActivity中动态的打印出来(这里的IAddCount 接口是为后面去掉Activity中的线程,这里占时没有用的)
Service:
1 public class MyService extends Service {
2 private int count;
3 private ServiceBinder binder;
4 private boolean isGoOn = true;
5 private IAddCount addCount;
6
7 public interface IAddCount {
8 public void showCount(int count);
9
10 }
11
12 @Override
13 public IBinder onBind(Intent intent) {
14 System.out.println("从activity传过来的数据是-->>"
15 + intent.getStringExtra("data"));
16
17 return binder;
18 }
19
20 public void setIAddCount(IAddCount addCount) {
21 this.addCount = addCount;
22 }
23
24 public class ServiceBinder extends Binder {
25
26 public int getCount() {
27 return count;
28 }
29
30 public MyService getService() {
31 return MyService.this;
32 }
33
34 }
35
36 @Override
37 public void onCreate() {
38 super.onCreate();
39 System.out.println("MyService---onCreate()");
40 binder = new ServiceBinder();
41
42 new Thread(new Runnable() {
43
44 @Override
45 public void run() {
46
47 while (isGoOn) {
48 try {
49 Thread.sleep(1000);
50 count++;
51 if (count == 5) {
52 isGoOn = false;
53 }
54 } catch (InterruptedException e) {
55 e.printStackTrace();
56 }
57
58 }
59
60 }
61 }).start();
62
63 }
64
65 @Override
66 public void onDestroy() {
67 super.onDestroy();
68 System.out.println("MyService---onDestroy");
69
70 }
71
72 }
MainActivity:
1 public class MainActivity extends Activity {
2
3 private MyService.MyBinder binder;
4 ServiceConnection connection;
5
6 @Override
7 protected void onCreate(Bundle savedInstanceState) {
8 super.onCreate(savedInstanceState);
9 setContentView(R.layout.activity_main);
10
11 connection = new ServiceConnection() {
12
13 @Override
14 public void onServiceDisconnected(ComponentName name) {
15
16 }
17
18 @Override
19 public void onServiceConnected(ComponentName name, IBinder service) {
20 // 获取被绑定service中的binder
21 binder = (MyService.MyBinder) service;
22
23 System.out.println("从service返回来的数据->" + binder.add(5, 3));
24
25 }
26 };
27
28 Intent intent = new Intent("android.intent.mysecondservice");
29 bindService(intent, connection, BIND_AUTO_CREATE);
30
31 }
32
33 }
打印出的结果是:
3)这里在获取Service的数据的时候,是在Activity中开了一个线程与Service中的线程去对应,然后动态的去提取数据的,其实可以采用接口回调的方法来实现,不用去在开线程的
Service:
1 public class MyService extends Service {
2 private int count;
3 private ServiceBinder binder;
4 private boolean isGoOn = true;
5 private IAddCount addCount;
6
7 public interface IAddCount {
8 public void showCount(int count);
9
10 }
11
12 @Override
13 public IBinder onBind(Intent intent) {
14 System.out.println("从activity传过来的数据是-->>"
15 + intent.getStringExtra("data"));
16
17 return binder;
18 }
19
20 public void setIAddCount(IAddCount addCount) {
21 this.addCount = addCount;
22 }
23
24 public class ServiceBinder extends Binder {
25
26 public int getCount() {
27 return count;
28 }
29
30 public MyService getService() {
31 return MyService.this;
32 }
33
34 }
35
36 @Override
37 public void onCreate() {
38 super.onCreate();
39 System.out.println("MyService---onCreate()");
40 binder = new ServiceBinder();
41
42 new Thread(new Runnable() {
43
44 @Override
45 public void run() {
46
47 while (isGoOn) {
48 try {
49 Thread.sleep(1000);
50 count++;
51 if (count == 5) {
52 isGoOn = false;
53 }
54 } catch (InterruptedException e) {
55 e.printStackTrace();
56 }
57
58 }
59
60 }
61 }).start();
62
63 }
64
65 @Override
66 public void onDestroy() {
67 super.onDestroy();
68 System.out.println("MyService---onDestroy");
69
70 }
71
72 }
MainActivity:
1 public class SecondActivity extends Activity implements OnClickListener {
2
3 private Button btn;
4 private int count;
5 MyService.ServiceBinder binder;
6 private boolean isBack = true;
7 private MyService myService;
8
9 @Override
10 protected void onCreate(Bundle savedInstanceState) {
11 super.onCreate(savedInstanceState);
12 setContentView(R.layout.activity_second);
13 btn = (Button) findViewById(R.id.btn222);
14 btn.setOnClickListener(this);
15 }
16
17 @Override
18 public void onClick(View v) {
19
20 switch (v.getId()) {
21 case R.id.btn222:
22
23 Intent intent = new Intent("android.intent.myservice");
24 intent.putExtra("data", "我是从activity传过来的数据");
25 ServiceConnection sercon = new ServiceConnection() {
26
27 @Override
28 public void onServiceDisconnected(ComponentName name) {
29
30 }
31
32 @Override
33 public void onServiceConnected(ComponentName name,
34 IBinder service) {
35 binder = (MyService.ServiceBinder) service;
36 myService = binder.getService();
37 // 实例化接口
38 myService.setIAddCount(new IAddCount() {
39 // ************************************//
40 // 接口回调
41 @Override
42 public void showCount(int count) {
43 System.out.println("接口回调返回的数据是-->>" + count);
44 }
45 });
46 }
47 };
48 bindService(intent, sercon, BIND_AUTO_CREATE);
49 System.out.println("输出的数据是-->>" + count);
50
51 // new Thread() {
52 // @Override
53 // public void run() {
54 // try {
55 // while (isBack) {
56 // Thread.sleep(1000);
57 // count = binder.getCount();
58 // if (count == 5) {
59 // isBack = false;
60 // }
61 //
62 // Message msg = myHandler.obtainMessage();
63 // msg.arg1 = count;
64 // myHandler.sendMessage(msg);
65 // }
66 //
67 // } catch (InterruptedException e) {
68 // e.printStackTrace();
69 // }
70 //
71 // }
72 //
73 // }.start();
74
75 break;
76 }
77
78 }
79
80 Handler myHandler = new Handler() {
81 public void handleMessage(android.os.Message msg) {
82
83 System.out.println("在activity中获取到的数据是->" + msg.arg1);
84
85 };
86
87 };
88
89 }
运行后的效果和上图一样的
通过broadcast(广播)的形式
在Activity中动态注册一个广播接收器,然后service将数据广播给Activity中的接收器即可
1 public class MainActivity extends Activity {
2 private ProgressBar mProgressBar;
3 private Intent mIntent;
4 private MsgReceiver msgReceiver;
5
6
7 @Override
8 protected void onCreate(Bundle savedInstanceState) {
9 super.onCreate(savedInstanceState);
10 setContentView(R.layout.activity_main);
11
12 //动态注册广播接收器
13 msgReceiver = new MsgReceiver();
14 IntentFilter intentFilter = new IntentFilter();
15 intentFilter.addAction("com.example.communication.RECEIVER");
16 registerReceiver(msgReceiver, intentFilter);
17
18
19 mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
20 Button mButton = (Button) findViewById(R.id.button1);
21 mButton.setOnClickListener(new OnClickListener() {
22
23 @Override
24 public void onClick(View v) {
25 //启动服务
26 mIntent = new Intent("com.example.communication.MSG_ACTION");
27 startService(mIntent);
28 }
29 });
30
31 }
32
33
34 @Override
35 protected void onDestroy() {
36 //停止服务
37 stopService(mIntent);
38 //注销广播
39 unregisterReceiver(msgReceiver);
40 super.onDestroy();
41 }
42
43
44 /**
45 * 广播接收器
46 * @author len
47 *
48 */
49 public class MsgReceiver extends BroadcastReceiver{
50
51 @Override
52 public void onReceive(Context context, Intent intent) {
53 //拿到进度,更新UI
54 int progress = intent.getIntExtra("progress", 0);
55 mProgressBar.setProgress(progress);
56 }
57
58 }
59
60 }
Service :
1 public class MsgService extends Service {
2 /**
3 * 进度条的最大值
4 */
5 public static final int MAX_PROGRESS = 100;
6 /**
7 * 进度条的进度值
8 */
9 private int progress = 0;
10
11 private Intent intent = new Intent("com.example.communication.RECEIVER");
12
13
14 /**
15 * 模拟下载任务,每秒钟更新一次
16 */
17 public void startDownLoad(){
18 new Thread(new Runnable() {
19
20 @Override
21 public void run() {
22 while(progress < MAX_PROGRESS){
23 progress += 5;
24
25 //发送Action为com.example.communication.RECEIVER的广播
26 intent.putExtra("progress", progress);
27 sendBroadcast(intent);
28
29 try {
30 Thread.sleep(1000);
31 } catch (InterruptedException e) {
32 e.printStackTrace();
33 }
34
35 }
36 }
37 }).start();
38 }
39
40
41
42 @Override
43 public int onStartCommand(Intent intent, int flags, int startId) {
44 startDownLoad();
45 return super.onStartCommand(intent, flags, startId);
46 }
47
48
49
50 @Override
51 public IBinder onBind(Intent intent) {
52 return null;
53 }
Activity调用 bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我 们可以利用回调方法
Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好
参考地址:
关于怎样让服务不被杀死
这个倒是有点流氓软件的意思,但有些特定情况还是需要服务能保持开启不被杀死,当然这样做我还是在程序里添加了关闭服务的按钮,也就是开启了就杀不死,除非在软件里关闭。
服务不被杀死分3种来讨论
1.系统根据资源分配情况杀死服务
2.用户通过settings
->Apps
->Running
->Stop
方式杀死服务
3.用户通过settings
->Apps
->Downloaded
->Force Stop
方式杀死服务
第一种情况:
用户不干预,完全靠系统来控制,办法有很多。比如onStartCommand()方法的返回值设为START_STICKY
,服务就会在资源紧张的时候被杀掉,然后在资源足够的时候再恢复。当然也可设置为前台服务,使其有高的优先级,在资源紧张的时候也不会被杀掉。
第二种情况:
用户干预,主动杀掉运行中的服务。这个过程杀死服务会通过服务的生命周期,也就是会调用onDestory()方法,这时候一个方案就是在onDestory()中发送广播开启自己。这样杀死服务后会立即启动。如下:
1 @Override
2 public void onCreate() {
3 // TODO Auto-generated method stub
4 super.onCreate();
5
6 mBR = new BroadcastReceiver() {
7 @Override
8 public void onReceive(Context context, Intent intent) {
9 // TODO Auto-generated method stub
10 Intent a = new Intent(ServiceA.this, ServiceA.class);
11 startService(a);
12 }
13 };
14 mIF = new IntentFilter();
15 mIF.addAction("listener");
16 registerReceiver(mBR, mIF);
17 }
18
19 @Override
20 public void onDestroy() {
21 // TODO Auto-generated method stub
22 super.onDestroy();
23
24 Intent intent = new Intent();
25 intent.setAction("listener");
26 sendBroadcast(intent);
27
28 unregisterReceiver(mBR);
29 }
当然,从理论上来讲这个方案是可行的,实验一下也可以。但有些情况下,发送的广播在消息队列中排的靠后,就有可能服务还没接收到广播就销毁了(这是 我对实验结果的猜想,具体执行步骤暂时还不了解)。所以为了能让这个机制完美运行,可以开启两个服务,相互监听,相互启动。服务A监听B的广播来启动B, 服务B监听A的广播来启动A。经过实验,这个方案可行,并且用360杀掉后几秒后服务也还是能自启的。到这里再说一句,如果不是某些功能需要的服务,不建 议这么做,会降低用户体验。
第三种情况:
强制关闭就没有办法。这个好像是从包的level去关的,并不走完整的生命周期。所以在服务里加代码是无法被调用的。处理这个情况的唯一方法是屏蔽掉force stop
和uninstall
按钮,让其不可用。方法自己去找吧。当然有些手机自带的清理功能就是从这个地方清理的,比如华为的清理。所以第三种情况我也没有什么更好的办法了。