欢迎光临散文网 会员登陆 & 注册

第七章 后台服务(远程服务)

2018-11-11 23:58 作者:swiss126  | 我要投稿

参考资料:

《Android应用程序开发》ISBN 9787302283164

参考软件:

Android Studio、Eclipse+ADT、Android SDK、JDK

远程服务

一、什么是远程服务

简单来说就是:从一个进程调用另一个进程中的服务程序。

二、Android实现原理

      如图1所示:

图1 android远程服务示意图

(1)    客户端一般是自定义的Activity,通过bindService()发起服务绑定

(2)    服务端,通过onBind()响应绑定请求,并返回共接口的Binder

(3)    客户端将接收到的Binder转换成接口对象ISecondary,好比获得了远程对象通信接口的应用

(4)    由于客户端与服务端定义了相同的接口(AIDL文档相同),所以可以通过(3)中的ISecondary对象调用接口中的方法,如此一来访问远程服务的方法如同访问本地对象的方法一般

(5)    通过接口实现代码将请求传给服务对象

(6)    服务代码调用自己的方法

一、 进程间的通讯IPC

q  在Android系统中,每个应用程序在各自的进程中运行,而且出于安全原因的考虑,这些进程之间彼此是隔离的,进程之间传递数据和对象,需要使用Android支持的进程间通信(Inter-Process Communication,IPC)机制

q  在Unix/Linux系统中,传统的IPC机制包括共享内存、管道、消息队列和socket等等,这些IPC机制虽然被广泛使用,但仍然存在着固有的缺陷,如容易产生错误、难于维护等等

q  在Android系统中,没有使用传统的IPC机制,而是采用Intent和远程服务的方式实现IPC,使应用程序具有更好的独立性和鲁棒性

 

q  Android系统允许应用程序使用Intent启动Activity和Service,同时Intent可以传递数据,是一种简单、高效、易于使用的IPC机制

q  Android系统的另一种IPC机制就是远程服务,服务和调用者在不同的两个进程中,调用过程需要跨越进程才能实现

q  在Android系统中使用远程服务,一般按照以下三个步骤实现

        n 使用AIDL语言定义远程服务的接口

        n 根据AIDL语言定义的接口,在具体的Service类中实现接口中定义的方法和属性

        n 在需要调用远程服务的组件中,通过相同的AIDL接口文件,调用远程服务

二、服务创建与调用

q  在Android系统中,进程之间不能直接访问相互的内存控件,因此为了使数据能够在不同进程间传递,数据必须转换成能够穿越进程边界的系统级原语,同时,在数据完成进程边界穿越后,还需要转换回原有的格式

q  AIDL(Android Interface Definition Language)是Android系统自定义的接口描述语言,可以简化进程间数据格式转换和数据交换的代码,通过定义Service内部的公共方法,允许在不同进程间的调用者和Service之间相互传递数据

q  AIDL的IPC机制、COM和Corba都是基于接口的轻量级进程通信机制

 

 

q  AIDL语言的语法与Java语言的接口定义非常相似,唯一不同之处在于,AIDL允许定义函数参数的传递方向

q  AIDL支持三种方向:in、out和inout

        n 标识为in的参数将从调用者传递到远程服务中

        n 标识为out的参数将从远程服务传递到调用者中

        n 标识为inout的参数将先从调用者传递到远程服务中,再从远程服务返回给调用者

q  如果不标识参数的传递方向,默认所有函数的传递方向为in

q  出于性能方面的考虑,不要在参数中标识不需要的传递方向

 

 

q  远程服务的创建和调用需要使用AIDL语言,一般分为以下几个过程

        n 使用AIDL语言定义远程服务的接口

        n 通过继承Service类实现远程服务

        n 绑定和使用远程服务

三、服务端的建立

(1)建立一个android应用

向导完成

(2)使用AIDL语言定义远程服务的接口

 

 

package com.example.serverdemo;

 

 

 

publicinterface IMathService {

 

  long add(long a,long b);

 

}

 

 

 

重命名

 

