标签:android style blog class code java
前言
在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势。本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病。更多android开源代码请到:www.23code.com.
正文
  一、 基本概念和注意点
1.1 首先需要了解一点:在Android中可以动态加载,但无法像Java中那样方便动态加载jar
      原因:Android的虚拟机(Dalvik VM)是不认识Java打出jar的byte 
code,需要通过dx工具来优化转换成Dalvik byte 
code才行。这一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex。
所以这条路不通,请大家注意。
1.2 当前哪些API可用于动态加载
1.2.1 DexClassLoader
这个可以加载jar/apk/dex,也可以从SD卡中加载,也是本文的重点。
1.2.3 PathClassLoader
只能加载已经安装到Android系统中的apk文件。
  二、 准备
本文主要参考"四、参考文章"中第一篇文章,补充细节和实践过程。
2.1 下载开源项目
http://code.google.com/p/goodev-demo
将项目导入工程,工程报错的话应该是少了gen文件夹,手动添加即可。注意这个例子是从网上下载优化好的jar(已经优化成dex然后再打包成的jar)到本地文件系统,然后再从本地文件系统加载并调用的。本文则直接改成从SD卡加载。
  三、实践 
3.1 编写接口和实现
3.1.1 接口IDynamic
01 | 
    package com.dynamic; | 
02 | 
    
03 | 
    public interface 
IDynamic { | 
04 | 
        public 
String helloWorld(); | 
05 | 
    } | 
06 | 
          3.1.2  实现类DynamicTest | 
07 | 
    [url=][/url] | 
08 | 
    package com.dynamic; | 
09 | 
    
10 | 
    public class 
DynamicTest implements 
IDynamic { | 
11 | 
    
12 | 
        @Override | 
13 | 
        public 
String helloWorld() { | 
14 | 
            return 
"Hello World!"; | 
15 | 
        } | 
16 | 
    } | 
3.2 打包并转成dex
3.2.1 选中工程,常规流程导出即可,如图:

注意:在实践中发现,自己新建一个Java工程然后导出jar是无法使用的,这一点大家可以根据文章一来了解相关原因,也是本文的重点之一。这里打包导出为dynamic.jar
(后期修复:打包请不要把接口文件打进来,参见文章末尾后续维护!)
3.2.2 将打包好的jar拷贝到SDK安装目录android-sdk-windows\platform-tools下,DOS进入这个目录,执行命名:
dx --dex --output=test.jar dynamic.jar
3.3 修改调用例子
修改MainActivity,如下:
01 | 
    @Override | 
02 | 
        public 
void onCreate(Bundle savedInstanceState) { | 
03 | 
            super.onCreate(savedInstanceState); | 
04 | 
            setContentView(R.layout.main); | 
05 | 
            mToastButton = (Button) findViewById(R.id.toast_button); | 
06 | 
              | 
07 | 
            // Before the secondary dex file can be processed by the DexClassLoader, | 
08 | 
            // it has to be first copied from asset resource to a storage location. | 
09 | 
    //        final File dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE),SECONDARY_DEX_NAME); | 
10 | 
    //        if (!dexInternalStoragePath.exists()) { | 
11 | 
    //            mProgressDialog = ProgressDialog.show(this, | 
12 | 
    //                    getResources().getString(R.string.diag_title),  | 
13 | 
    //                    getResources().getString(R.string.diag_message), true, false); | 
14 | 
    //            // Perform the file copying in an AsyncTask. | 
15 | 
    //            // 从网络下载需要的dex文件 | 
16 | 
    //            (new PrepareDexTask()).execute(dexInternalStoragePath); | 
17 | 
    //        } else { | 
18 | 
    //            mToastButton.setEnabled(true); | 
19 | 
    //        } | 
20 | 
              | 
21 | 
            mToastButton.setOnClickListener(new 
View.OnClickListener() { | 
22 | 
                public 
void onClick(View view) { | 
23 | 
                    // Internal storage where the DexClassLoader writes the optimized dex file to. | 
24 | 
                    //final File optimizedDexOutputPath = getDir("outdex", Context.MODE_PRIVATE); | 
25 | 
                    final 
File optimizedDexOutputPath = new 
File(Environment.getExternalStorageDirectory().toString() | 
26 | 
                        + File.separator + "test.jar"); | 
27 | 
                    // Initialize the class loader with the secondary dex file. | 
28 | 
    //                DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(), | 
29 | 
    //                        optimizedDexOutputPath.getAbsolutePath(), | 
30 | 
    //                        null, | 
31 | 
    //                        getClassLoader()); | 
32 | 
                    DexClassLoader cl = new 
DexClassLoader(optimizedDexOutputPath.getAbsolutePath(), | 
33 | 
                        Environment.getExternalStorageDirectory().toString(), null, getClassLoader()); | 
34 | 
                    Class libProviderClazz = null; | 
35 | 
                      | 
36 | 
                    try 
{ | 
37 | 
                        // Load the library class from the class loader. | 
38 | 
                        // 载入从网络上下载的类 | 
39 | 
    //                    libProviderClazz = cl.loadClass("com.example.dex.lib.LibraryProvider"); | 
40 | 
                        libProviderClazz = cl.loadClass("com.dynamic.DynamicTest"); | 
41 | 
                          | 
42 | 
                        // Cast the return object to the library interface so that the | 
43 | 
                        // caller can directly invoke methods in the interface. | 
44 | 
                        // Alternatively, the caller can invoke methods through reflection, | 
45 | 
                        // which is more verbose and slow. | 
46 | 
                        //LibraryInterface lib = (LibraryInterface) libProviderClazz.newInstance(); | 
47 | 
                        IDynamic lib = (IDynamic)libProviderClazz.newInstance(); | 
48 | 
                          | 
49 | 
                        // Display the toast! | 
50 | 
                        //lib.showAwesomeToast(view.getContext(), "hello 世界!"); | 
51 | 
                        Toast.makeText(MainActivity.this, lib.helloWorld(), Toast.LENGTH_SHORT).show(); | 
52 | 
                    } catch 
(Exception exception) { | 
53 | 
                        // Handle exception gracefully here. | 
54 | 
                        exception.printStackTrace(); | 
55 | 
                    } | 
56 | 
                } | 
57 | 
            }); | 
58 | 
        } | 
3.4 执行结果
    
这个软件就是按照这个原理实现的,感兴趣的跳转到这里
Android动态加载jar/dex,布布扣,bubuko.com
标签:android style blog class code java
原文地址:http://www.cnblogs.com/wanqieddy/p/3715501.html