Android M 6.0,关于ActivityThread和ApplicationThread的解析.

      文章仅仅用于个人的学习记录,基本上内容都是网上各中资料,此处摘录过来以自己的理解学习方式记录一下。
        ActivityThread和ApplicationThread的理解在你阅读源代码尤其和进程启动,service、activity启动等相关的代码时,就能发现其重要性了。
1、ActivityThread.
        在Android中它就代表了Android的主线程,注意是代表而不是说它就是一个Thread类,它是创建完新进程之后(肯定是在
    一个线程中啊),main函数被加载,然后执行一个loop的循环使当前线程进入消息循环,并且作为主线程。接下来还会初始化
    很多 必要 的属性.   它的很多成员变量和内部类十分的重要,深入理解这些成员变量有助于我们进一步的认识Android系统的各个组件的交互。
       1.1、它的main函数如下.
   
   
public static void main(String[] args) {
......
 
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();//实例化这个类
thread.attach(false);//这个attach也很关键后面分析.
 
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();//很重要mainHandler用于处理UI线程的各种信息
}
......  
Looper.loop();
//可以看出来主线程也是在无限的循环的,异常退出循环的时候会报错.  
throw new RuntimeException("Main thread loop unexpectedly exited");
}
            注意此处虽然new 出了ActivityThread的实例但是它的局部的啊,那我们怎么得到这个实例那?
   
   
private static ActivityThread sCurrentActivityThread;
public static ActivityThread currentActivityThread() {
return sCurrentActivityThread;
}
private void attach(boolean system) {
sCurrentActivityThread = this;
......//其它的我们后面专门分析.
}
            通过currentActivityThread()的方法.
        1.2、final ApplicationThread mAppThread = new ApplicationThread();这个成员变量我们后面专门分析.
                 它就是作为服务端,接收ActivityManagerService的指令并执行.是ActivityThread与AMS连接的桥梁.
        1.3、final H mH = new H()
                  这个H是继承自Handler的,它是个私有的内部类,其实就是主线程的Handler,通过这个Handler就可以往主线程
              的消息队列发消息如:启动Activity、service,接收广播等等,很多重要的工作.
                  这个成员变量mH默认权限修饰符可以通过ActivityThread的如下方法来获得.
   
   
private class H extends Handler {......}
final Handler getHandler() {
return mH;
}
                 这个消息队列可以说是一个中转站,用来更好的分类管理各种类别的业务的处理,如AMS创建service,通过
             mAppThread 这个 binder对象的 成员变量当中的方法,进而往消息队列中发送相应的消息,然后在不同的case中作出
            相应的处理.如:startservice()的流程最后.调用到 ApplicationThread scheduleCreateService(跨进程)
   
   
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
 
sendMessage(H.CREATE_SERVICE, s);
}
   
   
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
    
    
private void handleCreateService(CreateServiceData data) {
......
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
......
}
 
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
 
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
 
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}
} catch (Exception e) {
......
}
}
           这样最终完成service的启动,调用到service的onCreate的方法,很多这样的调用模式,需要熟悉。
           这样我们就会发现ActivityThread中好多类似的重要的方法用于最终的事件处理.如下:
   
   
handleActivityConfigurationChanged()
handleBindApplication()
handleBindService()
handleCancelVisibleBehind()
handleConfigurationChanged()
handleCreateService()
handleDestroyActivity()
handleDispatchPackageBroadcast()
handleLaunchActivity()
handleLowMemory()
handleMessage()
handleNewIntent()
handlePauseActivity()
handleReceiver()
handleRelaunchActivity()
handleResumeActivity()
handleSendResult()
handleServiceArgs()
handleStopActivity()
handleStopService()
handleUnbindService()
        光看名字都能感觉到这些函数的重要性,而这些函数有的又会调用到如下的系列函数完成最终的事件处理.
   
   
performDestroyActivity()
performDestroyActivity()
performLaunchActivity()
performNewIntents()
performPauseActivity()
performPauseActivity()
performRestartActivity()
performResumeActivity()
performStopActivity()
performStopActivityInner()
performUserLeavingActivity()
         1.4、成员变量 mActivities.
              它包含了当前进程的所有的activity,(一个进程对应一个ActivityThread)注意不是简单的把activity做了数据集
           合,而是封装成了 ActivityClientRecord.
           final ArrayMap<IBinder,ActivityClientRecord> mActivities  = new ArrayMap<IBinder,ActivityClientRecord>()
              那么就需要看一下 ActivityClientRecord了.
  
  
