一.什么是动态加载?为什么要动态加载?
动态加载就是用到的时候再去加载,也叫懒加载,也就意味着用不到的时候是不会去加载的。
二.编写Demo
1.利用jar,dx 创建dex
1)创建DynamicDex.java,生成DynamicDex.class
2)生成dex
jar是JDK提供的,dx是Android SDK提供,只要配置好环境变量,可在任意位置执行
我是在debug中执行,方便使用
jar -cvf cn 生成jar包
dx --dex --output=target.jar source.jar 生成包含dex的jar包
注意:把dex放入assets后,把DynamicDex.java删掉或改名,否则加载的是它,而不是dex中的类
2.加载Dex
public class DexUtil {
public static void loadDexClass(final Context context, final String dexName, final Handler handler) {
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
File cacheFile = getCacheDir(context.getApplicationContext());
String internalPath = cacheFile.getAbsolutePath() + File.separator + dexName;
Log.v("DexUtil", "internalPath = " + internalPath);
File desFile = new File(internalPath);
if (!desFile.exists()) {
try {
if (!desFile.exists()) {
desFile.createNewFile();
copyFiles(context, dexName, desFile);
}
} catch (IOException e) {
e.printStackTrace();
}
}
return internalPath;
}
@Override
protected void onPostExecute(String internalPath) {
super.onPostExecute(internalPath);
File dexOutputDir = context.getDir("dex", 0);
File soOutputDir = context.getDir("lib", 0);
String librarySerachPath = soOutputDir.getAbsolutePath().replace("app_lib", "lib");
Log.v("DexUtil", "librarySerachPath = " + librarySerachPath);
DexClassLoader dexClassLoader = new DexClassLoader(internalPath, dexOutputDir.getAbsolutePath(),
librarySerachPath, context.getClassLoader());//ClassLoader.getSystemClassLoader().getParent());
Message msg = new Message();
msg.obj = dexClassLoader;
handler.sendMessage(msg);
}
}.execute();
}
public static void copyFiles(Context context, String fileName, File desFile) {
InputStream in = null;
OutputStream out = null;
try {
in = context.getApplicationContext().getAssets().open(fileName);
out = new FileOutputStream(desFile.getAbsolutePath());
byte[] bytes = new byte[1024];
int i;
while ((i = in.read(bytes)) != -1) {
out.write(bytes, 0, i);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static boolean hasExternalStorage() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
/**
* 获取缓存路径
*
* @param context
* @return 返回缓存文件路径
*/
public static File getCacheDir(Context context) {
File cache;
if (hasExternalStorage()) {
cache = context.getExternalCacheDir();
} else {
cache = context.getCacheDir();
}
if (!cache.exists())
cache.mkdirs();
return cache;
}
}
Dex加载步骤:
1)把assets中的dex的jar拷贝到met目录下
文件拷贝需要添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2)利用DexClassLoader加载Dex,把dex放入到相关目录上
注意:文件的拷贝需要放在子线程中运行
3.利用反射加载
public class MainActivity extends AppCompatActivity {
public static DexClassLoader mapLoader;
TextView tv_hello;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_hello = (TextView) this.findViewById(R.id.tv_hello);
DexUtil.loadDexClass(this, "dex_dynamic.jar", dexHandler);
}
private Handler dexHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mapLoader = (DexClassLoader) msg.obj;
try {
Class DynamicDex_Class = mapLoader.loadClass("cn.liufei.dynamicdex.DynamicDex");
Constructor DynamicDex_Cons = DynamicDex_Class.getConstructor(null);
Object DynamicDex_Obj = DynamicDex_Cons.newInstance();
Method test_meth = DynamicDex_Class.getMethod("test", null);
String result = (String) test_meth.invoke(DynamicDex_Obj, null);
tv_hello.setText(result);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
};
}
Demo地址:链接: https://pan.baidu.com/s/1kVMQ6jX 密码: i4vp