直接到项目文件夹中改名

然后在项目中刷新

 

 

 

 

 

 

 

n IMathService.java文件根据IMathService.aidl的定义,生成了一个内部静态抽象类Stub,Stub继承了Binder类,并实现IMathService接口

n 在Stub类中,还包含一个重要的静态类Proxy。可以认为Stub类用来实现本地服务调用,Proxy类用来实现远程服务调用,将Proxy作为Stub的内部类完全是出于使用方便的目的

 

(3)通过继承Service类实现远程服务

 

 

package com.example.serverdemo;

 

 

 

import android.app.Service;

 

import android.content.Intent;

 

import android.os.IBinder;

 

import android.os.RemoteException;

 

import android.widget.Toast;

 

 

 

public class MathService extends Service  {

 

         private  final IMathService.Stub mBinder = new IMathService.Stub(){

 

 

 

                   @Override

 

                   public  long add(long a, long b) throws RemoteException {

 

                            //  TODO Auto-generated method stub

 

                            return  a + b;

 

                   }

 

                  

 

         };

 

 

 

         @Override

 

         public  IBinder onBind(Intent intent) {

 

                   Toast.makeText(this,  "远程绑定:MathService",

 

                                Toast.LENGTH_SHORT).show();

 

                   return  mBinder;

 

         }

 

 

 

         @Override

 

         public  boolean  onUnbind  (Intent intent){

 

                     Toast.makeText(this, "取消远程绑定:MathService",

 

                                           Toast.LENGTH_SHORT).show(); 

 

                   return  false;

 

         }

 

}

 

(4)注册并隐式启动服务

四、客户端的建立

(1)建立android项目

 


 

(2)建立和服务端一样的AIDL

从服务端copy一份,改下包名

 

 

package com.example.clientdemo;

 

 

 

interface IMathService {

 

  long  add(long a,long b);

 

}

 

 

 

(3)绑定和使用远程服务

 

 五、自定义数据类型传递

http://wenku.baidu.com/link?url=Ib7a77WsZpgrcPN3JQ4GUqO4K9v2Yzxi7lYPseV5rk-66DEQWL4J4fPs6x0MdEuRsxr7-cgeja8NlgCh2nDGPKEG6qSmI7swgHb6DgPZiUO

 

q  在Android系统中,进程间传递的数据包括:

        n Java语言支持的基本数据类型

        n 用户自定义的数据类型

q  为了使数据能够穿越进程边界,所有数据都必须是“可打包”的

q  对于Java语言的基本数据类型,打包过程是自动完成的

q  但对于自定义的数据类型,用户则需要实现Parcelable接口,使自定义的数据类型能够转换为系统级原语保存在Parcel对象中,穿越进程边界后可再转换为初始格式

实例

(1)服务器端建立

A、建立Role对象用来被传递

 

包--àNew-àclass

 

 

 

 

package com.lsu.aidlserverdemo;

 

 

 

import android.graphics.Bitmap;

 

import android.os.Parcel;

 

import android.os.Parcelable;

 

 

 