static final class ActivityClientRecord {
IBinder token;
int ident;
Intent intent;
String referrer;
IVoiceInteractor voiceInteractor;
Bundle state;
PersistableBundle persistentState;
Activity activity;
Window window;
Activity parent;
String embeddedID;
Activity.NonConfigurationInstances lastNonConfigurationInstances;
boolean paused;
boolean stopped;
boolean hideForNow;
Configuration newConfig;
Configuration createdConfig;
ActivityClientRecord nextIdle;
 
ProfilerInfo profilerInfo;
 
ActivityInfo activityInfo;
CompatibilityInfo compatInfo;
LoadedApk packageInfo;
 
List<ResultInfo> pendingResults;
List<ReferrerIntent> pendingIntents;
 
boolean startsNotResumed;
boolean isForward;
int pendingConfigChanges;
boolean onlyLocalRequest;
 
View mPendingRemoveWindow;
WindowManager mPendingRemoveWindowManager;
 
ActivityClientRecord() {
parent = null;
embeddedID = null;
paused = false;
stopped = false;
hideForNow = false;
nextIdle = null;
}
......
public boolean isPersistable() {
return activityInfo.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS;
}
......
}
         在ActivityThread当中最终通过performLaunchActivity()来完成Activity的启动.先只贴出要分析的代码.
   
   
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......//完成Activity的启动.
mActivities.put(r.token, r);
}
         可以看到最终完成Activity在本进程中的启动的时候,会以ActivityClientRecord的成员变量token为key,以 ActivityCli
      e nt Record为value.存入到mActivitys当中.这个token是一个IBinder的变量.(??最后补上)那么问题的关键就是 ActivityCli e
      n t Record是怎么实例化然后传入过来的?我们在往上一层跟.
  
  
public final Activity startActivityNow(Activity parent, String id,
Intent intent, ActivityInfo activityInfo, IBinder token, Bundle state,
Activity.NonConfigurationInstances lastNonConfigurationInstances) {
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = 0;
r.intent = intent;
r.state = state;
r.parent = parent;
r.embeddedID = id;
r.activityInfo = activityInfo;
r.lastNonConfigurationInstances = lastNonConfigurationInstances;
......
return performLaunchActivity(r, null);
}
        可以看到很多关键信息都是由调用给这个方法的类传入的,其实就是AMS.我们在分析Activity启动的时候会详细分析.相对
     非常重要的有token、intent、activityInfo等.尤其这个ActivityInfo包含了太多的Activity的信息.
     
         1.5、成员变量 mServices
              它和mActivities类似的处理方式,里面也是包含了当前进程中所有的services,不过就是直接存放的当前Service的信息,没有封装
