Android AIDL和远程Service调用示例代码

Android:AIDL和远程Service调用

本讲的内容,理解起来很难,也许你看了很多资料也看不明白,但是用起来缺简单的要命。所以我们干脆拿一个音乐播放器中进度条的实例来说明一下AIDL和Remote Service的价值和使用方法,你把这个例子跑一边,体会一下就OK了。下面的例子是我

正在准备的项目实例中的一部分。

首先说明一下我们面临的问题,如果看不懂下面的描述请看前面的课程:

第一、我们知道在AndroId中如果需要进行音乐播放,最方面的方法就是使用自带的MediaPlayer对象,如果我们在Activity中控制MediaPlayer对象进行播放,那么一旦你打开了另外一个程序譬如浏览器,那么歌声就会立刻停止,这当然不是我们需要的结果。 我们需要的是在做其他事情的同时能够在后台听歌,于是我们就需要把对MediaPlayer对象的操作放在后台Service中去。

第二、我们已经把对MediaPlayer的操作转移到Service中去了,按照我们以前的做法,我们在Activity中发送一个Intent对象给Service对象,在Intent中传送播放啊、暂停啊一类的信息给Service,这样Service就知道该怎么做了。这一切看起来很美好,可是现在出了一个新问题,那就是我想在Activity中显示一个进度条,这个进度条要跟着Service中的MediaPlayer中的歌曲进度同步向前走,而且如果我点击进度条中的某一个位置,还想让歌曲跳转到新的时间点继续播放,这个,该怎么实现?

第三、我们需要在Activity中操作Service中的MediaPlayer对象,就好像这个对象是自己的一样。我们可以采用Android接口定义语言 AIDL(Android Interface Definition Language)技术:

1、把Service中针对MediaPlayer的操作封装成一个接口(.aidl文件)
2、在Service中建个子类实现这接口的存根(stub)对象
3、并在onBind()方法中返回这个存根对象。
4、在Activity中使用绑定服务的方式连接Service,但是不用Intent来传递信息,而是在ServiceConnection的onServiceConnected方法里,获得Service中Stub对象的客户端使用代理。我们通过操作Activity中的代理就可以达到操作Service中的MediaPlayer对象的目的。这样我们就可以想用本地对象一样操作Service中的对象了,那么进度条一类的需求自然也就迎刃而解。

下面的例子,并不是专门为本讲准备的,所以有些无关代码,而且没加注释,请见谅(本例完整讲解会放在项目实训中,正在准备):

1、新建一个项目 App_elfPlayer ,启动Activity是个启动画面:CoverActivity

2、AndroidManifest.xml 的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest package="app.android.elfplayer" xmlns:android="http://schemas.android.com/apk/res/android" android:versioncode="1" android:versionname="1.0">
  <uses -sdk="" android:minsdkversion="7">
  <uses -permission="" android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses>

  <application android:label="@string/app_name" android:icon="@drawable/icon">
    <activity android:name=".CoverActivity">
      <intent -filter="">
        <action android:name="android.intent.action.MAIN">
        <category android:name="android.intent.category.LAUNCHER">
      </category></action></intent>
    </activity>
    <activity android:name=".PlayerActivity">
    </activity>
    <service android:name=".MusicService" android:enabled="true">
    </service>
  </application>

</uses></manifest>

我们注意到有2个Activity,1个Service,还有读写外部存储的权限声明3、CoverActivity.java的代码如下:这是个全屏的启动画面,2秒后会跳转到PlayerActivity

package app.android.elfplayer;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.Window;
import android.view.WindowManager;

public class CoverActivity extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.cover);

    new Handler().postDelayed(new Runnable(){

     @Override
     public void run() {
      Intent mainIntent = new Intent(CoverActivity.this,PlayerActivity.class);
      CoverActivity.this.startActivity(mainIntent);
      CoverActivity.this.finish();
     }

    }, 2000);

  }
}

4、PlayerActivity.java的代码如下:

