对于安卓的开发,我并没有太多的经验,并且很多的东西目前也没有深入的研究。最近在更新Findu的安卓版本的时候,出现了一个意外的错误。错误代码如下:
03-07 15:03:30.046 12215-12290/today.findu.findu.alibaba.openIMUI:watchdog E/AndroidRuntime: FATAL EXCEPTION: initFeedbackThread
Process: today.findu.findu.alibaba.openIMUI:watchdog, PID: 12215
com.alibaba.wxlib.exception.WXRuntimeException: should call prepareTargetKey first
at com.alibaba.mobileim.utility.AccountInfoTools.initTargetAppKeys(AccountInfoTools.java:190)
at com.alibaba.mobileim.FeedbackAPI.initFeedbackImpl(FeedbackAPI.java:108)
at com.alibaba.mobileim.FeedbackAPI.access$000(FeedbackAPI.java:38)
at com.alibaba.mobileim.FeedbackAPI$1.run(FeedbackAPI.java:97)
at java.lang.Thread.run(Thread.java:761)
并且同时还有大量的其他的错误信息:
03-07 15:03:34.274 12215-12215/today.findu.findu.alibaba.openIMUI:watchdog E/security: [2014@taobao_h5_3.0.0][WLqJSW6PXu8DAOb+xk4MZjLO][] : ***********************************************************
错误编码 = 10010
错误消息 = 发生错误,消息为 null sec code 162, 请使用 LogCat 查看更多细节
解决建议 = 请使用默认的 androiddebugkey 对当前开发应用签名或在应用初始化之前调用 AlibabaSDK.turnOnDebug(), 运行程序查看 logcat 输出以获取更多错误细节,并采取对应操作
错误堆栈 = ErrorCode = 162
com.alibaba.wireless.security.open.SecException
at com.alibaba.wireless.security.open.initialize.c.a(Unknown Source)
at com.alibaba.wireless.security.open.initialize.a.a(Unknown Source)
at com.alibaba.wireless.security.open.initialize.b.b(Unknown Source)
at com.alibaba.wireless.security.open.initialize.b.loadLibrarySync(Unknown Source)
at com.alibaba.wireless.security.open.initialize.b.initialize(Unknown Source)
at com.alibaba.sdk.android.security.impl.h.a(SourceFile:23)
at com.alibaba.sdk.android.security.impl.SecurityGuardWrapper.init(SourceFile:61)
at java.lang.reflect.Method.invoke(Native Method)
at com.alibaba.sdk.android.a.a.a.a(SourceFile:91)
at com.alibaba.sdk.android.task.a.c(SourceFile:186)
at com.alibaba.sdk.android.task.a.a(SourceFile:144)
at com.alibaba.sdk.android.AlibabaSDK.a(SourceFile:135)
at com.alibaba.sdk.android.AlibabaSDK.asyncInit(SourceFile:98)
at cn.org.findu.finduUI.demo.DemoApplication.onCreate(DemoApplication.java:61)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1024)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5403)
at android.app.ActivityThread.-wrap2(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
刚开始的时候按照第二段错误代码作为关键词进行搜索:请使用默认的 androiddebugkey 对当前开发应用签名或在应用初始化之前调用 AlibabaSDK.turnOnDebug()
搜索到的信息并没有什么太大的用处,也没有解决问题。于是考虑可能是集成的hellodaemon有问题,于是给hellodaemon的作者发了一封邮件询问相关的事宜。比较诡异的是使用淘宝的openimsdkdemo的项目,最终问题竟然消失了,于是又给他发了一封邮件说明问题。既然官方的demo能解决这个问题,那说明最终的问题并非是出在他们的代码上,很可能是自己的环境配置或者代码有问题。于是继续搜索相关的错误信息,这时才看到第一段错误信息,于是按照第一段的错误信息作为关键字进行搜索:com.alibaba.wxlib.exception.WXRuntimeException: should call prepareTargetKey first 当然请使用google,不要用百毒,百毒什么都不知道。
搜索到这个链接:https://bbs.aliyun.com/read/289869.html,里面提到了同样的错误。但是并没有解决问题的方法,于是继续分析这个错误信息,发现这个错误是出现在创建的独立进程today.findu.findu.alibaba.openIMUI:watchdog 里,而不是主进程,于是猜测应该是在初始化创建子进程的时候出现了错误,下面的初始化代码:
在子进程中初始化了,而主进程中并没有得到相关的初始化信息。继续看相关初始化的代码发现了这么一段代码:
//todo Application.onCreate中,首先执行这部分代码,以下代码固定在此处,不要改动,这里return是为了退出Application.onCreate!!!
if(mustRunFirstInsideApplicationOnCreate()){
//todo 如果在":TCMSSevice"进程中,无需进行openIM和app业务的初始化,以节省内存
return;
}
找到函数定义:
private boolean mustRunFirstInsideApplicationOnCreate() {
//必须的初始化
setApplication(this);
sContext = getApplicationContext();
return SysUtil.isTCMSServiceProcess(sContext);
}
猜测问题最终是由于,Application的onCreate()函数并不是调用一次就结束了,会调用多次来创建多个进程,例如创建openim的tcmsservice。那么同样在创建我们的watchgod进程的时候同样也需要直接返回,只有在创建主进程的时候才能执行初始化代码。否则就会导致上面的第二段错误,1.在错误的地方执行了初始化,导致主进程无法找到初始化信息2.在错误的地方初始化,无法初始化主进程的相关实现继续报错。
那么要解决这个问题也就简单了,参考上面的函数实现,进行一下进程onCreate判断:
private boolean isWatchDog()
{
setApplication(this);
sContext = getApplicationContext();
setApplication(sContext);
String procName = getCurProcessName(sContext);
return procName != null && procName.contains(":watchdog");
}
到这里问题就完全解决了,最后来说一下Android下的Application onCreate()相关的知识(与我的猜测是基本一致的,在此之前并没有搜索过相关的信息,嘎嘎)
一般情况下,一个应用开启一个进程,application会被执行一次,如果涉及多开进程,那情况就不同了,application就会被执行多次,下面笔者根据这问题对应用开启多进程的进行分析:
android:process说到Android进程,我们就得了解android:process这个属性,这个属性有什么作用?我们就来看看:
在Android的帮助文档中我们可以了解到,一般情况下一个服务没有自己独立的进程,它一般是作为一个线程运行于它所在的应用的进程中。但是也有例外,Android声明文件中的android:process属性却可以为任意组件包括应用指定进程,换句话说,通过在声明文件中设置android:process属性,我们可以让组件(例如Activity, Service等)和应用(Application)创建并运行于我们指定的进程中。
举个例子://包名 //为activity开启一个进程 上面就是为登录的Activity开启一个叫login进程,只不过这个进程是在以应用默认的包名下开启的进程,叫com.soubw.prodemo:login,在属性中值为什么以冒号开头呢,因为’:’这个前缀将把这个名字附加到你的包所运行的标准进程名字的后面作为新的进程名称(只不过这个login进程为该应用私用,其他应用不能共享),上面的例子很好的讲述这点。
还有一种是不以冒号开头而以小写字母开头,我们也举个例子来说明:
//为activity开启一个不同于应用包名的进程 这个进程将以com.wxj.register这个名字命名的运行于全局的进程中(该进程就可以让不同应用中的各种组件可以共享一个进程)。
解决多进程次执行多次onCreate()如果应用中采用多进程方式,oncreate方法会执行多次,根据不同的进程名字进行不同的初始化。应用判断进程名字进行单独初始化,这要就可以利用进程名根据具体需求,应该加载哪些资源,执行哪些具体逻辑了。
@Override public void onCreate() { super.onCreate(); String processName = getProcessName(this); if (processName!= null) { if(processName.equals("com.soubw.prodemo")){ //初始化com.soubw.prodemo以包名为进程名,项目默认的进程 } else if(processName.equals("com.soubw.prodemo:login")){ //初始化com.soubw.prodemo:login }else if(processName.equals("com.wxj.register")){ //初始化com.wxj.register }else{ } } } private String getProcessName(Context context) { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); ListrunningApps = am.getRunningAppProcesses(); if (runningApps == null) { return null; } for (ActivityManager.RunningAppProcessInfo proInfo : runningApps) { if (proInfo.pid == android.os.Process.myPid()) { if (proInfo.processName != null) { return proInfo.processName; } } } return null; }
参考链接:http://blog.csdn.net/wx_jin/article/details/50894058
1 comment
非常不错的技术博客,以后会常来的。