publicclass Role implements Parcelable {

 

    private String name//名字

 

    private String vocation//职业

 

    private String profession//专业

 

    private String weapon//武器

 

    private String GS//GS

 

    private String credit//当前声望

 

    private Bitmap image//头像

 

    public String getName() {

 

        returnname;

 

    }

 

 

 

    publicvoid setName(String name) {

 

        this.name = name;

 

    }

 

 

 

    public String getVocation() {

 

        returnvocation;

 

    }

 

 

 

    publicvoid setVocation(String vocation) {

 

        this.vocation = vocation;

 

    }

 

 

 

    public String getProfession() {

 

        returnprofession;

 

    }

 

 

 

    publicvoid setProfession(String profession)  {

 

        this.profession = profession;

 

    }

 

 

 

    public String getWeapon() {

 

        returnweapon;

 

    }

 

 

 

    publicvoid setWeapon(String weapon) {

 

        this.weapon = weapon;

 

    }

 

 

 

    public String getGS() {

 

        returnGS;

 

    }

 

 

 

    publicvoid setGS(String gS) {

 

        GS = gS;

 

    }

 

 

 

    public String getCredit() {

 

        returncredit;

 

    }

 

 

 

    publicvoid setCredit(String credit) {

 

        this.credit = credit;

 

    }

 

 

 

    public Bitmap getImage() {

 

        returnimage;

 

    }

 

 

 

    publicvoid setImage(Bitmap image) {

 

        this.image = image;

 

    }

 

 

 

   

 

 

 

    @Override

 

    publicint describeContents() {

 

        // TODO Auto-generated method stub

 

        return 0;

 

    }

 

 

 

    @Override

 

    publicvoid writeToParcel(Parcel dest, int flags) {

 

        dest.writeString(name);

 

        dest.writeString(vocation);

 

        dest.writeString(profession);

 

        dest.writeString(weapon);

 

        dest.writeString(GS);

 

        dest.writeString(credit);

 

        image.writeToParcel(dest, 0);

 

 

 

    }

 

    publicstaticfinal Parcelable.Creator<Role> CREATOR = new  Creator<Role>(){

 

 

 

        @Override

 

        public Role createFromParcel(Parcel  source) {

 

            Role role = new Role();

 

            role.name = source.readString();

 

            role.vocation = source.readString();

 

            role.profession = source.readString();

 

            role.GS = source.readString();

 

            role.credit = source.readString();

 

            role.weapon = source.readString();

 

            role.image = Bitmap.CREATOR.createFromParcel(source);

 

                   

 

            return role;

 

        }

 

 

 

        @Override

 

        public Role[] newArray(int size) {

 

            // TODO Auto-generated method stub

 

            returnnew Role[size];

 

        }

 

       

 

    } ;

 

 

 

}

 

 

 

 

B、建立Role.aidl

 

C、首先建立MyAidl.aidl

File---ànew---àinterface

 

到源代码文件夹改名

在项目中刷新

 

代码 1

 

 

package com.lsu.aidlserverdemo;

 

 

 

 

 

import com.lsu.aidlserverdemo.Role;

 

 

 

interface MyAidl {

 

    List  getRoleList(); //得到所有的游戏角色

 

    Role  getRole(String name);

 

    String  getName();

 

}

 

 

 

 

先看主方法,里面定义了3个方法,分别为getRoleList()、getRole(String name)、getName()。返回值分别为List、Role、String。

需要特别注意,不是基本数据类型,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置,每个Aidl文件中只能定义一个Interface。       

 

其中Role是我们自定义的实体类,Aidl并不能找到这个类,所以需要倒包,但是这个包是Role.java和Role.aidl所在的包。Role.aidl是对Role.java的一个指向

 

D、建立Service

代码 2

 

 

package com.lsu.aidlserverdemo;

 

 

 

import java.util.ArrayList;

 

import java.util.List;

 

 

 

import android.app.Service;

 

import android.content.Intent;

 

import android.graphics.BitmapFactory;

 

import android.os.IBinder;

 

import android.os.RemoteException;

 

 

 

public class DataProvider extends Service  {

 

         public  static final String TAG = "aidlService";

 

         ArrayList<Role>  list;

 

 

 

        

 

         @Override

 

         public  void onCreate() {            

 

                   super.onCreate();

 

                   list  = new ArrayList<Role>();

 

                   Role  warrior = new Role();

 

                   warrior.setName("雨过天晴");

 

                   warrior.setVocation("战士");

 

                   warrior.setProfession("采矿");

 

                   warrior.setWeapon("巨剑");

 

                   warrior.setGS("5880");

 

                   warrior.setCredit("aaaaa");

 

                  warrior.setImage(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher));

 

