异步加载分包

异步加载分包,第1张

概述 import java.util.Map;import java.util.jar.Attributes;import java.util.jar.JarFile;import java.util.jar.Manifest; public class App extends Application {    public static final String KEY_DEX2_SHA1 = "dex2-SHA1-Digest"; 
 

import java.util.Map;

import java.util.jar.Attributes;

import java.util.jar.Jarfile;

import java.util.jar.Manifest;

 

public class App extends Application {

    public static final String KEY_DEX2_SHA1 = "dex2-SHA1-Digest";

    @OverrIDe

    protected voID attachBaseContext(Context base) {

        super .attachBaseContext(base);

        LogUtils.d( "loadDex", "App attachBaseContext ");

        if (!quickStart() && Build.VERSION.SDK_INT < Build.VERSION_CODES.LolliPOP) {//>=5.0的系统默认对dex进行oat优化

            if (neeDWait(base)){

                waitForDexopt(base);

            }

            MultIDex.install (this );

        } else {

            return;

        }

    }

 

    @OverrIDe

    public voID onCreate() {

        super .onCreate();

        if (quickStart()) {

            return;

        }

        ...

    }

 

    public boolean quickStart() {

        if (StringUtils.contains( getCurProcessname(this), ":mini")) {

            LogUtils.d( "loadDex", ":mini start!");

            return true;

        }

        return false ;

    }

    //neead wait for dexopt ?

    private boolean neeDWait(Context context){

        String flag = get2thDexSHA1(context);

        LogUtils.d( "loadDex", "dex2-sha1 "+flag);

        SharedPreferences sp = context.getSharedPreferences(

                PackageUtil.getPackageInfo(context). versionname, MODE_MulTI_PROCESS);

        String saveValue = sp.getString(KEY_DEX2_SHA1, "");

        return !StringUtils.equals(flag,saveValue);

    }

    /**

     * Get classes.dex file signature

     * @param context

     * @return

     */

    private String get2thDexSHA1(Context context) {

        ApplicationInfo ai = context.getApplicationInfo();

        String source = ai.sourceDir;

        try {

            Jarfile jar = new Jarfile(source);

            Manifest mf = jar.getManifest();

            Map<String, Attributes> map = mf.getEntrIEs();

            Attributes a = map.get("classes2.dex");

            return a.getValue("SHA1-Digest");

        } catch (Exception e) {

            e.printstacktrace();

        }

        return null ;

    }

    // optDex finish 

    public voID installFinish(Context context){

        SharedPreferences sp = context.getSharedPreferences(

                PackageUtil.getPackageInfo(context).versionname, MODE_MulTI_PROCESS);

        sp.edit().putString(KEY_DEX2_SHA1,get2thDexSHA1(context)).commit();

    }

  

    public static String getCurProcessname(Context context) {

        try {

            int pID = androID.os.Process.myPID();

            ActivityManager mActivityManager = (ActivityManager) context

                    .getSystemService(Context. ACTIVITY_SERVICE);

            for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager

                    .getRunningAppProcesses()) {

                if (appProcess.pID == pID) {

                    return appProcess. processname;

                }

            }

        } catch (Exception e) {

            // ignore

        }

        return null ;

    }

    public voID waitForDexopt(Context base) {

        Intent intent = new Intent();

        Componentname componentname = new

                Componentname( "com.zongwu", LoadResActivity.class.getname());

        intent.setComponent(componentname);

        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        base.startActivity(intent);

        long startWait = System.currentTimeMillis ();

        long waitTime = 10 * 1000 ;

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1 ) {

            waitTime = 20 * 1000 ;//实测发现某些场景下有些2.3版本有可能10s都不能完成optdex

        }

        while (neeDWait(base)) {

            try {

                long NowWait = System.currentTimeMillis() - startWait;

                LogUtils.d("loadDex" , "wait ms :" + NowWait);

                if (NowWait >= waitTime) {

                    return;

                }

                Thread.sleep(200 );

            } catch (InterruptedException e) {

                e.printstacktrace();

            }

        }

    }

}

PackageUtil的方法

 

 public static PackageInfo getPackageInfo(Context context){

        PackageManager pm = context.getPackageManager();

        try {

            return pm.getPackageInfo(context.getPackagename(), 0);

        } catch (PackageManager.nameNotFoundException e) {

            LogUtils.e(e.getLocalizedMessage());

        }

        return  new PackageInfo();

    }

这里使用了classes(N).dex的方式保存了后面的dex而不是像微信目前的做法放到assest文件夹。前面有说到ART模式会将多个dex优化合并成oat文件。如果放置在asset里面就没有这个好处了。
Launcher Activity 依然是原来的代码里的WelcomeActivity。
在Application启动的时候会检测dexopt是否已经完成过,(检测方式是查看sp文件是否有dex文件的SHA1-Digest记录,这里要两个进程读取该sp,读取模式是MODE_MulTI_PROCESS)。如果没有就启动LoadDexActivity(属于:mini进程) 。否则就直接install dex !对,直接install。通过日志发现,已经dexopt的dex文件再次install的时候 只耗费几十毫秒。
LoadDexActivity 的逻辑比较简单,启动AsyncTask 来install dex 这时候会触发dexopt 。

 

public class LoadResActivity extends Activity {

    @OverrIDe

    public voID onCreate(Bundle savedInstanceState) {

        requestwindowFeature(Window.FEATURE_NO_Title);

        super .onCreate(savedInstanceState);

        getwindow().setFlags(WindowManager.LayoutParams.FLAG_FulLSCREEN , WindowManager.LayoutParams.FLAG_FulLSCREEN );

        overrIDePendingTransition(R.anim.null_anim, R.anim.null_anim);

        setContentVIEw(R.layout.layout_load);      

        new LoadDexTask().execute();

    }

    class LoadDexTask extends AsyncTask {

        @OverrIDe

        protected Object doInBackground(Object[] params) {

            try {

                MultIDex.install(getApplication());

                LogUtils.d("loadDex" , "install finish" );

                ((App) getApplication()).installFinish(getApplication());

            } catch (Exception e) {

                LogUtils.e("loadDex" , e.getLocalizedMessage());

            }

            return null;

        }

        @OverrIDe

        protected voID onPostExecute(Object o) {

            LogUtils.d( "loadDex", "get install finish");

            finish();

            System.exit( 0);

        }

    }

    @OverrIDe

    public voID onBackpressed() {

        //cannot backpress

    }

Manifest.xml 里面 

 

<activity

    androID:name= "com.zongwu.LoadResActivity"

    androID:launchMode= "singleTask"

    androID:process= ":mini"

    androID:alwaysRetainTaskState= "false"

    androID:excludeFromrecents= "true"

    androID:screenorIEntation= "portrait" />

 

<activity

    androID:name= "com.zongwu.WelcomeActivity"

    androID:launchMode= "singletop"

    androID:screenorIEntation= "portrait">

    <intent-filter >

        <action androID:name="androID.intent.action.MAIN"/>

        <category androID:name="androID.intent.category.LAUNCHER"/>

    </intent-filter >

</activity>

替换Activity默认的出现动画 R.anim.null_anim 文件的定义:

 

<set xmlns:androID="http://schemas.androID.com/apk/res/androID">

    <Alpha

        androID:fromAlpha="1.0"

        androID:toAlpha="1.0"

        androID:duration="550"/>

 

总结

以上是内存溢出为你收集整理的异步加载分包全部内容,希望文章能够帮你解决异步加载分包所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1043054.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存