android 使用反射获取MediaPlayer的Invoke方法

原创 2016年08月29日 19:25:56

最近有需求需要使用MediaPlayer的invoke接口去实现某些功能, 但是invoke接口是隐藏的, 没有在sdk中开放出来. 所以使用反射的方法来获取invoke接口, 但在实现的过程中出现一些问题, 在这里记录一下.

1.使用反射的方式获取隐藏的接口

    if (mMediaPlayer != null) {
        Parcel request = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            request.writeInt(200);

            Class<?> cls = mMediaPlayer.getClass();
            Method method = cls.getDeclaredMethod("invoke", Parcel.class, Parcel.class);
            method.setAccessible(true); //如果隐藏接口是public的, 这句可以不要
            method.invoke(mMediaPlayer, request, reply); 

            int result = reply.readInt();
            if (0 == result) {
              return false;
          } else if (1 == result) {
              return true;
          }
        }  catch (Exception e) {
                e.getCause().printStackTrace();
        } finally {
            request.recycle();
            reply.recycle();
        }
    }

反射的调用步骤:
(1) 获取相关类的class
Class cls = mMediaPlayer.getClass();
或者通过包名获取:
Class cls = Class.forName (“android.media.MediaPlayer”);

(2) 通过方法名获得方法接口, 如果方法有参数, 需要将参数的class传入
Method method = cls.getDeclaredMethod(“invoke”, Parcel.class, Parcel.class);

(3) 通过Method的invoke接口来实现方法的调用, 这时候需要传参, 将参数传入:
method.invoke(mMediaPlayer, request, reply);

2.出现的问题
当通过这种方式调用后会发现无效, 并且会打印下面的error信息:

01-01 08:31:42.270 W/System.err( 1475): java.lang.reflect.InvocationTargetException
01-01 08:31:42.270 W/System.err( 1475):  at java.lang.reflect.Method.invokeNative(Native Method)
01-01 08:31:42.270 W/System.err( 1475):  at java.lang.reflect.Method.invoke(Method.java:511)

这个问题搞了好久, 反射调用的方法应该没什么问题, 错误应该是其他的, 仔细看log发现有下列信息:

01-01 08:31:42.269 E/Parcel  ( 3212): Reading a NULL string not supported here.

我没有传入任何string下去, 却报出这个error, 应该是需要再出入一个string下去.

这个时候查看MediaPlayer的源码, 看到selectOrDeselectTrack等方法内部也是调用的invoke接口:

    private void selectOrDeselectTrack(int index, boolean select)
            throws IllegalStateException {
        Parcel request = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            request.writeInterfaceToken(IMEDIA_PLAYER);
            request.writeInt(select ? INVOKE_ID_SELECT_TRACK
                    : INVOKE_ID_DESELECT_TRACK);
            request.writeInt(index);
            invoke(request, reply);
        } finally {
            request.recycle();
            reply.recycle();
        }
    }

这里面与我写的调用invoke接口多了一句:

request.writeInterfaceToken(IMEDIA_PLAYER);

IMEDIA_PLAYER的值为:

  private final static String IMEDIA_PLAYER = "android.media.IMediaPlayer";

当我将这句加上测试后, 果然没问题了, 调用成功. 这句代码的意思是标识远程服务的名称. 不然不知道去启动哪个服务来操作.

其实MediaPlayer中有提供方法来获取Parcel对象, 但是此方法也是隐藏的:

    public Parcel newRequest() {
        Parcel parcel = Parcel.obtain();
        parcel.writeInterfaceToken(IMEDIA_PLAYER);
        return parcel;
    }

这个方法的内部也是调用了writeInterfaceToken接口.

