一. 卸载 SD 卡

参考链接

1
2
3
4
5
6
7
8
9
10
11
12
public static void unmountVolume(String path) {

try {
Method method = Class.forName("android.os.ServiceManager")
.getMethod("getService", String.class);
IBinder binder = (IBinder) method.invoke(null, "mount");
IMountService service = IMountService.Stub.asInterface(binder);
service.unmountVolume(path, true, true);
} catch (Exception e) {
Log.i(TAG, "unmountVolume: 卸载设备出错----" + e.toString());
}
}

二. 加载 SD 卡

参考链接

1
2
3
4
5
6
7
8
9
10
11
12
public static void mountVolume(String path) {

try {
Method method = Class.forName("android.os.ServiceManager")
.getMethod("getService", String.class);
IBinder binder = (IBinder) method.invoke(null, "mount");
IMountService service = IMountService.Stub.asInterface(binder);
service.mountVolume(path, true, true);
} catch (Exception e) {
Log.i(TAG, "unmountVolume: 挂载设备出错----" + e.toString());
}
}

三. 获取外置存储设备的路径

参考链接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static String[] getVolumePaths(Context context) {
String paths[] = null;
StorageManager storageManager = (StorageManager) context
.getSystemService(Context.STORAGE_SERVICE);
try {
Class<?>[] paramClasses = {};
Method getVolumePathsMethod = StorageManager.class
.getMethod("getVolumePaths", paramClasses);
getVolumePathsMethod.setAccessible(true);
Object[] params = {};
paths = (String[]) getVolumePathsMethod.invoke(storageManager, params);

} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return paths;
}

四. 反射简介

  1. 什么是反射

    反射阔以通过非常规手段直接获取并操作方法、字段等所有类的成员。

  2. 如何使用反射

    这里简单介绍一下如何使用反射。仅能用于理解上面部分代码。如需全面深刻的理解,建议结合 这篇文章 并且动手实践以加深印象。

    • 使用反射的必要条件,即反射的入口

      获取需要操作类的 Class 对象,有三种方式:

      1) class.class

      2) class.instance.getClass()

      3) Class.forName()

      如,上面的卸载 & 挂载 SD 卡部分的代码Class.forName("android.os.ServiceManager") 即使用的方法 3;而获取外部存储设备的路径中 StorageManager.class 即使用的方法 1;通过类的实例获取 Class 的对象的话,就需要使用 getClass() 方法了。

    • 获取指定的方法

      当我们获取到类的Class 对象后,就能通过此对象来操作类的成员,这里只介绍如何通过Class 对象来获取对象的方法。

      1
      2
      3
      4
      Class<?> smClass = Class.forName("android.os.ServiceManager");
      // 参数 1:需要指定获取方法的名的字符串,这里需要获取 getService(), 就传
      Method getService = smClass.getMeDeclaredMethod("getService", String.class);
      getService.invoke(smClass.newInstance(), )

      Class类提供了以下 4 个函数来获取方法:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
      throws NoSuchMethodException, SecurityException

      public Method getMethod(String name, Class<?>... parameterTypes)
      throws NoSuchMethodException, SecurityException

      public Method[] getDeclaredMethods() throws SecurityException

      public Method[] getMethods() throws SecurityException

      根据方法名就能明白这些方法的用途。下面来讲一下 getDeclaredMethod()getMethod() 的共同点与差别。

      共同点: 需要传入 方法名 以及 参数类型 来获取指定方法。方法的名字不难理解,你需要告诉程序,你想要哪一个方法。而参数类型,是为了避免方法重载,程序无法获知你需要的具体方法。方法名 以及 参数类型 就像坐标,帮程序准确定位。

      区别: getMethod 只能获取到使用 public 修饰符修饰的方法,且能获取到继承父类中的方法;而 getDeclaredMethod 阔以获取到所有该类中的方法,但无法获取父类中的任何办法。

      下面我们使用 getDeclaredMethodsgetMethods 来验证一下区别:

      Father:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      public class Father {

      public Father() {

      }

      public void fatherMethod1() {
      System.out.println("father's public method");
      }

      private void fatherMethod2() {
      System.out.println("father's private method");
      }
      }

      Son:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      public class Son extends Father {
      public Son() {

      }

      public void sonMethod1() {
      System.out.println("son's public method");
      }

      private void sonMethod2() {
      System.out.println("son's private method");
      }
      }

      ReflectTest:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      public class ReflectTest {

      public static void main(String[] args) {

      try {
      Class<?> sonClass = Class.forName("Son");
      Method[] methods = sonClass.getMethods();
      Method[] declaredMethods = sonClass.getDeclaredMethods();

      for (Method method : methods) {
      System.out.println("getMethods----" + method);
      }

      for (Method method : declaredMethods) {
      System.out.println("getDeclaredMethods----" + method);
      }

      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      }

      }
      }

      打印结果:

      可以看到, getMethods() 成功获取到使用 public 修饰符修饰的方法,包括 Object 中的方法。而getDeclaredMethods() 只获取到了Son类中的所有方法,无法获得继承的方法。

    • 调用指定方法

      调用方法使用:

      1
      public Object invoke(Object obj, Object... args)

      参数1:指定类的实例,可以通过 Class.newInstance() 获得。通过反射获取类的实例有两种方法,我们这里使用最 简单的,也是不推荐用的。需要了解更多可以 点击这里看看

      参数2:调用该方法传入的值。(这里应该好理解吧?虽然我说得很抽象…)

      代码部分:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      public class ReflectTest {

      public static void main(String[] args) {

      try {
      Class<?> sonClass = Class.forName("Son");
      Method method1 = sonClass.getDeclaredMethod("sonMethod1", null);
      method1.invoke(sonClass.newInstance(), null);
      } catch (NoSuchMethodException e) {
      e.printStackTrace();
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (InstantiationException e) {
      e.printStackTrace();
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      } catch (InvocationTargetException e) {
      e.printStackTrace();
      }

      }
      }

      使用到的类都是上面用过的,就不再贴代码了。

      可以看到,这里 参数2 我传入的值为 null, 因为该方法不需要参数。

      打印结果:

      至此好像就把最上边设计到的两三行代码讲完了…

五. 总结

  1. 获得 Class 对象有三种方法。
  2. 获得指定方法有两种方式,传入的参数为 方法名 以及 参数类型 ;获取方法集有两种方法。
  3. 调用方法使用 invoke 传入的参数为 类的实例 以及 方法值 ,如果该方法为静态,那么 类的实例 可以为 null