Android中的动态加载机制(折腾版)

最近在拜读博主姜维的文章,感觉获益匪浅。

原文在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;
	@Override
	public void init(Activity activity) {
		mActivity = activity;
	}

	@Override
	public void showBanner() {
		Toast.makeText(mActivity, "我是ShowBannber方法", Toast.LENGTH_LONG).show(); 
	}

	@Override
	public void showDialog() {
		Toast.makeText(mActivity, "我是ShowDialog方法", Toast.LENGTH_LONG).show();
	}

	@Override
	public 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() {
			
			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				if (lib != null) {
					lib.showBanner();
				} else {
					Toast.makeText(MainActivity.this, "load error", Toast.LENGTH_LONG).show();
				}
			}
		});
        
        showDialogBtn.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				if (lib != null) {
					lib.showDialog();
				} else {
					Toast.makeText(MainActivity.this, "load error", Toast.LENGTH_LONG).show();
				}
			}
		});
    }

}

最后,运行成功加载。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值