我们研究两个问题,
1、Service如何通过Broadcaster更改activity的一个TextView。
(研究这个问题,考虑到Service从服务器端获得消息之后,将msg返回给activity)
2、Activity如何通过Binder调用Service的一个方法。
(研究这个问题,考虑到与服务器端交互的动作,打包至Service,Activity只呈现界面,调用Service的方法)
结构图见如下:
效果图如下:
u
点击“start service”按钮,启动Service,然后更改Activity的UI。
点击“send msg to server”按钮调用Service的方法,显示NotificationBar
1、新建一个MyService类,继承Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
package
com.ljq.activity;
import
android.app.Notification;
import
android.app.NotificationManager;
import
android.app.PendingIntent;
import
android.app.Service;
import
android.content.Context;
import
android.content.Intent;
import
android.graphics.Color;
import
android.os.Binder;
import
android.os.IBinder;
public
class
MyService
extends
Service {
private
NotificationManager notificationManager =
null
;
private
final
IBinder binder =
new
LocalBinder();
@Override
public
void
onCreate() {
sendMsgtoActivty(
"Service is oncreating.\n"
);
}
@Override
public
IBinder onBind(Intent intent) {
String msg =
"Activity is sendding message to service,\n Service send msg to server!\n"
;
sendMsgtoActivty(msg);
return
binder;
}
/**
* 把信息传递给activity
*
* @param msg
*/
private
void
sendMsgtoActivty(String msg) {
Intent intent =
new
Intent(
"com.android.Yao.msg"
);
intent.putExtra(
"msg"
, msg);
this
.sendBroadcast(intent);
}
@Override
public
void
onDestroy() {
super
.onDestroy();
if
(notificationManager!=
null
){
notificationManager.cancel(
0
);
notificationManager=
null
;
}
}
/**
* 在状态栏显示通知
*
* @param msg
*/
private
void
showNotification(String msg) {
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// 定义Notification的各种属性
Notification notification =
new
Notification(R.drawable.icon,
"A Message Coming!"
, System.currentTimeMillis());
//FLAG_AUTO_CANCEL 该通知能被状态栏的清除按钮给清除掉
//FLAG_NO_CLEAR 该通知不能被状态栏的清除按钮给清除掉
//FLAG_ONGOING_EVENT 通知放置在正在运行
//FLAG_INSISTENT 是否一直进行,比如音乐一直播放,知道用户响应
notification.flags |= Notification.FLAG_ONGOING_EVENT;
// 将此通知放到通知栏的"Ongoing"即"正在运行"组中
notification.flags |= Notification.FLAG_NO_CLEAR;
// 表明在点击了通知栏中的"清除通知"后,此通知不清除,经常与FLAG_ONGOING_EVENT一起使用
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
//DEFAULT_ALL 使用所有默认值,比如声音,震动,闪屏等等
//DEFAULT_LIGHTS 使用默认闪光提示
//DEFAULT_SOUNDS 使用默认提示声音
//DEFAULT_VIBRATE 使用默认手机震动,需加上<uses-permission android:name="android.permission.VIBRATE" />权限
notification.defaults = Notification.DEFAULT_LIGHTS;
//叠加效果常量
//notification.defaults=Notification.DEFAULT_LIGHTS|Notification.DEFAULT_SOUND;
notification.ledARGB = Color.BLUE;
notification.ledOnMS =
5000
;
//闪光时间,毫秒
// 设置通知的事件消息
//Intent notificationIntent =new Intent(MainActivity.this, MainActivity.class); // 点击该通知后要跳转的Activity
Intent notificationIntent =
new
Intent(getApplicationContext(), MainActivity.
class
);
// 加载类,如果直接通过类名,会在点击时重新加载页面,无法恢复最后页面状态。
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentItent = PendingIntent.getActivity(
this
,
0
, notificationIntent,
0
);
notification.setLatestEventInfo(
this
,
"Message"
,
"Message:"
+ msg, contentItent);
// 把Notification传递给NotificationManager
notificationManager.notify(
0
, notification);
}
/**
* 从activity获取信息
*
* @param msg
*/
public
void
receiverMsgtoActivity(String msg){
sendMsgtoActivty(
"\n receiverMsgtoActivity:"
+msg);
}
public
void
sendMsgtoServer(String msg) {
showNotification(msg);
}
public
class
LocalBinder
extends
Binder {
public
MyService getService() {
return
MyService.
this
;
}
}
}
|
2、新建MyBroadcastreceiver类,继承BroadcastReceiver,用来发送Intent启动服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package
com.ljq.activity;
import
android.content.BroadcastReceiver;
import
android.content.Context;
import
android.content.Intent;
/**
* 发送Intent启动服务
*
* @author jiqinlin
*
*/
public
class
MyBroadcastreceiver
extends
BroadcastReceiver {
@Override
public
void
onReceive(Context context, Intent intent) {
Intent service =
new
Intent(context, MyService.
class
);
context.startService(service);
}
}
|
3、新建MainActivity类,其实是一个activity,用来呈现界面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
package
com.ljq.activity;
import
java.util.List;
import
android.app.Activity;
import
android.app.ActivityManager;
import
android.content.BroadcastReceiver;
import
android.content.ComponentName;
import
android.content.Context;
import
android.content.Intent;
import
android.content.IntentFilter;
import
android.content.ServiceConnection;
import
android.os.Bundle;
import
android.os.IBinder;
import
android.util.Log;
import
android.view.View;
import
android.widget.TextView;
public
class
MainActivity
extends
Activity
implements
View.OnClickListener {
private
String msg =
""
;
private
TextView txtMsg;
private
UpdateReceiver receiver;
private
MyService myService;
private
final
static
String TAG=MainActivity.
class
.getSimpleName();
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtMsg = (TextView)
this
.findViewById(R.id.txtMsg);
this
.findViewById(R.id.btnStart).setOnClickListener(
this
);
this
.findViewById(R.id.btnSend).setOnClickListener(
this
);
//订阅广播Intent
receiver =
new
UpdateReceiver();
IntentFilter filter =
new
IntentFilter();
filter.addAction(
"com.android.Yao.msg"
);
this
.registerReceiver(receiver, filter);
//初始化时启动服务
//Intent intent = new Intent(MainActivity.this, MyService.class);
//this.bindService(intent, conn, BIND_AUTO_CREATE);
}
@Override
protected
void
onDestroy() {
super
.onDestroy();
//结束服务
if
(conn!=
null
){
unbindService(conn);
myService=
null
;
}
}
public
class
UpdateReceiver
extends
BroadcastReceiver {
@Override
public
void
onReceive(Context context, Intent intent) {
//获取service传过来的信息
msg = intent.getStringExtra(
"msg"
);
txtMsg.append(msg);
}
}
private
ServiceConnection conn =
new
ServiceConnection() {
@Override
public
void
onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.LocalBinder) service).getService();
Log.i(TAG,
"onServiceConnected myService: "
+myService);
}
@Override
public
void
onServiceDisconnected(ComponentName name) {
myService =
null
;
}
};
@Override
public
void
onClick(View v) {
Intent intent =
new
Intent(MainActivity.
this
, MyService.
class
);
switch
(v.getId()) {
case
R.id.btnStart:
//判断服务是否启动
if
(
false
==isServiceRunning(
this
, MyService.
class
.getName())){
Log.i(TAG,
"start "
+MyService.
class
.getSimpleName()+
" service"
);
this
.bindService(intent, conn, BIND_AUTO_CREATE);
}
Log.i(TAG, MyService.
class
.getName()+
" run status: "
+isServiceRunning(
this
, MyService.
class
.getName()));
break
;
case
R.id.btnSend:
//判断服务是否启动
if
(
false
==isServiceRunning(
this
, MyService.
class
.getName())){
Log.i(TAG,
"start "
+MyService.
class
.getSimpleName()+
" service"
);
this
.bindService(intent, conn, BIND_AUTO_CREATE);
}
Log.i(TAG, MyService.
class
.getName()+
" run status: "
+isServiceRunning(
this
, MyService.
class
.getName()));
Log.i(TAG,
"onClick myService: "
+myService);
//第一次启动服务时此处为null(小编认为虽然服务已启动成功,但是还没全部初始化)
if
(myService!=
null
){
myService.sendMsgtoServer(
"i am sending msg to server"
);
//从activity传递信息给service
myService.receiverMsgtoActivity(
"this is a msg"
);
}
break
;
}
}
/**
* 判断服务是否正在运行
*
* @param context
* @param className 判断的服务名字:包名+类名
* @return true在运行 false 不在运行
*/
public
static
boolean
isServiceRunning(Context context, String className) {
boolean
isRunning =
false
;
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
//获取所有的服务
List<ActivityManager.RunningServiceInfo> services= activityManager.getRunningServices(Integer.MAX_VALUE);
if
(services!=
null
&&services.size()>
0
){
for
(ActivityManager.RunningServiceInfo service : services){
if
(className.equals(service.service.getClassName())){
isRunning=
true
;
break
;
}
}
}
return
isRunning;
}
}
|
4、main.xml布局文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:orientation
=
"vertical"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
>
<
TextView
android:layout_width
=
"fill_parent"
android:layout_height
=
"wrap_content"
android:id
=
"@+id/txtMsg"
/>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:orientation
=
"horizontal"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
>
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"start service"
android:id
=
"@+id/btnStart"
/>
<
Button
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"send msg to server"
android:id
=
"@+id/btnSend"
/>
</
LinearLayout
>
</
LinearLayout
>
|
5、清单文件AndroidManifest.xml,用来配置组件等信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
manifest
xmlns:android
=
"http://schemas.android.com/apk/res/android"
package
=
"com.ljq.activity"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
application
android:icon
=
"@drawable/icon"
android:label
=
"@string/app_name"
>
<
activity
android:name
=
".MainActivity"
android:label
=
"@string/app_name"
>
<
intent-filter
>
<
action
android:name
=
"android.intent.action.MAIN"
/>
<
category
android:name
=
"android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
<
service
android:name
=
".MyService"
/>
<
receiver
android:name
=
".MyBroadcastreceiver"
/>
</
application
>
<
uses-sdk
android:minSdkVersion
=
"7"
/>
</
manifest
>
|
本案例代码下载地址
事实上,用Binder也可实现将值从Servcie传送至Activity。。。有兴趣的同志可以去看看这篇文章–>Android与Activity交互的本地服务示例