
耳机控制需要使用Intent的,在intentjava(以下代码均来源于android44源码)中可以找到如下字段:
public static final String ACTION_MEDIA_BUTTON ="androidintentactionMEDIA_BUTTON";
这就是android自己用于耳机控制播放器的intent action字段了,我们可以利用它来找到相关代码,很容易我们找到了这个类MediaFocusControl类,其中包含方法dispatchMediaKeyEvent():
private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
Intent keyIntent = new Intent(IntentACTION_MEDIA_BUTTON, null);
mRCStackpeek()mMediaIntentsend(mContext,
needWakeLock WAKELOCK_RELEASE_ON_FINISHED : 0 ,
keyIntent, this, mEventHandler);
}
这里讲intent发送了出去,具体去了哪里我们不用 *** 心,我们只要知道谁用了这个intent。这里的mRCStack是一个Stack类,其中包含着我们需要的RemoteControlStackEntry类对象。我们继续查看,这个对象是在哪被放入Stack中的,最后找到pushMediaButtonReceiver_syncAfRcs()方法,其中关键部分如下:
private boolean pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent,
ComponentName target, IBinder token) {
if (!wasInsideStack) {
rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
}
mRCStackpush(rcse); //rcse被push进mRCStack
}
由此,可以知道这个rcse就是我们需要的对象,而他是被直接new出来的,则这个构造函数的参数就变的很重要了。查看构造函数如下:
public RemoteControlStackEntry(MediaFocusControl controller, PendingIntent mediaIntent,
ComponentName eventReceiver, IBinder token)
可以发现,里面包含了一个重要的ComponentName对象,这个对象在android中就带表着一个应用程序,看来这就是我们要找的音乐播放软件了。那么他是如何被系统拿出来的呢?我们继续找。在刚刚的构造方法创建对象过程中,这个参数是使用target变量直接放入的。而这个target是pushMediaButtonReceiver_syncAfRcs方法的一个参数,那么继续根据这个线索向上找。发现这个参量是经过registerMediaButtonIntent()传入,但是仍然是方法的一个参数,那么继续找,发现找到了源头:
protected void restoreMediaButtonReceiver() {
String receiverName = SettingsSystemgetStringForUser(mContentResolver,
SettingsSystemMEDIA_BUTTON_RECEIVER, UserHandleUSER_CURRENT);
ComponentName eventReceiver = ComponentNameunflattenFromString(receiverName);
registerMediaButtonIntent(pi, eventReceiver, null);
}
由此我们发现了ComponentName对象的创建过程,它使用了一个receiverName对象,这个是个String,他就是我们的目标了。这是用了system的一个方法来创建,进入发现他竟然是个hide的方法,无法作为api使用。后来分析了方法名才释然,这个适用于多用户的,android43以后准备加入用户系统,可惜还不完善所以不给我们用,这肯定是有一般方法的,很快找到了getString方法,其实他就是调用了getStringForUser而已,只是屏蔽了id的参数。但是还有一个小问题,其实SettingsSystemMEDIA_BUTTON_RECEIVER字段也是个hide字段,是不可以当做api来用的,我想这就系统根本就是不想提供获取正在播放音乐的软件的方法,不过既然是个字段就没问题了,我们查看一下源码就能看到MEDIA_BUTTON_RECEIVER字段其实就代表着"media_button_receiver"而已。到这里我们已经可以实现功能了。方法如下,其实就简单的三句即可:
================================功能实现===========================================
String receiverName = SettingsSystemgetString(thisgetContentResolver(),
"media_button_receiver");
ComponentName eventReceiver = ComponentNameunflattenFromString(receiverName);
String musicPlayerPkgName = eventReceivergetPackageName();
我们即可得到我们所需要的包名。
额 思路 拿到classLoder的路径 然后一级一级的查找下去 当找到了 文件名为classNameclass 的话(如路径为 com/kidd/tset 对应的包名就是 comkiddtest) 就可以构建出包名了 就调用 ClassforName() ;
没有包名怎么行呢?如果有几个相同的类名的类,该怎么区分呢。如果有报名的话可以用反射: Class clazz = ClassforName("comTest");//包名类名
Method method = cgetMethod("test", Stringclass);//方法名,和参数的类对象
methodinvoke(clazznewInstance(), "print hello word");//类的实例,和参数
Java中要用到反射,首先就必须要获取到对应的class对象,在Java中有三种方法获取类对应的class对象。
1、通过类的class属性
2、通过类实例的getClass()方法获取
3、通过ClassforName(String className)方法获取
现在比如在package下有个类Calculator
public class Calculator{public double add(double score1,double score2){
return score1 + score2;
}
public void print(){
Systemoutprintln("OK");
}
public static double mul(double score1,double score2){
return score1 score2;
}
}public class CalculatorTest {
public static void main(String[] args) throws Exception {
//通过类的class属性获取
Class<Calculator> clz = Calculatorclass;
//或者通过类的完整路径获取,这个方法由于不能确定传入的路径是否正确,这个方法会抛ClassNotFoundException
// Class<Calculator> clz = ClassforName("testCalculator");
//或者new一个实例,然后通过实例的getClass()方法获取
// Calculator s = new Calculator();
// Class<Calculator> clz = sgetClass();
//1 获取类中带有方法签名的mul方法,getMethod第一个参数为方法名,第二个参数为mul的参数类型数组
Method method = clzgetMethod("mul", new Class[]{doubleclass,doubleclass});
//invoke 方法的第一个参数是被调用的对象,这里是静态方法故为null,第二个参数为给将被调用的方法传入的参数
Object result = methodinvoke(null, new Object[]{20,25});
//如果方法mul是私有的private方法,按照上面的方法去调用则会产生异常NoSuchMethodException,这时必须改变其访问属性
//methodsetAccessible(true);//私有的方法通过发射可以修改其访问权限
Systemoutprintln(result);//结果为50
//2 获取类中的非静态方法
Method method_2 = clzgetMethod("add", new Class[]{doubleclass,doubleclass});
//这是实例方法必须在一个对象上执行
Object result_2 = method_2invoke(new Calculator(), new Object[]{20,25});
Systemoutprintln(result_2);//45
//3 获取没有方法签名的方法print
Method method_3 = clzgetMethod("print", new Class[]{});
Object result_3 = method_3invoke(new Calculator(), null);//result_3为null,该方法不返回结果
}
}
你所说的java文件是什么文件?如果是java源码文件是不能调用的,但如果是编译后的class文件可以通过类加载器进行加载,然后通过反射调用;但一般会通过实现特定的接口来简化调用过程。一个自定义的类加载器如下 :
class MyClassLoader extends ClassLoader {//类加载器的名称
private String name;
//类存放的路径
private String path = "E:\\bin";
MyClassLoader(String name) {
thisname = name;
}
MyClassLoader(ClassLoader parent, String name) {
super(parent);
thisname = name;
}
/
重写findClass方法,加载特定目录下的类文件
/
@Override
public Class<> findClass(String name) {
byte[] data = loadClassData(name);
return thisdefineClass(name, data, 0, datalength);
}
public byte[] loadClassData(String name) {
try {
name = namereplace("", "//");
FileInputStream is = new FileInputStream(new File(path, name + "class"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b = 0;
while ((b = isread()) != -1) {
baoswrite(b);
}
return baostoByteArray();
} catch (Exception e) {
eprintStackTrace();
}
return null;
}
}
jar 包的名字跟类名字没啥关系,写死了不要紧
包的文件名可以随便写,影响的不是 java 代码,而是 java 启动参数里面的 classpath
对于 java 代码来说,只要类名方法名之类不变就不要紧
jar 包和 package 包是不同的概念。
jar 包名是在启动时需要的,启动以后,java 代码执行过程中,根本不在乎 jar 包在 *** 作系统里的文件名,只在乎 package 的包名
所以,package 包可以用反射来做,jar 包路径和文件名最好还是在启动脚本里面做变量,那是启动 java 虚拟机之前的事情了,不应该影响 Java 代码
以上就是关于如何获取当前正在播放音乐的音乐软件的包名全部的内容,包括:如何获取当前正在播放音乐的音乐软件的包名、java 通过类名字符串实例化类并调用其中的方法 例如"className.methodName" 不知道具体包名.、java 通过类名字符串实例化类并调用其中的方法 例如"className.methodName" 不知道具体包名等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)