Android中的动态加载机制(折腾版)
来源:互联网 发布:linux备份文件命令bak 编辑:程序博客网 时间:2024/04/20 08:40
最近在拜读博主姜维的文章,感觉获益匪浅。
原文在http://blog.csdn.net/jiangwei0910410003/article/details/17679823。里面详细讲解了android动态加载的原理及实例。
看了文章免不了要自己动手复现一遍,在复现的过程中遇到了一些问题。
我将自己复现成功的过程与大家分享,希望能够少走一些弯路吧。
文章中的测试工程有些绕,不太适合新手,这里我重新写了一遍,简化了与动态加载机制不太相关的东西,更聚焦问题所在吧。
第一步,建立一个android工程,并建立动态代码类。
为了简化,我只保留了4个方法。
package com.example.interfaces;import android.app.Activity;public interface IDynamic { /**初始化方法*/ public void init(Activity activity); /**自定义方法*/ public void showBanner(); public void showDialog(); /**销毁方法*/ public void destory(); }
Dynamic.java代码如下:
package com.example.impl;import android.app.Activity;import android.widget.Toast;import com.example.interfaces.IDynamic;public class Dynamic implements IDynamic {public Activity mActivity;@Overridepublic void init(Activity activity) {mActivity = activity;}@Overridepublic void showBanner() {Toast.makeText(mActivity, "我是ShowBannber方法", Toast.LENGTH_LONG).show(); }@Overridepublic void showDialog() {Toast.makeText(mActivity, "我是ShowDialog方法", Toast.LENGTH_LONG).show();}@Overridepublic void destory() {}}
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">第二步,打包并转换jar文件</span>
将上面开发好的动态类打包成.jar,这里要注意的是只打包实现类Dynamic.java,不打包接口类IDynamic.java,
然后将打包好的jar文件拷贝到android sdk的安装目录中的\sdk\build-tools\android-4.4W目录下。(android-4.4W更换成你的开发版本就好了,此处原文中有误)
使用dx命令转换jar文件:(我的jar文件是test.jar)
dx --dex --output=load.jar test.jar
将load.jar放入sdcard adb push load.jar /sdcard/
第三步,在android工程中删除com.dynamic.impl包及其中的java代码,保留com.dynamic.interfaces包及代码。
删除com.dynamic.impl包及其中的java代码,主要是为了更清楚地显示后面的代码是动态加载的,当然你不删除也可以。
保留com.dynamic.interfaces包及代码,主要是为了在动态加载的时候能够识别动态类,原文作者是通过导入jar包来实现的,这里我们直接写入代码是一样的效果。
第四步、编写app,动态加载类。
首先在AndroidManifest.xml中加入<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>,因为我们要把动态加载的jar包放在sdcard根目录。
下面是activity_main.xml,我加入了两个button
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.dynamic.demo.MainActivity" > <Button android:id="@+id/show_banner_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="showBanner" /> <Button android:id="@+id/show_dialog_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="showDialog" /></LinearLayout>
接下来是MainActivity.java的代码,里面最大的改动就是将DexClassLoader的第二个参数,也就是要解压到的路径改为了程序本身目录下的cache目录。主要原因是,在android 4.1之后,不允许将dex文件解压到sccard目录下。这也是大部分人遇到错误的原因吧。
package com.example.testdynamic;import java.io.File;import com.example.interfaces.IDynamic;import dalvik.system.DexClassLoader;import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends Activity {IDynamic lib; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); File optimizedDexOutputPath = new File(Environment.getExternalStorageDirectory().toString() + File.separator + "load.jar"); String pathString = optimizedDexOutputPath.getAbsolutePath(); String outPath = getApplicationContext().getCacheDir().toString(); DexClassLoader classLoader = new DexClassLoader(pathString, outPath, null, getClassLoader()); Class libProviderClazz = null; try { libProviderClazz = classLoader.loadClass("com.example.impl.Dynamic"); lib = (IDynamic) libProviderClazz.newInstance(); if (lib != null) { lib.init(MainActivity.this);System.out.println("lib is not null");}else {System.out.println("null");}} catch (Exception e) {// TODO: handle exception} Button showBannerBtn = (Button) findViewById(R.id.show_banner_btn); Button showDialogBtn = (Button) findViewById(R.id.show_dialog_btn); showBannerBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubif (lib != null) {lib.showBanner();} else {Toast.makeText(MainActivity.this, "load error", Toast.LENGTH_LONG).show();}}}); showDialogBtn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubif (lib != null) {lib.showDialog();} else {Toast.makeText(MainActivity.this, "load error", Toast.LENGTH_LONG).show();}}}); }}
最后,运行成功加载。
- Android中的动态加载机制(折腾版)
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制
- Android中的动态加载机制--薛彦顺
- Android中的class动态加载机制
- Android动态加载机制
- Cpp--改造多重继承
- 作业(1)
- 移植ok6410 2.6内核
- 开源骇客文本编辑工具-atom之快捷键
- Yii2加入新的应用
- Android中的动态加载机制(折腾版)
- WebApplicationContext与ServletContext的关系
- Leetcode178: Basic Calculator
- ListView 获取Item 高宽
- 创建简单的Android Material DesignDemo
- 升级“FOTA”洪荒之力,对抗APP过多导致的慢、卡、热
- Boost的log编译使用
- SWT 在Composite动态添加控件注意问题
- // 正则判断手机号码地址格式