= new ArrayMap<IBinder, Service>();
   
   
private void handleCreateService(CreateServiceData data) {
try {
......
mServices.put(data.token, service);
......
} catch (Exception e) {
......
}
}
             也是最终完成startService的流程后,以key = CreateServiceData.token,Value = 启动的Service.存入到 mServices 
             当中。那么问题又来了我们就需要看一下 CreateServiceData怎么来的了.
               首先 handleCreateService是由mH中的case走过来的.
   
   
        case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
            找到本类中发送消息的地方.
   
   
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
            也同样可以看到 CreateServiceData就是把一些关键的信息封装到了一起如:token、info等,这些在分析启动service
        的流程的时候一定要仔细.
          1.6、其它
               还有很多的成员变量如:
                   Configuration mConfiguration;
                   final ArrayList<Application> mAllApplications = new ArrayList<Application>();
                   final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<String, WeakReference<LoadedApk>>();
                   final ArrayMap<ProviderKey,ProviderClientRecord> mProviderMap = new ArrayMap<ProviderKey,ProviderClientRecord>();
                   final ArrayMap<IBinder,ProviderClientRecord> mLocalProviders = new ArrayMap<IBinder ProviderClientRecord>();
               还有很多的内部类如:
                          static final class BindServiceData :用来封装使用bindeservice启动的时候的service的信息.
                         static final class ReceiverData    : 用来封装和广播处理相关的一些信息.
                         final class ProviderClientRecord   : 用来封装和Provider交互的一些信息
                           static final class AppBindData     : 用来封装和Application交互时的一些信息.
              这些都不一一分析了.遇到的时候或者感兴趣的时候再去研究一下.
        1.7、最后我们再分析一下attach的方法.
               这个方法在新进程启动完毕后会在main方法中调用,这是一种调用方法,其实它还会在systemMain()当中调用并且
            传 入的参数是true.它是由SystemServer.java调用的(没研究过这块的启动应该是系统的某个初始进程,没走Zygote)   
  
  
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
......
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);//很关键.
} catch (RemoteException ex) {
// Ignore
}
// Watch for getting close to heap limit.
......
} else {
// Don't set application object here -- if the system crashes,
// we can't display an alert, we just want to die die die.
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
 
ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
synchronized (mResourcesManager) {
......
sendMessage ( H . CONFIGURATION_CHANGED , newConfig );
.....
}
}
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(int level) {
}
});
}
           此处我们重点关注非系统的的逻辑.是通过mgr.attachApplication(mAppThread)调用AMS的对应方法,(发现解锁Binder)
       以后真的是读代码各种顺.注意:mAppThread对象的传入.
   
   
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
          获得了正在Binder通信的客户端的uid然后和ApplicationThread对象作为参数传入到AMS的attachApplicationLocked中
   
   
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
 
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);//在整个启动进程的流程中在前面已经push进入
}
} else {
app = null;
}
if (app == null) {
......
return false;//为null的时候直接返回.
}
//正常第一次开启时此时还是null
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
......
final String processName = app.processName;
......
//下面这个方法很关键,来时例化ProcessRecord的thread变量.它是一个IApplicationThread对象.  
app.makeActive(thread, mProcessStats);//在这里实现的附着!
app.curAdj = app.setAdj = -100;
app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.forcingToForeground = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
app.killedByAm = false;
 
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
 
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
......
try {
......
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
......
return false;
}
 
// Remove this record from the list of starting applications.
mPersistentStartingProcesses.remove(app);
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
"Attach application locked removing on hold: " + app);
mProcessesOnHold.remove(app);
 
boolean badApp = false;
boolean didSomething = false;
 
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
.....
}
 
// Find any services that should be running in this process...
if (!badApp) {
......
}
 
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
......
}
 
// Check whether the next backup agent is in this process...
if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
......
}
 
if (badApp) {
......
}
 
if (!didSomething) {
......
}
 
return true;
}
         在此处我们集中在为ProcessRecord的成员变量IApplicationThread thread赋值的步骤,也就是调用ProcessRecord中的
      makeActive(thread,mProcessStats);
   
   
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {//zy 它就是赋值thread.
if (thread == null) {
......
}
thread = _thread;
}

2、ApplicationThread.
      它是ActivityThread的私有内部类,也是一个Binder对象。在此处它是作为IApplicationThread对象的server端等待client端
   的请求然后进行处理,最大的client就是AMS.
  
  
private class ApplicationThread extends ApplicationThreadNative {
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
......
}
public final void scheduleStopActivity(IBinder token, boolean showWindow,
int configChanges) {
......
}
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state,
PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward,
ProfilerInfo profilerInfo) {
......
}
......  
}
       可以看出来它是继承自ApplicationThreadNative的,并且它内部有非常多的scheduleXXX的方法.以后看到thread调用这个方法
    就可以往这边找。我们先说一下这些方法,这些方法由外部的ActivityThread的binder远程代理对象调用最终走到这里.这些
    schedulexxx的方法会进一步的通过往外发送消息给mH这个消息队列.来做处理.比如:
   
   
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
 
sendMessage(H.CREATE_SERVICE, s);
}
       比较重要的 schedulexxx方法有:
    
    
schedulePauseActivity()
scheduleStopActivity()
scheduleResumeActivity()
scheduleSendResult()
scheduleLaunchActivity()
scheduleNewIntent()
scheduleDestroyActivity()
scheduleReceiver()
scheduleCreateService()
scheduleBindService()
scheduleUnbindService()
scheduleServiceArgs()
scheduleStopService()
bindApplication()
scheduleConfigurationChanged()
scheduleRegisteredReceiver()
scheduleInstallProvider()
还有很多dump信息的处理
        这些方法放在此处眼熟,暂时没精力一个个分析,从名字也能看出大概的功能.
        接下来我们再看看 ApplicationThreadNative,看这个函数的名字感觉就应该是被实现为了一个Binder对象。
  
  