                   list.add(warrior);

 

         }

 

 

 

 

 

         @Override

 

         public  IBinder onBind(Intent intent) {

 

                  

 

                   return  new AidlImpl();

 

         }

 

        

 

         class  AidlImpl extends MyAidl.Stub{

 

 

 

                   @Override

 

                   public  List getRoleList() throws RemoteException {

 

                            //  TODO Auto-generated method stub

 

                            return  list;

 

                   }

 

 

 

                   @Override

 

                   public  Role getRole(String name) throws RemoteException {

 

                            for(int  i = 0 ; i<list.size();i++){

 

                                     if(list.get(i).getName().equalsIgnoreCase(name)){

 

                                               return  list.get(i);

 

                                     }

 

                            }

 

                            return  null;

 

                   }

 

 

 

                   @Override

 

                   public  String getName() throws RemoteException {

 

                            //  TODO Auto-generated method stub

 

                            return  "123";

 

                   }

 

                  

 

         }

 

 

 

}

 

 

 

 

E、注册服务

代码 3

 

 

<serviceandroid:name="com.lsu.aidlserverdemo.DataProvider">

 

            <intent-filter>

 

                <action android:name="com.lsu.edu.role"></action>

 

            </intent-filter>

 

         </service>

 

 

 

F、界面启动服务

 

代码 4

 

 

package com.lsu.aidlserverdemo;

 

 

 

import android.app.Activity;

 

import android.content.Intent;

 

import android.os.Bundle;

 

import android.view.Menu;

 

import android.view.MenuItem;

 

import android.view.View;

 

import android.widget.Button;

 

 

 

 

 

public class MainActivity extends  Activity {

 

         private  Button btn;

 

 

 

     @Override

 

     protected void onCreate(Bundle savedInstanceState) {

 

         super.onCreate(savedInstanceState);

 

         setContentView(R.layout.activity_main);

 

         btn = (Button)findViewById(R.id.button1);

 

         

 

         btn.setOnClickListener(new View.OnClickListener() {

 

                           

 

                            @Override

 

                            public  void onClick(View v) {

 

                                     Intent  it = new Intent(MainActivity.this,DataProvider.class);

 

                                     startService(it);

 

                                    

 

                            }

 

                   });

 

     }

 

 

 

 

 

     @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;

 

     }

 

 

 

     @Override

 

     public boolean onOptionsItemSelected(MenuItem item) {

 

         // Handle action bar item clicks here. The action bar will

 

         // automatically handle clicks on the Home/Up button, so long

 

         // as you specify a parent activity in AndroidManifest.xml.

 

         int id = item.getItemId();

 

         if (id == R.id.action_settings) {

 

            return true;

 

         }

 

         return super.onOptionsItemSelected(item);

 

     }

 

}

 

 

(2)客户端的建立

A、建立和服务器端一样的包并copy文件

这个几个文件和服务器端的一模一样

B、建立界面

