使用消息传递进行异步服务回调






4.42/5 (8投票s)
如何通过 LocalBroadcastManager 使用消息传递进行回调。
引言
这段代码展示了如何使用消息传递(而非 RPC 绑定)来集成 Activity 和 Service。
代码模拟了一个长时间运行的进程 - 例如与 Web 服务器的数据同步。
该示例包含一个 Activity (MainActivity),其中包含:
- 一个 ProgressBar(显示服务进度)
- 一个 TextView(显示最终服务结果)
- 一个 Button(用于启动服务)
以及一个 Service (ServerSyncService)。当 ServerSyncService 接收到 Intent 时,它会执行以下逻辑:
- 循环 1 到 100
- 更新 ProgressBar(通过回调)
- 休眠 200 毫秒
- 将 TextView 设置为“来自服务器的数据...”(通过回调)
通过 LocalBroadcastManager 将 Intent 发送到 MainActivity 来完成从 Service 的回调。
Intent 包含一个命令和一个数据部分(作为 putExtras 嵌入)。命令是
- 命令
- 数据
命令结构如下
命令 | 数据 |
UPDATE_PROGRESS | 完成百分比 |
RESULT | 来自服务器的数据 |
为了避免“魔术数字”,使用了一个辅助类“Constant”来保存全局常量 - 例如 putExtra 键名。
一个重要的特性是,即使 Activity 被旋转(重启),它仍然可以正确更新。
背景
我教授 Android 编程,一直在寻找一个简单的示例来展示如何使用消息传递从 Service 进行回调。我可能没有搜索足够多,因为我没有找到我喜欢的示例 ">
无论如何,这是我自己构建的示例。该示例基于 LocalBroadcastManager
使用代码
辅助类“Constant”
package dk.eal.kbr.android.example.asyncservicecallbacktoactivity.communication;
/**
* Created by kbr on 01-10-13.
*/
public class Constant
{
public static final int UPDATE_PROGRESS = 1;
public static final int RESULT = 2;
public static final String FILTER =
"dk.eal.kbr.android.example.asyncservicecallbacktoactivity.communication.REQUEST_PROCESSED";
public static final String COMMAND = "COMMAND";
public static final String DATA = "DATA";
}
MainActivity 布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity">
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_gravity="left|center_vertical" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/result"
android:id="@+id/textView"
android:layout_gravity="left|center_vertical" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Service"
android:id="@+id/button"
android:onClick="onStartService_Clicked"
android:layout_gravity="left|center_vertical" />
</LinearLayout>
MainActivity Java 代码
package dk.eal.kbr.android.example.asyncservicecallbacktoactivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.app.Activity;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import dk.eal.kbr.android.example.asyncservicecallbacktoactivity.communication.Constant;
public class MainActivity extends Activity {
private ProgressBar mProgress;
private TextView result;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mProgress = (ProgressBar)findViewById(R.id.progressBar);
mProgress.setMax(100);
result = (TextView)findViewById(R.id.textView);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter(Constant.FILTER));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void onStartService_Clicked(View v)
{
mProgress.setProgress(0);
result.setText("");
Intent intent = new Intent(this, ServerSyncService.class);
startService(intent);
}
@Override
protected void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver((mMessageReceiver), new IntentFilter(Constant.FILTER));
}
@Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onStop();
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("KBR", "Got message");
handleMessage(intent);
}
};
private void handleMessage(Intent msg)
{
Bundle data = msg.getExtras();
switch (data.getInt(Constant.COMMAND, 0))
{
case Constant.UPDATE_PROGRESS:
int progress = data.getInt(Constant.DATA, 0);
mProgress.setProgress(progress);
break;
case Constant.RESULT:
String res = data.getString(Constant.DATA);
result.setText(res);
break;
default:
break;
}
}
}
重要代码:
在方法
- onCreate
- onStart
- onStop
中,非常重要的是使用 LocalBroadcastManager 来开始/停止监听来自 ServerSyncService 的传入 Intent。
当 Intent 抵达时,会调用方法“handleMessage”。“handleMessage”检查消息的命令部分,并在主线程上执行请求的操作。
ServerSyncService Java 代码
package dk.eal.kbr.android.example.asyncservicecallbacktoactivity;
import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import dk.eal.kbr.android.example.asyncservicecallbacktoactivity.communication.Constant;
/**
* Created by kbr on 01-10-13.
*/
public class ServerSyncService extends IntentService {
public ServerSyncService() {
super("ServerSyncService");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
protected void onHandleIntent(Intent intent) {
for(int i = 1 ; i <= 100 ; i++)
{
sendUpdateMessage(i);
try
{
Thread.sleep(200);
}
catch(Exception e)
{
Log.d("KBR", "SendError: " + e.getMessage());
}
}
sendResultMessage("Data fra serveren...");
stopSelf();
}
private void sendUpdateMessage(int pct) {
Log.d("KBR", "Broadcasting update message: " + pct);
Intent intent = new Intent(Constant.FILTER);
intent.putExtra(Constant.COMMAND, Constant.UPDATE_PROGRESS);
intent.putExtra(Constant.DATA, pct);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void sendResultMessage(String data) {
Log.d("sender", "Broadcasting result message: " + data);
Intent intent = new Intent(Constant.FILTER);
intent.putExtra(Constant.COMMAND, Constant.RESULT);
intent.putExtra(Constant.DATA, data);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
代码中比较有趣的部分是方法 sendUpdateMessage 和 sendResultMessage。它们分别构建用于 ProgressBar 更新和服务结果的消息。
清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dk.eal.kbr.android.example.asyncservicecallbacktoactivity"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="16" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="dk.eal.kbr.android.example.asyncservicecallbacktoactivity.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=".ServerSyncService">
</service>
</application>
</manifest>
记住在清单文件中包含 Service
关注点
对我来说,深入研究纯消息传递的通信方式是一件很棒的事情。
历史
初始版本。