package app.android.elfplayer;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class PlayerActivity extends Activity {

  public static final int PLAY = 1;
  public static final int PAUSE = 2;

  ImageButton imageButtonFavorite;
  ImageButton imageButtonNext;
  ImageButton imageButtonPlay;
  ImageButton imageButtonPre;
  ImageButton imageButtonRepeat;
  SeekBar musicSeekBar;

  IServicePlayer iPlayer;
  boolean isPlaying = false;
  boolean isLoop = false;  

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.player);

    imageButtonFavorite = (ImageButton) findViewById(R.id.imageButtonFavorite);
    imageButtonNext = (ImageButton) findViewById(R.id.imageButtonNext);
    imageButtonPlay = (ImageButton) findViewById(R.id.imageButtonPlay);
    imageButtonPre = (ImageButton) findViewById(R.id.imageButtonPre);
    imageButtonRepeat = (ImageButton) findViewById(R.id.imageButtonRepeat);
    musicSeekBar = (SeekBar) findViewById(R.id.musicSeekBar);

    bindService(new Intent(PlayerActivity.this, MusicService.class), conn, Context.BIND_AUTO_CREATE);
    startService(new Intent(PlayerActivity.this, MusicService.class));

    imageButtonPlay.setOnClickListener(new View.OnClickListener() {

      @Override
      public void onClick(View v) {
        Log.i("yao", "imageButtonPlay -> onClick");

        if (!isPlaying) {
          try {
            iPlayer.play();
          } catch (RemoteException e) {
            e.printStackTrace();
          }
          imageButtonPlay.setBackgroundResource(R.drawable.pause_button);
          isPlaying = true;

        } else {
          try {
            iPlayer.pause();
          } catch (RemoteException e) {
            e.printStackTrace();
          }
          imageButtonPlay.setBackgroundResource(R.drawable.play_button);
          isPlaying = false;
        }
      }
    });

    musicSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
      }

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {
      }

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {
        if (iPlayer != null) {
          try {
            iPlayer.seekTo(seekBar.getProgress());
          } catch (RemoteException e) {
            e.printStackTrace();
          }
        }
      }
    });

    handler.post(updateThread);
  }

  private ServiceConnection conn = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
      Log.i("yao", "ServiceConnection -> onServiceConnected");
      iPlayer = IServicePlayer.Stub.asInterface(service);
    }

    public void onServiceDisconnected(ComponentName className) {
    };
  };

  Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
    };
  };

  private Runnable updateThread = new Runnable() {
    @Override
    public void run() {
      if (iPlayer != null) {
        try {
          musicSeekBar.setMax(iPlayer.getDuration());
          musicSeekBar.setProgress(iPlayer.getCurrentPosition());
        } catch (RemoteException e) {
          e.printStackTrace();
        }
      }
      handler.post(updateThread);
    }
  };

}

5、其中用到的IServicePlayer.aidl,放在和Java文件相同的包中,内容如下:

package app.android.elfplayer;
interface IServicePlayer{
  void play();
  void pause();
  void stop();
  int getDuration();
  int getCurrentPosition();
  void seekTo(int current);
  boolean setLoop(boolean loop);
}

一旦你写好了这个IServicePlayer.aidl文件,ADT会自动帮你在gen目录下生成IServicePlayer.java文件。

6、MusicService.java的内容如下:

package app.android.elfplayer;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MusicService extends Service {

  String tag = "yao";

  public static MediaPlayer mPlayer;

  public boolean isPause = false;

  IServicePlayer.Stub stub = new IServicePlayer.Stub() {

    @Override
    public void play() throws RemoteException {
      mPlayer.start();
    }

    @Override
    public void pause() throws RemoteException {
      mPlayer.pause();
    }

    @Override
    public void stop() throws RemoteException {
      mPlayer.stop();
    }

    @Override
    public int getDuration() throws RemoteException {
      return mPlayer.getDuration();
    }

    @Override
    public int getCurrentPosition() throws RemoteException {
      return mPlayer.getCurrentPosition();
    }

    @Override
    public void seekTo(int current) throws RemoteException {
      mPlayer.seekTo(current);
    }

    @Override
    public boolean setLoop(boolean loop) throws RemoteException {
      return false;
    }

  };

  @Override
  public void onCreate() {
    Log.i(tag, "MusicService onCreate()");
    mPlayer = MediaPlayer.create(getApplicationContext(), ElfPlayerUtil.getFileinSD("wind.mp3"));
  }

  @Override
  public IBinder onBind(Intent intent) {
    return stub;
  }

}

7、实现效果图:

最后总结一下,AIDL提供了一种非常简单的方式,让我们可以把一个进程内的对象或方法暴露给另一个程序使用,就好象另一个程序也拥有这些功能一样。

以上就是Android AIDL和远程Service 的介绍和简单应用,后续继续补充相关知识,谢谢大家的支持!

(0)