代码 5

 

 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

 

     xmlns:tools="http://schemas.android.com/tools"

 

     android:layout_width="match_parent"

 

     android:layout_height="match_parent"

 

     android:paddingBottom="@dimen/activity_vertical_margin"

 

     android:paddingLeft="@dimen/activity_horizontal_margin"

 

     android:paddingRight="@dimen/activity_horizontal_margin"

 

     android:paddingTop="@dimen/activity_vertical_margin"

 

     tools:context="com.lsu.aidlclientdemo.MainActivity"  >

 

 

 

    <TextView

 

        android:id="@+id/textView1"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:text="@string/hello_world"  />

 

 

 

    <Button

 

        android:id="@+id/button4"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_alignParentBottom="true"

 

        android:layout_alignRight="@+id/button3"

 

        android:layout_marginBottom="78dp"

 

        android:layout_marginRight="18dp"

 

        android:text="reset"  />

 

 

 

    <Button

 

        android:id="@+id/button3"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_above="@+id/button4"

 

        android:layout_alignLeft="@+id/button1"

 

        android:text="取消绑定" />

 

 

 

    <Button

 

        android:id="@+id/button1"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_above="@+id/button3"

 

        android:layout_toRightOf="@+id/textView1"

 

        android:text="获取角色" />

 

 

 

    <Button

 

        android:id="@+id/button2"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_above="@+id/button1"

 

        android:layout_centerHorizontal="true"

 

        android:text="启动service" />

 

 

 

    <TextView

 

        android:id="@+id/textView2"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_alignLeft="@+id/textView1"

 

        android:layout_below="@+id/textView1"

 

        android:layout_marginTop="14dp"

 

        android:text="TextView"  />

 

 

 

    <TextView

 

        android:id="@+id/textView3"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_alignLeft="@+id/textView2"

 

        android:layout_below="@+id/textView2"

 

        android:layout_marginTop="22dp"

 

        android:text="TextView"  />

 

 

 

    <TextView

 

        android:id="@+id/textView4"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_alignLeft="@+id/textView3"

 

        android:layout_below="@+id/textView3"

 

        android:layout_marginTop="18dp"

 

        android:text="TextView"  />

 

 

 

    <TextView

 

        android:id="@+id/textView5"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_alignBottom="@+id/textView1"

 

        android:layout_alignRight="@+id/button2"

 

        android:text="TextView"  />

 

 

 

    <TextView

 

        android:id="@+id/textView6"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_alignBaseline="@+id/textView2"

 

        android:layout_alignBottom="@+id/textView2"

 

        android:layout_alignLeft="@+id/textView5"

 

        android:text="TextView"  />

 

 

 

    <ImageView

 

        android:id="@+id/imageView1"

 

        android:layout_width="wrap_content"

 

        android:layout_height="wrap_content"

 

        android:layout_alignRight="@+id/button1"

 

        android:layout_below="@+id/textView6"

 

        android:src="@android:drawable/btn_default"  />

 

 

 

</RelativeLayout>

 

 

C、实现“启动Service”按钮

 六、android studio中远程服务的实现

Android studio 实现远程服务(Service)AIDL的方法与在eclipse中实现有些不同,Android studio中自带了AIDL创建的方式,而eclipse中需要手动创建;

下面简单介绍实现远程服务(Service)AIDL的方法;

 

一、 创建服务工程应用项目  RemoteDemo

2. 创建 RemoteService 服务类

3. 创建AIDL文件, PublicBusiness 接口类  

在创建之前在目录build-->generated-->source-->aidl-->androidTest-->debug下面发现还没有任何文件

 

创建 PublicBusiness AIDL

创建后会出现如下  :  左边的main目录下出现aidl文件夹和PublicBusiness.aidl文件和包,将PublicBusiness.aidl文件中的basicTypes 方法删除

 

4.  在 PublicBusiness接口类中写入提供远程调用的方法,在确保PublicBusiness.aidl所在的包名与项目中默认的包名一致,如果一致,点击 Build-->Make Project(也可以直接点下图箭头指向的地方),生成相应的java文件。如果不一致,则改aidl的包名,改成一致,再点击生成,生成效果如图。

此时会发现在目录 build-->generated-->source-->aidl-->androidTest-->debug下面出现了编译的文件;

 

二、 创建使用远程服务中的工程应用项目   UseRemoteDemo工程:

  1. 将 RemoteDemo中main目录下的aidl文件夹全部复制到 UseRemoteDemo工程 的main目录下即可;

 

运行后的结果:

七、MediaPlay

本节引言:

本节带来的是Android多媒体中的——MediaPlayer,我们可以通过这个API来播放音频和视频 该类是Androd多媒体框架中的一个重要组件,通过该类,我们可以以最小的步骤来获取,解码 和播放音视频。它支持三种不同的媒体来源:

  • 本地资源

  • 内部的URI,比如你可以通过ContentResolver来获取

  • 外部URL(流) 对于Android所支持的的媒体格式列表

对于Android支持的媒体格式列表,可见:Supported Media Formats 文档

本节我们就来用MediaPlayer来写个简单的播放音视频的例子!

官方API文档:MediaPlayer

1.相关方法详解

1)获得MediaPlayer实例:

可以直接new或者调用create方法创建:

MediaPlayer mp = new MediaPlayer();MediaPlayer mp = MediaPlayer.create(this, R.raw.test);  //无需再调用setDataSource

