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();}}});    }}

最后,运行成功加载。




0 0
原创粉丝点击