65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.42/5 (8投票s)

2013年10月3日

CPOL

2分钟阅读

viewsIcon

41837

downloadIcon

753

如何通过 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 进行回调。我可能没有搜索足够多,因为我没有找到我喜欢的示例 Smile | <img src= ">

无论如何,这是我自己构建的示例。该示例基于 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 Smile | <img src=

关注点

对我来说,深入研究纯消息传递的通信方式是一件很棒的事情。

历史

初始版本。

© . All rights reserved.