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"/>
总结
以上是内存溢出为你收集整理的异步加载分包全部内容,希望文章能够帮你解决异步加载分包所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)