相关推荐

  • Android中如何利用AIDL机制调用远程服务

    在Android中,每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢?显然, Java中是不支持跨进程内存共享的.因此要传递对象,需要把对象解析成操作系统能够理解的数据格式,以达到跨界对象访问的目的.在JavaEE中,采用RMI通过序列化传递对象.在Android中,则采用AIDL(Android Interface DefinitionLanguage:接口描述语言)方式实现. AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Andro

  • 基于Android AIDL进程间通信接口使用介绍

    AIDL:Android Interface Definition Language,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口. ICP:Interprocess Communication ,内部进程通信. 使用: 1.先创建一个aidl文件,aidl文件的定义和java代码类似,但是!它可以引用其它aidl文件中定义的接口和类,但是不能引用自定义的java类文件中定义的接口和类,要引用自定义的接口或类,需要为此类也定义一个对应的aidl文件,并且此

  • 实例讲解Android中的AIDL内部进程通信接口使用

    首先描述下我们想要实现的内容,我们希望在一个应用中通过点击按钮,去操作另一个进程中应用的音乐播放功能. 如图,我们点击"播放"时,系统就会去远程调用我们提供的一个service(与当前service不是同一个应用哦),然后操作service中的音乐播放,点击"停止"则会终止播放.想要重新播放的话,必须先点"销毁service",再点播放按钮哦.(至于这里为什么要先点销毁按钮才能播放,完全是为了给大家展示下,远程调用service时,怎么去解绑se

  • Android编程实现AIDL(跨进程通信)的方法详解

    本文实例讲述了Android编程实现AIDL(跨进程通信)的方法.分享给大家供大家参考,具体如下: 一. 概述: 跨进程通信(AIDL),主要实现进程(应用)间数据共享功能. 二. 实现流程: 1. 服务器端实现: (1)目录结构,如下图: (2)实现*.aidl文件: A. IAIDLService.aidl实现: package com.focus.aidl; import com.focus.aidl.Person; interface IAIDLService { String getN

  • 浅谈Android Aidl 通讯机制

    服务端: 首先是编写一个aidl文件,注意AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符:AIDL运行方法有任何类型的参数和返回值,在java的类型中,以下的类型使用时不需要导入包(import),基本数据类型.String.Map.List.当然为了避免出错,建议只要使用了,就导入包. 然后在服务端启动一个服务并注册,编写一个任意类实现AIDL文件生成的JAVA接口Stub! 最后在service里面实例化你的任意类并且在onBind(Intent a)方法上

  • Android AIDL——进程通信机制详解

    Android  AIDL, Android进程机制通信机制,这里就整理下AIDL 的知识,帮助大家学习理解此部分知识! 什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言.听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具.它的存在形式是一种 .aidl 文件,开发者需要做的就是在该文件中定义进程间通信的接口,编译的时候 IDE 就会根据我们的 .aidl 接口文件生成可供项目使用的 .java 文件,这和

  • Android 进程间通信AIDL使用详解

    一.概述 AIDL 意思即 Android Interface Definition Language,翻译过来就是Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码.从某种意义上说AIDL其实是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此而生成的一个IInterface的实例代码,AIDL其实是为了避免我们重复编写代码而出现的一个模板 设计AIDL这门语言的目的就是为了实现进程间通信.在Android系统中,每个进程

  • Android 使用【AIDL】调用外部服务的解决方法

    在Android 中有一种服务说是服务其实倒不如说是一个接口,这个接口名为:Android Interface Definition Language ,这个接口可提供跨进程访问服务,英文缩写为:AIDL. 此种服务的好处在于,多个应用程序之间建立共同的服务机制,通过AIDL在不同应用程序之间达到数据的共享和数据相互操作,下面将通过一个DEMO 演示AIDL 是如何为应用程序之间提供服务的.本文大纲为:•1.创建AIDL 服务端.•2.创建AIDL 客户端.•3.客户端调用服务端提供的服务接口.

  • Android AIDL和远程Service调用示例代码

    Android:AIDL和远程Service调用 本讲的内容,理解起来很难,也许你看了很多资料也看不明白,但是用起来缺简单的要命.所以我们干脆拿一个音乐播放器中进度条的实例来说明一下AIDL和Remote Service的价值和使用方法,你把这个例子跑一边,体会一下就OK了.下面的例子是我 正在准备的项目实例中的一部分. 首先说明一下我们面临的问题,如果看不懂下面的描述请看前面的课程: 第一.我们知道在AndroId中如果需要进行音乐播放,最方面的方法就是使用自带的MediaPlayer对象,如

  • Android自定义控件之翻转按钮的示例代码

    本文介绍了Android自定义控件之翻转按钮的示例代码,分享给大家,具体如下: 先看一下效果 一.先定义控件的基本结构 这里我们定义一个容器,所以是在ViewGroup的基础上扩展. 简单起见,直接使用扩展自ViewGroup的LinearLayout,并将我们的控件扩展自LinearLayout. 1.按钮的基本布局如下 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr

  • Android视频悬浮窗口实现的示例代码

    前言 本文例子实现了点击显示悬浮窗口,同时窗口可播放视频,拖动位置,点击关闭及返回 APP 页面,通过例子来讲述悬浮窗口实现原理及细节处理,效果图如下所示: 悬浮窗口.gif 原理 WindowManager 对 View 视图进行添加.移除.更新处理: WindowManager.LayoutParams 对窗口参数进行一系列设置. 实现 首先,需要添加相对应悬浮窗权限: <uses-permission android:name="android.permission.SYSTEM_A

  • Android Flutter实现点赞效果的示例代码

    目录 前言 绘制小手 完整源码 前言 点赞这个动作不得不说在社交.短视频等App中实在是太常见了,当用户手指按下去的那一刻,给用户一个好的反馈效果也是非常重要的,这样用户点起赞来才会有一种强烈的我点了赞的效果,那么今天我们就用Flutter实现一个掘金App上的点赞效果. 首先我们看下掘金App的点赞组成部分,有一个小手,点赞数字.点赞气泡效果,还有一个震动反馈,接下来我们一步一步实现. 知识点:绘制.动画.震动反馈 绘制小手 这里我们使用Flutter的Icon图标中的点赞小手,Icons图标

  • Android实现绘制LocationMarkerView图的示例代码

    目录 LocationMarkerView图的绘制 绘制整公里的文字 添加动画 LocationMarker是运动轨迹上Start.End, 以及整公里点上笔者自定义绘制的一个MarkerView, 当时之所以没有用设计给的icon是这个MarkerView里需要填充动态的数字,自定义的话自主性比较大些也方面做动画,之前的Android 传统自定义View的实现可以看这篇文章介绍 运动App自定义LocationMarker. 这里先看下gif动图: LocationMarkerView图的绘制

  • Android实现用文字生成图片的示例代码

    本文介绍了Android实现用文字生成图片的示例代码,分享给大家,具体如下: 效果图 我们先来看看效果图,可以看到下图由各种颜色的"美"字拼接而成,形成了一张不一样的图片. 原理 生成这种图片的原理很简单,但是当时看开源项目时愣是看不懂,因为没学过Python,但是仔细研究,终于能慢慢的理解该开源项目源码,并把它改写成Android平台的源代码.下面把这个算法的主要内容讲给大家,该算法大致原理如下: 1.根据原图片的大小和字体的大小创建一张空白图片 2.把原图片按字体的大小分成若干块,

  • Android自定义滑动验证条的示例代码

    本文介绍了Android自定义滑动验证条的示例代码,分享给大家,具体如下: *注:不知道为什么,h5的标签在这里没用了,所以我也只能用Markdown的语法来写了 项目地址:https://github.com/994866755/handsomeYe.seekbar.github.io 需求: 在我们的某些应用中需要滑动验证.比如说这个样子的: 刚开始我也很懵逼要怎么去弄,结果我去看了一些人的代码,有人是用自定义viewgroup去做,就是viewgroup包含滑动块和滑动条.但我觉得太麻烦,

  • Android 给图片加上水印的示例代码(支持logo+文字)

    本文介绍了Android 给图片加上水印的示例代码(支持logo+文字),分享给大家,具体如下: 现在我们想要往图片上打上水印,该水印应符合这样的需求的: 支持logo+文字: 文字信息支持多行展示: 用户可以选择水印在图片上的生成位置(左上.右上.右下和左下). 粗略的结构图低配版大概就长这样... 水印结构图.png 现在提供这样的一种思路去实现这一个需求,我们可以通过自定义一个view,view的布局中包含logo.公司名称和相关信息,这个view就是我们要打上图片的水印. 这样的一个vi

  • Android TextView实现词组高亮的示例代码

    本文介绍了Android TextView实现词组高亮的示例代码,分享给大家,具体如下: HighlightTextView Android文本高亮控件,基于View实现. 特点 文本高亮 单词自动换行 高亮词组保持在同一行显示 效果如下: 主要逻辑: 两个 Paint 负责绘制不同的文字 在每次绘制之前计算将要绘制的文本是否会超出屏幕宽度,如果超出则换行 protected void onDraw(Canvas canvas) { super.onDraw(canvas); float x_d

  • Android实现强制下线功能的示例代码

    一.回顾 上次连载写了两个类,一个类ActivityCollector.java用于管理所有的活动:一个类是BaseActivity.java作为所有活动的父类: 还有一个放在layout目录中的登录界面login.xml 二.登录页面的活动 接下来写一个登录页面的活动,继承自BaseActivity.java package com.example.broadcastbestpractice; import android.content.Intent; import android.os.B

随机推荐