另外create还有这样的形式: create(Context context, Uri uri, SurfaceHolder holder) 通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器

2)设置播放文件:

//①raw下的资源:MediaPlayer.create(this, R.raw.test);//②本地文件路径:mp.setDataSource("/sdcard/test.mp3");//③网络URL文件:mp.setDataSource("http://www.xxx.com/music/test.mp3");

另外setDataSource()方法有多个,里面有这样一个类型的参数:FileDescriptor,在使用这个 API的时候,需要把文件放到res文件夹平级的assets文件夹里,然后使用下述代码设置DataSource:

AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());

3)其他方法

  • getCurrentPosition( ):得到当前的播放位置

  • getDuration() :得到文件的时间

  • getVideoHeight() :得到视频高度

  • getVideoWidth() :得到视频宽度

  • isLooping():是否循环播放

  • isPlaying():是否正在播放

  • pause():暂停

  • prepare():准备(同步)

  • prepareAsync():准备(异步)

  • release():释放MediaPlayer对象

  • reset():重置MediaPlayer对象

  • seekTo(int msec):指定播放的位置(以毫秒为单位的时间)

  • setAudioStreamType(int streamtype):指定流媒体的类型

  • setDisplay(SurfaceHolder sh):设置用SurfaceHolder来显示多媒体

  • setLooping(boolean looping):设置是否循环播放

  • setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener): 网络流媒体的缓冲监听

  • setOnCompletionListener(MediaPlayer.OnCompletionListener listener): 网络流媒体播放结束监听

  • setOnErrorListener(MediaPlayer.OnErrorListener listener): 设置错误信息监听

  • setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener): 视频尺寸监听

  • setScreenOnWhilePlaying(boolean screenOn):设置是否使用SurfaceHolder显示

  • setVolume(float leftVolume, float rightVolume):设置音量

  • start():开始播放

  • stop():停止播放

2.使用代码示例

示例一:使用MediaPlayer播放音频:

运行效果图