3.其他
如果可以查看源码, 其实每个方法的使用源码中都有对应的test例子, 例如现在说的invoke方法, 在源码中有 MediaPlayerInvokeTest.java, 这里面介绍了如何使用invoke接口, 下面是这个类的内容:

    // Tests for the invoke method in the MediaPlayer.
    public class MediaPlayerInvokeTest extends
            ActivityInstrumentationTestCase2<MediaFrameworkTest> {
        private static final String TAG = "MediaPlayerInvokeTest";
        private MediaPlayer mPlayer;
        private Random rnd;

        public MediaPlayerInvokeTest() {
            super("com.android.mediaframeworktest", MediaFrameworkTest.class);
            rnd = new Random(Calendar.getInstance().getTimeInMillis());
        }

        @Override
        protected void setUp() throws Exception {
            super.setUp();
            mPlayer = new MediaPlayer();
        }

        @Override
        protected void tearDown() throws Exception {
            mPlayer.release();
            super.tearDown();
        }

        // Generate a random number, sends it to the ping test player.
        @Suppress
        @MediumTest
        public void testPing() throws Exception {
            mPlayer.setDataSource("test:invoke_mock_media_player.so?url=ping");

            Parcel request = mPlayer.newRequest();
            Parcel reply = Parcel.obtain();

            int val = rnd.nextInt();
            request.writeInt(val);
            mPlayer.invoke(request, reply);
            assertEquals(val, reply.readInt());
        }
    }

这次的收获就是要学会善于查看android源码.

版权声明:本文为博主原创文章,未经博主允许不得转载。

JAVA 反射机制,invoke调用用法一个小的用法

JAVA反射机制基础: 参考:http://lavasoft.blog.51cto.com/62575/43218/ http://zhaohong.iteye.com/blog/432749 JA...
  • xuzhiop
  • xuzhiop
  • 2013年08月21日 17:27
  • 684

c# 反射Invoke调用方法获得out带出的值

var msg = string.Empty; object[] parameters = new object[] { model, null }; ...
  • hzh_csdn
  • hzh_csdn
  • 2016年11月20日 21:55
  • 906

Android开发之通过反射获取到Android隐藏的方法

感恩原创:http://www.cnblogs.com/liyiran/p/5296756.html在PackageManger中,有些方法被隐藏了,无法直接调用,需要使用反射来获取到该方法。比如方法...
  • qq_34329508
  • qq_34329508
  • 2017年08月19日 09:57
  • 127

反射invoke()方法

java反射invoke()方法   invoke()方法:     主要是为了类反射,可以在不知道具体类的情况下,根据配置字符串去调用一个类的方法。最简单的方法是可以把方法参数化。 ...
  • DianaCody
  • DianaCody
  • 2014年08月28日 18:10
  • 2809

Java 利用反射调用jar包中的类

下面讲展示的是从image.jar包中调用image.Buddy类的方法。 public class Main { public static void main(String[] arg...
  • sinat_16492463
  • sinat_16492463
  • 2015年04月03日 12:31
  • 5221

利用java反射调用类的的私有方法

今天和一位朋友谈到父类私有方法的调用问题,本来以为利用反射很轻松就可以实现,因为在反射看来根本不区分是否是private的,没有想到调用本身的私有方法是可以的,但是调用父类的私有方法则不行,后来纠其原...
  • woshinia
  • woshinia
  • 2013年09月17日 11:50
  • 8652

Java反射机制详解 及 Method.invoke解释

JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称...
  • Mr_Tim
  • Mr_Tim
  • 2016年06月06日 12:53
  • 18969

使用java反射中的getMethod,invoke方法调用对象方法的实例

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class A...
  • expleeve
  • expleeve
  • 2012年08月01日 11:03
  • 3042

java 反射调用有参方法,并传递参数

Class cla=Class.forName(classpath); Object o = cla.newInstance(); //下面两种方法是等效的,并注意method.invoke方法参数是...
  • Leolu007
  • Leolu007
  • 2014年06月30日 19:08
  • 5807

通过反射机制调用某个类的方法

要通过反射机制调用某个类的方法,主要用到了下面这个方法: public Object invoke(Object obj,Object... args) 这个方法对带有指定参数的指定对象调用由此 ...
  • Handsome_fan
  • Handsome_fan
  • 2017年02月04日 14:27
  • 4040
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android 使用反射获取MediaPlayer的Invoke方法
举报原因:
原因补充:

(最多只允许输入30个字)