• Service通信详解


    1.使用Intent进行异步通讯

    在Service任务一旦完成后,就发送广播。开发者只需要实现一个BroadcastReceiver来监听响应既可。

    Activity.startService启动intentService,intentService完成任务后sendBroadcast()发送广播,BroadcastReceiver.startActivity()通知Activity操作结果。

    在任务结束后调用sendBroadcast(new Intent(Action));

    然后在广播中通知Activity执行的结果。这种方法的优点是,Android提供了现成的机制,而不需要开发者自己构建复杂的组件间消息处理系统。

    缺点是通知的结果受限于Intent,该方法也不适合在IntentService和Activity之间进行大规模快速更新操作,比如进度条,因为这会阻塞系统。

    具体的代码就不多讲,和基本的Service一样使用,只是多实现了个广播.

    2.本地绑定Service

    本地绑定Service可以在Service中给Activity提供更复杂的回调,因为那些耗时的操作必须放到Service的后台线程中,所以Service大部分回调应该是异步的。实际的调用触发后台操作立即返回,一旦操作完成,Service使用回调接口来通知Activity相应的执行结果.

    下面的例子添加了一个回调接口和一个实现AsyncTask的类,该类用来模拟后台操作。Service的onBind()方法返回一个localBinder对象,通过该对象客户端可以获取Service引用,并能执行doLongRunningOperation()方法。此方法创建了一个新的AsyncTask,并用客户端传递进来的参数执行execute()函数,在执行的过程中,回调函数会通知客户端新进度,当执行完毕会回调执行结果.

    这个例子以下载图片讲解其详细的实现步骤

    public class MyLocalService extends Service {
    private static final int NOTIFICATION_ID = 1001;//通知的ID
    private LocalBinder mLocalBinder = new LocalBinder();//用于返回的localBinder对象
    private Callback mCallback;


    @Override
    public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return this.mLocalBinder;
    }


    public class LocalBinder extends Binder {
    public MyLocalService getService() {
    return MyLocalService.this;
    }
    }


    public void setCallback(Callback callback) {
    this.mCallback = callback;
    }


    //回调接口,便于Activity与Service进行通信
    public interface Callback {
    void onOperationProgress(int progress);


    void onOperationCompleted(String result);
    }


    public void doLongRunningOperation(String urlString) {
    new MyAsyncTask().execute(urlString);
    }


    private class MyAsyncTask extends AsyncTask<String, Integer, String> {

    //处理任务之中
    @Override
    protected String doInBackground(String... params) {
    publishProgress(0);//更新进度条
    String result = downloadPhoto(params[0]);
    publishProgress(10);
    return result;
    }

    //执行任务之前
    @Override
    protected void onPreExecute() {
    super.onPreExecute();
    startForeground(NOTIFICATION_ID, buildNotification());//保持服务一直处于活跃状态。并创建通知
    }

    //返回任务执行结果
    @Override
    protected void onPostExecute(String result) {
    if (mCallback != null) {
    mCallback.onOperationCompleted(result);
    }
    mCallback.onOperationProgress(10);
    stopForeground(true);
    }

    //进度条更新
    @Override
    protected void onProgressUpdate(Integer... values) {
    if (mCallback != null && values.length > 0) {
    for (Integer value : values) {
    mCallback.onOperationProgress(value);
    }
    }
    }

    //任务(结束)调用取消后
    @Override
    protected void onCancelled(String result) {
    // TODO Auto-generated method stub
    super.onCancelled(result);
    stopForeground(true);
    }


    }

    //创建通知
    private Notification buildNotification() {
    Builder builder = new Builder(this);
    builder.setSmallIcon(R.drawable.ic_launcher);
    builder.setContentTitle("正在下载");
    builder.setContentText("图片还在下载中");
    Notification notification = builder.getNotification();
    return notification;
    }

    //下载图片
    private String downloadPhoto(String uriString) {
    HttpURLConnection conn = null;
    try {
    Thread.sleep(8000);
    URL url = new URL(uriString);
    conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    conn.setReadTimeout(8000);
    conn.setConnectTimeout(8000);
    InputStream is = conn.getInputStream();
    File file = new File(Environment.getExternalStorageDirectory()
    .toString() + "/" + "book.jpg");


    FileOutputStream fos = new FileOutputStream(file);
    byte[] buf = new byte[8196];
    int line = 0;
    while ((line = is.read(buf)) != -1) {
    fos.write(buf, 0, line);
    }
    fos.close();
    return "下载完成";
    } catch (Exception e) {
    e.printStackTrace();
    } finally {
    if (conn != null) {
    conn.disconnect();
    }
    }
    return "下载失败";
    }
    }

    下面的代码显示了更新后的Activity,值得注意的变化是Activity实现了MyLocalService.Callback接口,当在onServiceConnected()方法中获取到对Service的引用后,调用setCallback(this)方法,以便于Activity能在操作执行期间收到回调通知。还有一点非常重要,当用户离开Activity或者调用onPause()时,不要忘记移除回调监听,否则可能导致内存泄漏。

    public class MainActivity extends Activity implements ServiceConnection,
    MyLocalService.Callback {
    private Button start;
    private TextView content;
    private MyLocalService mService;
    private ProgressDialog dialog;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    this.start = (Button) findViewById(R.id.start);
    this.content = (TextView) findViewById(R.id.content);

    }

    //启动Service里的AsyncTask线程

    public void onTriggerLongRunningOperation(View view) {
    if (this.mService != null) {
    this.mService
    .doLongRunningOperation("http://image.baidu.com/i?tn=download&word=download&ie=utf8&fr=detail&url=http%3A%2F%2Fwenwen.soso.com%2Fp%2F20090901%2F20090901120123-329341688.jpg&thumburl=http%3A%2F%2Fimg5.imgtn.bdimg.com%2Fit%2Fu%3D390263343%2C2695552076%26fm%3D21%26gp%3D0.jpg");
    }
    }

    //进度条更新操作
    @Override
    public void onOperationProgress(int progress) {
    if (dialog == null) {
    dialog = new ProgressDialog(this);
    dialog.setMessage("正在下载");
    dialog.setMax(10);
    dialog.setCanceledOnTouchOutside(false);
    dialog.show();
    } else {
    dialog.setProgress(progress);
    }
    if (progress == 10 && dialog != null) {
    dialog.dismiss();
    }
    }


    @Override
    public void onOperationCompleted(String result) {
    this.content.setText(result);//设置下载图片的返回结果
    }

    //绑定服务后的初始化操作都写在该方法内
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    this.mService = ((MyLocalService.LocalBinder) service).getService();
    this.mService.setCallback(this);
    this.start.setOnClickListener(new OnClickListener() {


    @Override
    public void onClick(View v) {
    onTriggerLongRunningOperation(v);//执行Service下载线程
    start.setEnabled(false);//设置启动按钮为不可用
    }
    });
    }

    //注销之前结束后的收尾操作
    @Override
    public void onServiceDisconnected(ComponentName name) {
    this.mService = null;
    }


    @Override
    protected void onResume() {
    super.onResume();
    Intent bindIntent = new Intent(this, MyLocalService.class);
    bindService(bindIntent, this, BIND_AUTO_CREATE);//绑定Service
    }


    @Override
    protected void onPause() {
    super.onPause();
    if (this.mService != null) {
    this.mService.setCallback(null);
    unbindService(this);//解绑Service
    }
    }
    }

    如果用户在操作执行完前离开了Activity,Service还会继续执行,因为显式调用了StartForeground()方法。如果Activity在操作结束前又重新恢复,它会在成功绑定到Service后继续调用继续接受回调。这种行为很容易把耗时的操作和用户界面分开。并且允许Activity恢复后还能继续获取运行的状态。

    如果Service内部维护了一些状态,允许客户端获取这些状态以及订阅这些状态的变化是个很好的做法。因为当Activity重新恢复并绑定到Service后,这些状态可能已经发生了变化.

  • 相关阅读:
    oracle中查询表是否存在
    asp.net webform/mvc导出Excel通用代码
    分享给大家一个500G.Net ftp资料库
    C# 使用TopShelf实现Windows服务部署
    C#基于Quartz.NET实现任务调度并部署Windows服务
    附加进程找不到w3wp.exe进程解决方案
    在vs2015中使用附加进程的方式调试IIS中的页面
    删除datatable的行后,出现“不能通过已删除的行访问该行的信息”的错误,即DeletedRowInaccessibleException
    C# FTP操作类
    C# vb .net实现发光效果
  • 原文地址:https://www.cnblogs.com/liyuanjinglyj/p/liyuanjing_service.html
Copyright © 2020-2023  润新知