关键代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener{    private Button btn_play;    private Button btn_pause;    private Button btn_stop;    private MediaPlayer mPlayer = null;    private boolean isRelease = true;   //判断是否MediaPlayer是否释放的标志    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        bindViews();    }    private void bindViews() {        btn_play = (Button) findViewById(R.id.btn_play);        btn_pause = (Button) findViewById(R.id.btn_pause);        btn_stop = (Button) findViewById(R.id.btn_stop);        btn_play.setOnClickListener(this);        btn_pause.setOnClickListener(this);        btn_stop.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.btn_play:                if(isRelease){                    mPlayer = MediaPlayer.create(this,R.raw.fly);                    isRelease = false;                }                mPlayer.start();   //开始播放                btn_play.setEnabled(false);                btn_pause.setEnabled(true);                btn_stop.setEnabled(true);                break;            case R.id.btn_pause:                mPlayer.pause();     //停止播放                btn_play.setEnabled(true);                btn_pause.setEnabled(false);                btn_stop.setEnabled(false);                break;            case R.id.btn_stop:                mPlayer.reset();     //重置MediaPlayer                mPlayer.release();   //释放MediaPlayer                isRelease = true;                btn_play.setEnabled(true);                btn_pause.setEnabled(false);                btn_stop.setEnabled(false);                break;        }    }}

注意事项:

播放的是res/raw目录下的音频文件,创建MediaPlayer调用的是create方法,第一次启动播放前 不需要再调用prepare(),如果是使用构造方法构造的话,则需要调用一次prepare()方法! 另外贴下官方文档中,从其他两种途径播放音频的示例代码:

本地Uri

Uri myUri = ....; // initialize Uri hereMediaPlayer mediaPlayer = new MediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(getApplicationContext(), myUri);mediaPlayer.prepare();mediaPlayer.start();

外部URL

String url = "http://........"; // your URL hereMediaPlayer mediaPlayer = new MediaPlayer();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(url);mediaPlayer.prepare(); // might take long! (for buffering, etc)mediaPlayer.start();

Note:假如你通过一个URL以流的形式播放在线音频文件,该文件必须可以进行 渐进式下载

示例二:使用MediaPlayer播放视频

MediaPlayer主要用于播放音频,没有提供图像输出界面,所以我们需要借助其他的 组件来显示MediaPlayer播放的图像输出,我们可以使用用SurfaceView 来显示,下面我们使用SurfaceView来写个视频播放的例子:

运行效果图

实现代码

布局文件:activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:padding="5dp">    <SurfaceView        android:id="@+id/sfv_show"        android:layout_width="match_parent"        android:layout_height="300dp" />    <Button        android:id="@+id/btn_start"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="开始" />    <Button        android:id="@+id/btn_pause"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="暂停 " />    <Button        android:id="@+id/btn_stop"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="终止" />    </LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener, SurfaceHolder.Callback {    private MediaPlayer mPlayer = null;    private SurfaceView sfv_show;    private SurfaceHolder surfaceHolder;    private Button btn_start;    private Button btn_pause;    private Button btn_stop;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        bindViews();    }    private void bindViews() {        sfv_show = (SurfaceView) findViewById(R.id.sfv_show);        btn_start = (Button) findViewById(R.id.btn_start);        btn_pause = (Button) findViewById(R.id.btn_pause);        btn_stop = (Button) findViewById(R.id.btn_stop);        btn_start.setOnClickListener(this);        btn_pause.setOnClickListener(this);        btn_stop.setOnClickListener(this);        //初始化SurfaceHolder类,SurfaceView的控制器        surfaceHolder = sfv_show.getHolder();        surfaceHolder.addCallback(this);        surfaceHolder.setFixedSize(320, 220);   //显示的分辨率,不设置为视频默认    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn_start:                mPlayer.start();                break;            case R.id.btn_pause:                mPlayer.pause();                break;            case R.id.btn_stop:                mPlayer.stop();                break;        }    }    @Override    public void surfaceCreated(SurfaceHolder holder) {        mPlayer = MediaPlayer.create(MainActivity.this, R.raw.lesson);        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);        mPlayer.setDisplay(surfaceHolder);    //设置显示视频显示在SurfaceView上    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}    @Override    public void surfaceDestroyed(SurfaceHolder holder) {}    @Override    protected void onDestroy() {        super.onDestroy();        if (mPlayer.isPlaying()) {            mPlayer.stop();        }        mPlayer.release();    }}

代码很简单,布局有个SurfaceView,然后调用getHolder获得一个SurfaceHolder对象, 在这里完成SurfaceView相关的设置,设置了显示的分辨率以及一个Callback接口, 重写了SurfaceView创建时,发生变化时,以及销毁时的三个方法!然后按钮控制播放 以及暂停而已~

示例三:使用VideoView播放视频

除了使用MediaPlayer + SurfaceView播放视频的方式,我们还可以使用VideoView来直接 播放视频,我们稍微改点东西就可以实现视频播放!运行效果和上面的一致,就不贴了, 直接上代码!

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private VideoView videoView;    private Button btn_start;    private Button btn_pause;    private Button btn_stop;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        bindViews();    }        private void bindViews() {        videoView = (VideoView) findViewById(R.id.videoView);        btn_start = (Button) findViewById(R.id.btn_start);        btn_pause = (Button) findViewById(R.id.btn_pause);        btn_stop = (Button) findViewById(R.id.btn_stop);        btn_start.setOnClickListener(this);        btn_pause.setOnClickListener(this);        btn_stop.setOnClickListener(this);                //根据文件路径播放        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {            videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/lesson.mp4");        }        //读取放在raw目录下的文件        //videoView.setVideoURI(Uri.parse("android.resource://com.jay.videoviewdemo/" + R.raw.lesson));        videoView.setMediaController(new MediaController(this));    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn_start:                videoView.start();                break;            case R.id.btn_pause:                videoView.pause();                break;            case R.id.btn_stop:                videoView.stopPlayback();                break;        }    }}

 


第七章 后台服务(远程服务)的评论 (共 条)

分享到微博请遵守国家法律