動態加載案例

定義

所謂的動態加載就是動態的執行不通的代碼,只需要將最新的代碼放在服務器上即可,避免了頻繁的更新apk,提高了用戶的體驗

分類

Android項目中,動態加載按技術實現上的區別大致可以分爲兩種:

一 . 動態加載.dex/jar/apk(現在動態加載普遍說的是這種)
- 步驟(以動態引用APK文件爲例子):
(1)編寫Remote工程——新建一個Remote項目,並在其中添加一個如下類:

public class RemoteService {
    public String getInfo(String info){
        return "動態加載成功了" + info;
    }
}

運行這個Remote工程,在bin目錄先會生成一個remote.apk文件,使用studio開發的同學會在build/output/apk/目錄下,將這個apk文件放在你的服務器上,也可以使用.jar和.dex的形式
(2)編寫MyProject工程
首先創建一個App類,繼承Applicaion,在oncreate方法中下載最新的apk文件

package com.stv.demo;

import android.app.Application;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by lenovo on 2016/12/20.
 */
public class App extends Application {
    FileOutputStream fos = null;
    HttpURLConnection conn = null;

    @Override
    public void onCreate() {
        super.onCreate();
        new Thread(new Runnable() {
            @Override
            public void run() {
                loadApk();
            }
        }).start();
    }

    private void loadApk() {
        try {
            File file = new File("data/data/com.stv.demo/remote.apk");
            if (file.exists()) {
                file.delete();
            }
            URL url = new URL("http://10.58.180.214:8080/remote.apk");
            conn = (HttpURLConnection) url.openConnection();//一定是這種類型
            conn.setReadTimeout(5000);//設置客戶端連接超時間隔,如果超過指定時間  服務端還沒有響應 就不要等了
            //判斷服務端正常的反饋是否已經到達了 客戶端
            if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){

                //獲得網絡字節輸入流對象
                InputStream is=conn.getInputStream();

                //建立內存到硬盤的連接
                fos=new FileOutputStream(file);

                //老三樣 寫文件
                byte[] b=new byte[1024];
                int len=0;
                while((len=is.read(b))!=-1){  //先讀到內存
                    fos.write(b, 0, len);
                }
                fos.flush();
                Toast.makeText(App.this,"下載成功",Toast.LENGTH_LONG).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在主界面添加一個按鈕,在按鈕的點擊事件中使用反射的方式去加載apk中的代碼

package com.stv.demo;

import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import java.lang.reflect.Method;

import dalvik.system.DexClassLoader;

public class MainActivity extends AppCompatActivity {
    private DexClassLoader dexClassLoader;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //第 1 步:裝載APK文件
        //定義優化目錄:/data/data/com.songshi.myproject
        String optimizedDirectory = Environment.getDataDirectory().toString() + "/data/" + getPackageName();
        dexClassLoader = new DexClassLoader("/data/data/com.stv.demo/remote.apk", optimizedDirectory, null, ClassLoader.getSystemClassLoader());

        findViewById(R.id.load).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    //第 2 步:裝載要訪問的類
                    Class c = dexClassLoader.loadClass("com.stv.demo.remote.RemoteService");   //Call requires API level 14 (current min is 8)

                    //第 3 步:創建類的對象
                    Object obj = c.newInstance();
                    //第 4 步:用Java反射技術調用ServiceClass類中的addService方法
                    Method method = obj.getClass().getMethod("getInfo", String.class);
                    String info = String.valueOf(method.invoke(obj, "Hello World"));

                    Toast.makeText(MainActivity.this, info, Toast.LENGTH_LONG).show();
                } catch (Exception e) {
                    Toast.makeText(MainActivity.this, "error:" + e.getMessage(), Toast.LENGTH_LONG).show();
                }
            }
        });
    }
}

效果圖如下:
這裏寫圖片描述

修改Remote工程的代碼如下:並將新生成的apk文件更新到服務器上

public class RemoteService {
    public String getInfo(String info){
        return "修改了代碼" + info;
    }
}

不需要修改Demo工程的代碼,效果圖如下:
這裏寫圖片描述

二 . 動態加載.so庫
動態加載so庫沒有使用過,請自行研究

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章