/** {@hide} */
public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
//根据传入的不同参数决定返回不同的值.
static public IApplicationThread asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IApplicationThread in =
(IApplicationThread)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ApplicationThreadProxy(obj);
}
 
public ApplicationThreadNative() {
attachInterface(this, descriptor);
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
......
}
}
public IBinder asBinder()
{
return this;
}
 
}
        果不其然啊,并且还是先了业务接口IApplicationThread,非常标准的Binder模板.IApplicationThread extends IInterface
     它里面就是定义了非常多的通信的业务接口,也都是schedulexxx理解上对应到 ApplicationThread那些方法.
        首先是提供了一个静态的方法asInterface()用来获取IApplicationThread的Binder对象或者Binder代理对象,其 它进程跨进
     程调用时候当传入的是BinderProxy那么就会返回一个ApplicationThreadProxy对象并把BinderProxy传入它的构 造.而一般在
     本进程中调用的时候,就直接返回当前 IApplicationThread对象.然后就是onTransact()函数了,里面通过不同的code对应到不
     同的case,进而调用不同的schedulexxx的方法,最终调入到 ApplicationThread中的schedulexxx.
         ApplicationThread这样就完成了作为服务端的构架,接下来就就是代理端的分析了.前面我们知道跨进程调用asInterface的
     时候返回的是ApplicationThreadProxy对象,该类位于 ApplicationThreadNative.java文件当中,但是不是内部类,同文件而已.
          
  
  
class ApplicationThreadProxy implements IApplicationThread {
private final IBinder mRemote;
public ApplicationThreadProxy(IBinder remote) {
mRemote = remote;
}
public final IBinder asBinder() {
return mRemote;
}
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
data.writeInt(finished ? 1 : 0);
data.writeInt(userLeaving ? 1 :0);
data.writeInt(configChanges);
data.writeInt(dontReport ? 1 : 0);
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
public final void scheduleStopActivity(IBinder token, boolean showWindow,
int configChanges) throws RemoteException {
......
}
......//一些列的schedulexxx  
 
}
        也是代理端的标准实现,实现了IApplicationThread 接口,然后重写出接口中定义的业务方法,在每个方法中最终调用到了
     服务端的对应的schedulexxx方法中.通过mRemote变量和驱动去交互进而调用到server端,  mRemote是一个BinderProxy对象.
        关于 IApplicationThread 的Binder相关实现,有个需要注意的它没有趣service manager中注册,走的是一个匿名的binder的
     方法,其实对于驱动来说都一样.暂时发现的是别的地方如AMS用的时候通过ActivityThread的接口获得到 ApplicationThread的
     对象,然后传入到asInterface(),获取对应的 IApplicationThread 对象进行跨进程调用.
   
3、Instrumentation.
      在android.app包下有Instrumentation这个类,这个类没有继承和实现其它的任何类,也没被其它的类继承.会在应用的任何
   代 码执行前被实列化,用来监控系统组件与应用的交互过程,其实就是很多操作封装一下,由它来完成实现. Instrumentation另
   一个重要作用是提供Android组件单元测试    
      每一个应用进程中只有唯一的Instrumentation, 在ActivityThread中 成员变量Instrumentation mInstrumentation,通过方法   
    public  Instrumentation getInstrumentation()来获得.
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
这是什么问题FATAL EXCEPTION: main Process: com.example.lightcontrol_app2, PID: 4533 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.lightcontrol_app2/com.example.lightcontrol_app2.ui.control.activity.EditingSingleLampActivity}: java.lang.RuntimeException: setOnItemClickListener cannot be used with a spinner. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2668) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2729) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1480) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6176) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783) Caused by: java.lang.RuntimeException: setOnItemClickListener cannot be used with a spinner. at android.widget.Spinner.setOnItemClickListener(Spinner.java:571) at com.example.lightcontrol_app2.ui.control.activity.EditingSingleLampActivity.init(EditingSingleLampActivity.java:111) at com.example.lightcontrol_app2.ui.control.activity.EditingSingleLampActivity.onCreate(EditingSingleLampActivity.java:65) at android.app.Activity.performCreate(Activity.java:6692) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2621) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2729) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1480) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6176) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
06-11

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值