最近,需要使用MediaPlayer的invoke接口实现某些功能,但invoke接口是隐藏的,在sdk中不开放。 因此,用反射的方法获取invoke接口,但在实现过程中出现了一些问题,在此记录。
1 .使用反射获取隐藏的接口if (媒体播放器!=空) {
Parcel request=Parcel.obtain (;
Parcel reply=Parcel.obtain (;
try {
request.writeint(200;
Class cls=mMediaPlayer.getClass (;
方法方法=cls.getdeclaredmethod (' invoke ',Parcel.class,Parcel.class );
method.set accessible (真; //如果隐藏接口是公共接口,则可以放弃此语句
method.invoke(mmediaplayer,请求,复制);
int result=reply.readInt (;
if(0==result ) {
返回假;
}elseif(1==result ) )。
返回真;
}
}catch(exceptione ) {
e.getCause ().printStackTrace );
} finally {
request.recycle (;
reply.recycle (;
}
}
反射调用步骤:
(1)获取相关类的类class
Class cls=mMediaPlayer.getClass (;
或者用包名获取:
class cls=class.forname (" Android.media.media player " )
)从方法名称中获取方法接口,如果方法具有参数,则必须传递参数的class
方法方法=cls.getdeclaredmethod (“invoke”,Parcel.class,Parcel.class );
)3)用Method的invoke接口实现方法调用时,需要将参数传递给:
method.invoke(mmediaplayer,请求,复制);
2 .出现的问题
用这种方法调用会发现无效,以下error信息:01-0108336031336042.270 w/system.err (1475 ) : Java.lang.reflect.invocationion
01-0108:31336042.270 w/system.err (1475 ) : at Java.lang.reflect.method.invoke native (本机方法) )。
01-0108336031336042.270 w/system.err (1475 ) : at Java.lang.reflect.method.invoke (method.Java 3360511 ) )
这个问题进行了很久,但是反射调用的方法应该没有问题。 错误应该是其他的。 仔细查看log,发现有以下信息。01-0108336031336042.269 e/parcel (3212 ) : readinganullstringnotsupportedherroted
我没有给任何字符串,但是报告这个错误应该是需要进出另一个字符串。
此时,查看MediaPlayer的源代码,可以看到在selectOrDeselectTrack等方法内部也调用的invoke接口: privatevoidselectordeselecttrack (intindid
throws IllegalStateException {
Parcel request=Parcel.obtain (;
Parcel reply=Parcel.obtain (;
try {
request.writeinterfacetoken (I media _ player;
request.write int (选择? INVOKE_ID_SELECT_TRACK
: INVOKE_ID_DESELECT_TRACK;
request.write int (索引;
invoke (请求、复制);
} finally {
request.recycle (;
reply.recycle (;
}
}
这里面添加了我写的invoke界面和: request.writeinterfacetoken (I media _ player )。
IMEDIA_PLAYER的值为: privatefinalstaticstringimedia _ player=' Android.media.I media player ';
我对这个进行了测试之后,还是没有问题,调用成功了。 此代码意味着识别远程服务的名称。 否则,我不知道启动和操作哪个服务。
实际上,媒体播放器有一种获取Parcel对象的方法,但也隐藏了该方法:公共parcel new request
Parcel parcel=Parcel.obtain (;
parcel.writeinterfacetoken (I media _ player;
返回平行;
}
该方法的内部也调用了writeInterfaceToken接口
3 .其他
如果可以看到源代码,则实际上有一个与每个方法的使用源代码相对应的test示例。 例如,现在所说的invoke方法在源代码中有MediaPlayerInvokeTest.java,其中介绍了如何使用invoke接口。 以下是这个班的内容3360//testsfortheinvokemetetava
publicclassmediaplayerinvoketestextends
activityinstrumentationtestcase2{
privatestaticfinalstringtag=' mediaplayerinvoketest ';
私人媒体播放器播放器;
私有随机射频识别;
公共媒体播放器invoketest (
super (com.Android.mediaframeworktest (,MediaFrameworkTest.class ) );
rnd=new random (calendar.getinstance ().getTimeInMillis ) );
}
@Override
protectedvoidsetup { } throws exception
super.setUp (;
mPlayer=new MediaPlayer (;
}
@Override
protectedvoidteardown { } throws exception {
mPlayer.release (;
super.tearDown (;
}
//Generate a random number,sends it to the ping test player。
@Suppress
@ medium测试
公共语音测试坪() throws Exception { ) )。
mplayer.setdata source (test : invoke _ mock _ media _ player.so? url=ping ';
parcel request=mplayer.new request (;
Parcel reply=Parcel.obtain (;
int val=rnd.nextInt (;
request.writeint(val;
mplayer.invoke (请求,复制);
资产质量(val,reply.readInt );
}
}
这次的成果是学会善于看安卓的源代码。