版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
踩坑之路:finish方法执行后居然还有这种操作?某天,测试提了一个bug,说当前页面关闭了以后回到了上一个页面,但是对应的音乐并没有立刻停止,而是过了一段时间才停止。于是翻阅了一下代码:
@Override
protected
void
onStop()
{
super.onStop();
if
(mIsLoading)
{
mAudioTool.pausePlayAudio();
}
}mAudioTool.pausePlayAudio方法是停止播放音频的代码,似乎并没有什么问题。而且这段代码已经运行了好久,之前测试也是通过的,为何这个版本会出现这个问题?所以首先我debug一下当前页面的onStop方法,结果发现页面关闭的时候onStop方法并没有被执行,然后过了差不多10s左右再被执行,感觉又是踩到了某个坑里面去了,仔细回想了最近改了的代码,问题可能出在了上一个页面的下面这段代码:
/**
*
开始抖动
*/
private
fun
startShake()
{
if(mRotateAnim
==
null){
mRotateAnim
=
RotateAnimation(-2f,
2f,
Animation.RELATIVE_TO_SELF,
0.5f,
Animation.RELATIVE_TO_SELF,
0.5f)
}
if
(mRotateAnim!!.hasStarted()
&&
!mRotateAnim!!.hasEnded())
{
//当前动画已经开始并且没有结束
return
}
//从左向右
mRotateAnim!!.duration
=
50
mRotateAnim!!.repeatMode
=
Animation.REVERSE
mRotateAnim!!.repeatCount
=
Animation.INFINITE
val
smallAnimationSet
=
AnimationSet(false)
smallAnimationSet.addAnimation(mRotateAnim)
cl_wrong_book.startAnimation(smallAnimationSet)
}由于设置的repeatCount是INFINITE,所以动画是一直在执行中的。不过还是有点纳闷,动画跟Activity生命周期有啥关系?为了印证下到底是不是Animation影响的当前页面生命周期调用异常,于是将这段代码进行了删除操作。结果Activity的onStop生命周期还真的就正常执行了。然后自己又做了一个demo,来查看下onStop的执行时间。(这段是没有动画的)2020-12-14
12:40:17.334
24575-24575/com.example.demo
I/MainActivity:
onCreate
2020-12-14
12:40:17.663
24575-24575/com.example.demo
I/MainActivity:
onStart
2020-12-14
12:40:17.670
24575-24575/com.example.demo
I/MainActivity:
onResume
2020-12-14
12:40:20.818
24575-24575/com.example.demo
I/MainActivity:
onPause
2020-12-14
12:40:20.836
24575-24575/com.example.demo
I/SecondActivity:
onCreate
2020-12-14
12:40:20.857
24575-24575/com.example.demo
I/SecondActivity:
onStart
2020-12-14
12:40:20.858
24575-24575/com.example.demo
I/SecondActivity:
onResume
2020-12-14
12:40:21.406
24575-24575/com.example.demo
I/MainActivity:
onStop
2020-12-14
12:40:22.930
24575-24575/com.example.demo
I/SecondActivity:
onPause
2020-12-14
12:40:22.936
24575-24575/com.example.demo
I/MainActivity:
onStart
2020-12-14
12:40:22.937
24575-24575/com.example.demo
I/MainActivity:
onResume
2020-12-14
12:40:23.439
24575-24575/com.example.demo
I/SecondActivity:
onStop
2020-12-14
12:40:23.440
24575-24575/com.example.demo
I/SecondActivity:
onDestroy(这段是加上动画的)2020-12-14
12:38:06.392
24278-24278/com.example.demo
I/MainActivity:
onCreate
2020-12-14
12:38:06.563
24278-24278/com.example.demo
I/MainActivity:
onStart
2020-12-14
12:38:06.565
24278-24278/com.example.demo
I/MainActivity:
onResume
2020-12-14
12:38:23.940
24278-24278/com.example.demo
I/MainActivity:
onPause
2020-12-14
12:38:23.964
24278-24278/com.example.demo
I/SecondActivity:
onCreate
2020-12-14
12:38:23.980
24278-24278/com.example.demo
I/SecondActivity:
onStart
2020-12-14
12:38:23.980
24278-24278/com.example.demo
I/SecondActivity:
onResume
2020-12-14
12:38:24.544
24278-24278/com.example.demo
I/MainActivity:
onStop
2020-12-14
12:38:28.111
24278-24278/com.example.demo
I/SecondActivity:
onPause
2020-12-14
12:38:28.117
24278-24278/com.example.demo
I/MainActivity:
onStart
2020-12-14
12:38:28.118
24278-24278/com.example.demo
I/MainActivity:
onResume
2020-12-14
12:38:38.153
24278-24278/com.example.demo
I/SecondActivity:
onStop
2020-12-14
12:38:38.155
24278-24278/com.example.demo
I/SecondActivity:
onDestroydemo的log也显示了在加上动画以后,确实onStop和onDestroy就会被延迟执行,而且试了多次,发现每次延迟的时间都是10s左右。所以猜测一定存在某种定时执行onStop操作的场景,不然不可能每次都这么凑巧。既然踩到坑,那么我就得想办法搞清楚为什么会出现这种情况。所以还是跟以前一样,查阅Android源码一探究竟。finish()操作
/**
*
Finishes
the
current
activity
and
specifies
whether
to
remove
the
task
associated
with
this
*
activity.
*/
@UnsupportedAppUsage
private
void
finish(int
finishTask)
{
if
(mParent
==
null)
{
int
resultCode;
Intent
resultData;
synchronized
(this)
{
resultCode
=
mResultCode;
resultData
=
mResultData;
}
if
(false)
Log.v(TAG,
"Finishing
self:
token="
+
mToken);
try
{
if
(resultData
!=
null)
{
resultData.prepareToLeaveProcess(this);
}
if
(ActivityTaskManager.getService()
.finishActivity(mToken,
resultCode,
resultData,
finishTask))
{
mFinished
=
true;
}
}
catch
(RemoteException
e)
{
//
Empty
}
}
else
{
mParent.finishFromChild(this);
}
//
Activity
was
launched
when
user
tapped
a
link
in
the
Autofill
Save
UI
-
Save
UI
must
//
be
restored
now.
if
(mIntent
!=
null
&&
mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN))
{
getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_RESTORE,
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
}
}
/**
*
Call
this
when
your
activity
is
done
and
should
be
closed.
The
*
ActivityResult
is
propagated
back
to
whoever
launched
you
via
*
onActivityResult().
*/
public
void
finish()
{
finish(DONT_FINISH_TASK_WITH_ACTIVITY);
}Activity的finish方法会调用自身带有参数的finish方法,然后通过Binder会执行ActivityTaskManagerService的finishActivity方法。
@Override
public
final
boolean
finishActivity(IBinder
token,
int
resultCode,
Intent
resultData,
int
finishTask)
{
...代码省略...
synchronized
(mGlobalLock)
{
...代码省略...
try
{
boolean
res;
final
boolean
finishWithRootActivity
=
finishTask
==
Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
if
(finishTask
==
Activity.FINISH_TASK_WITH_ACTIVITY
||
(finishWithRootActivity
&&
r
==
rootR))
{
...代码省略
}
else
{
res
=
tr.getStack().requestFinishActivityLocked(token,
resultCode,
resultData,
"app-request",
true);
if
(!res)
{
Slog.i(TAG,
"Failed
to
finish
by
app-request");
}
}
return
res;
}
finally
{
Binder.restoreCallingIdentity(origId);
}
}
}由于finishTask是DONT_FINISH_TASK_WITH_ACTIVITY类型,所以会走else分支,tr.getStack()得到的是ActivityStack对象,所以接下来执行的就是ActivityStack的requestFinishActivityLocked方法。
/**
*
@return
Returns
true
if
this
activity
has
been
removed
from
the
history
*
list,
or
false
if
it
is
still
in
the
list
and
will
be
removed
later.
*/
final
boolean
finishActivityLocked(ActivityRecord
r,
int
resultCode,
Intent
resultData,
String
reason,
boolean
oomAdj,
boolean
pauseImmediately)
{
if
(r.finishing)
{
//这个判断条件是为了防止多次进入,做了一道屏障
Slog.w(TAG,
"Duplicate
finish
request
for
"
+
r);
return
false;
}
mWindowManager.deferSurfaceLayout();
try
{
//这个方法是为了将finishing设置为true
r.makeFinishingLocked();
final
TaskRecord
task
=
r.getTaskRecord();
EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
r.mUserId,
System.identityHashCode(r),
task.taskId,
r.shortComponentName,
reason);
final
ArrayList
activities
=
task.mActivities;
final
int
index
=
activities.indexOf(r);
if
(index
<
(activities.size()
-
1))
{
task.setFrontOfTask();
if
((ent.getFlags()
&
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
!=
0)
{
//
If
the
caller
asked
that
this
activity
(and
all
above
it)
//
be
cleared
when
the
task
is
reset,
don't
lose
that
information,
//
but
propagate
it
up
to
the
next
activity.
ActivityRecord
next
=
activities.get(index+1);
ent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
}
//停止按键的事件分发
r.pauseKeyDispatchingLocked();
adjustFocusedActivityStack(r,
"finishActivity");
//检查是否有设置ActivityResult,如果存在则加入列表中
finishActivityResultsLocked(r,
resultCode,
resultData);
final
boolean
endTask
=
index
<=
0
&&
!task.isClearingToReuseTask();
final
int
transit
=
endTask
?
TRANSIT_TASK_CLOSE
:
TRANSIT_ACTIVITY_CLOSE;
//当前页面处于Resume状态,所以会进入此分支
if
(mResumedActivity
==
r)
{
if
(DEBUG_VISIBILITY
||
DEBUG_TRANSITION)
Slog.v(TAG_TRANSITION,
"Prepare
close
transition:
finishing
"
+
r);
if
(endTask)
{
mService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
task.getTaskInfo());
}
getDisplay().mDisplayContent.prepareAppTransition(transit,
false);
//
Tell
window
manager
to
prepare
for
this
one
to
be
removed.
r.setVisibility(false);
if
(mPausingActivity
==
null)
{
if
(DEBUG_PAUSE)
Slog.v(TAG_PAUSE,
"Finish
needs
to
pause:
"
+
r);
if
(DEBUG_USER_LEAVING)
Slog.v(TAG_USER_LEAVING,
"finish()
=>
pause
with
userLeaving=false");
//当前页面还没有进入pause状态,所以会调用此方法
startPausingLocked(false,
false,
null,
pauseImmediately);
}
if
(endTask)
{
mService.getLockTaskController().clearLockedTask(task);
}
}
else
if
(!r.isState(PAUSING))
{
//
If
the
activity
is
PAUSING,
we
will
complete
the
finish
once
//
it
is
done
pausing;
else
we
can
just
directly
finish
it
here.
if
(DEBUG_PAUSE)
Slog.v(TAG_PAUSE,
"Finish
not
pausing:
"
+
r);
if
(r.visible)
{
prepareActivityHideTransitionAnimation(r,
transit);
}
final
int
finishMode
=
(r.visible
||
r.nowVisible)
?
FINISH_AFTER_VISIBLE
:
FINISH_AFTER_PAUSE;
final
boolean
removedActivity
=
finishCurrentActivityLocked(r,
finishMode,
oomAdj,
"finishActivityLocked")
==
null;
//
The
following
code
is
an
optimization.
When
the
last
non-task
overlay
activity
//
is
removed
from
the
task,
we
remove
the
entire
task
from
the
stack.
However,
//
since
that
is
done
after
the
scheduled
destroy
callback
from
the
activity,
that
//
call
to
change
the
visibility
of
the
task
overlay
activities
would
be
out
of
//
sync
with
the
activitiy
visibility
being
set
for
this
finishing
activity
above.
//
In
this
case,
we
can
set
the
visibility
of
all
the
task
overlay
activities
when
//
we
detect
the
last
one
is
finishing
to
keep
them
in
sync.
if
(task.onlyHasTaskOverlayActivities(true
/*
excludeFinishing
*/))
{
for
(ActivityRecord
taskOverlay
:
task.mActivities)
{
if
(!taskOverlay.mTaskOverlay)
{
continue;
}
prepareActivityHideTransitionAnimation(taskOverlay,
transit);
}
}
return
removedActivity;
}
else
{
if
(DEBUG_PAUSE)
Slog.v(TAG_PAUSE,
"Finish
waiting
for
pause
of:
"
+
r);
}
return
false;
}
finally
{
mWindowManager.continueSurfaceLayout();
}
}设置当前ActivityRecord为finishing状态停止按键的事件分发检查ActivityResult状态,存在的话就加入到列表中执行startPausingLocked方法。
final
boolean
startPausingLocked(boolean
userLeaving,
boolean
uiSleeping,
ActivityRecord
resuming,
boolean
pauseImmediately)
{
...代码省略...
if
(prev.attachedToProcess())
{
if
(DEBUG_PAUSE)
Slog.v(TAG_PAUSE,
"Enqueueing
pending
pause:
"
+
prev);
try
{
EventLogTags.writeAmPauseActivity(prev.mUserId,
System.identityHashCode(prev),
prev.shortComponentName,
"userLeaving="
+
userLeaving);
mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
prev.appToken,
PauseActivityItem.obtain(prev.finishing,
userLeaving,
prev.configChangeFlags,
pauseImmediately));
}
catch
(Exception
e)
{
//
Ignore
exception,
if
process
died
other
code
will
cleanup.
Slog.w(TAG,
"Exception
thrown
during
pause",
e);
mPausingActivity
=
null;
mLastPausedActivity
=
null;
mLastNoHistoryActivity
=
null;
}
}
else
{
mPausingActivity
=
null;
mLastPausedActivity
=
null;
mLastNoHistoryActivity
=
null;
}
...代码省略...
}这里面有一大段代码都需要管,重点关注里面的mService.getLifecycleManager().scheduleTransaction这个方法。是通过TransactionExecutor进行调度的。这段代码最终会执行ActivityThread里面的下面这段处理:ActivityThread.javacase
EXECUTE_TRANSACTION:
final
ClientTransaction
transaction
=
(ClientTransaction)
msg.obj;
mTransactionExecutor.execute(transaction);
if
(isSystem())
{
//
Client
transactions
inside
system
process
are
recycled
on
the
client
side
//
instead
of
ClientLifecycleManager
to
avoid
being
cleared
before
this
//
message
is
handled.
transaction.recycle();
}
//
TODO(lifecycler):
Recycle
locally
scheduled
transactions.
break;TransactionExecutor.java
private
void
executeLifecycleState(ClientTransaction
transaction)
{
final
ActivityLifecycleItem
lifecycleItem
=
transaction.getLifecycleStateRequest();
if
(lifecycleItem
==
null)
{
//
No
lifecycle
request,
return
early.
return;
}
final
IBinder
token
=
transaction.getActivityToken();
final
ActivityClientRecord
r
=
mTransactionHandler.getActivityClient(token);
if
(DEBUG_RESOLVER)
{
Slog.d(TAG,
tId(transaction)
+
"Resolving
lifecycle
state:
"
+
lifecycleItem
+
"
for
activity:
"
+
getShortActivityName(token,
mTransactionHandler));
}
if
(r
==
null)
{
//
Ignore
requests
for
non-existent
client
records
for
now.
return;
}
//
Cycle
to
the
state
right
before
the
final
requested
state.
cycleToPath(r,
lifecycleItem.getTargetState(),
true
/*
excludeLastState
*/,
transaction);
//
Execute
the
final
transition
with
proper
parameters.
lifecycleItem.execute(mTransactionHandler,
token,
mPendingActions);
lifecycleItem.postExecute(mTransactionHandler,
token,
mPendingActions);
}我们是执行了startPausingLocked方法,那么此处最后自然会执行到PauseActivityItem的execute方法里面去的。execute方法就是简单的做了pause的生命周期方法,重点关注下postExecute方法,这里简单梳理下postExecute的调用链。在公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。PauseActivityItem#poseExecute()ActivityTaskManagerService#activityPaused()ActivityStack#activityPausedLocked()ActivityStack#finishCurrentActivityLocked()RootActivityContainer#resumeFocusedStacksTopActivities()ActivityStack#resumeTopActivityUncheckedLocked()ActivityStack#resumeTopActivityInnerLocked()@GuardedBy("mService")
private
boolean
resumeTopActivityInnerLocked(ActivityRecord
prev,
ActivityOptions
options)
{
...代码省略...
if
(next.attachedToProcess())
{
...代码省略...
try
{
final
ClientTransaction
transaction
=
ClientTransaction.obtain(next.app.getThread(),
next.appToken);
//
Deliver
all
pending
results.
ArrayList
a
=
next.results;
if
(a
!=
null)
{
final
int
N
=
a.size();
if
(!next.finishing
&&
N
>
0)
{
if
(DEBUG_RESULTS)
Slog.v(TAG_RESULTS,
"Delivering
results
to
"
+
next
+
":
"
+
a);
transaction.addCallback(ActivityResultItem.obtain(a));
}
}
if
(next.newIntents
!=
null)
{
transaction.addCallback(
NewIntentItem.obtain(next.newIntents,
true
/*
resume
*/));
}
//
Well
the
app
will
no
longer
be
stopped.
//
Clear
app
token
stopped
state
in
window
manager
if
needed.
next.notifyAppResumed(next.stopped);
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
next.mUserId,
System.identityHashCode(next),
next.getTaskRecord().taskId,
next.shortComponentName);
next.sleeping
=
false;
mService.getAppWarningsLocked().onResumeActivity(next);
next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
getDisplay().mDisplayContent.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
if
(DEBUG_STATES)
Slog.d(TAG_STATES,
"resumeTopActivityLocked:
Resumed
"
+
next);
}
catch
(Exception
e)
{
...代码省略...
return
true;
}
//
From
this
point
on,
if
something
goes
wrong
there
is
no
way
//
to
recover
the
activity.
try
{
pleteResumeLocked();
}
catch
(Exception
e)
{
//
If
any
exception
gets
thrown,
toss
away
this
//
activity
and
try
the
next
one.
Slog.w(TAG,
"Exception
thrown
during
resume
of
"
+
next,
e);
requestFinishActivityLocked(next.appToken,
Activity.RESULT_CANCELED,
null,
"resume-exception",
true);
return
true;
}
}
else
{
//
Whoops,
need
to
restart
this
activity!
if
(!next.hasBeenLaunched)
{
next.hasBeenLaunched
=
true;
}
else
{
if
(SHOW_APP_STARTING_PREVIEW)
{
next.showStartingWindow(null
/*
prev
*/,
false
/*
newTask
*/,
false
/*
taskSwich
*/);
}
if
(DEBUG_SWITCH)
Slog.v(TAG_SWITCH,
"Restarting:
"
+
next);
}
if
(DEBUG_STATES)
Slog.d(TAG_STATES,
"resumeTopActivityLocked:
Restarting
"
+
next);
mStackSupervisor.startSpecificActivityLocked(next,
true,
true);
}
return
true;
}next.attachedToProcess()可以判断next页面是否已经被系统回收,如果是false就代表页面被回收了走else分支,调用StackSupervisor的startSpecificActivityLocked重启页面。如果是true,那么就会通过TransactionExecutor调度执行ResumeActivityItem的execute方法,执行前一个页面的onResume方法。逻辑处理完以后接下来有这么一段代码:
//
From
this
point
on,
if
something
goes
wrong
there
is
no
way
//
to
recover
the
activity.
try
{
pleteResumeLocked();
}
catch
(Exception
e)
{
//
If
any
exception
gets
thrown,
toss
away
this
//
activity
and
try
the
next
one.
Slog.w(TAG,
"Exception
thrown
during
resume
of
"
+
next,
e);
requestFinishActivityLocked(next.appToken,
Activity.RESULT_CANCELED,
null,
"resume-exception",
true);
return
true;
}我们看下completeResumeLocked的逻辑:
void
completeResumeLocked()
{
...代码省略...
//
Schedule
an
idle
timeout
in
case
the
app
doesn't
do
it
for
us.
mStackSupervisor.scheduleIdleTimeoutLocked(this);
...代码省略...
}
void
scheduleIdleTimeoutLocked(ActivityRecord
next)
{
if
(DEBUG_IDLE)
Slog.d(TAG_IDLE,
"scheduleIdleTimeoutLocked:
Callers="
+
Debug.getCallers(4));
Message
msg
=
mHandler.obtainMessage(IDLE_TIMEOUT_MSG,
next);
mHandler.sendMessageDelayed(msg,
IDLE_TIMEOUT);
}主要就是发送一个延时的message,message主要就是用了执行Activity的onStop和onDestroy生命周期,而IDLE_TIMEOUT正是10s。当前页面的Activity执行了finish操作,并且onStop已经调用,然后上一个页面的onResume方法也已经调用。至此finish相关的操作逻辑告一段落,但是似乎没有看到执行onStop和onDestroy地方(只有一个延迟10s执行的代码)。handleResumeActivity的处理
@Override
public
void
handleResumeActivity(IBinder
token,
boolean
finalStateRequest,
boolean
isForward,
String
reason)
{
...代码省略...
//这段代码最终会执行Activity的onResume方法
final
ActivityClientRecord
r
=
performResumeActivity(token,
finalStateRequest,
reason);
...代码省略...
if
(r.window
==
null
&&
!a.mFinished
&&
willBeVisible)
{
//这个判断条件代表当前页面是第一次进入,条件里面的处理就是初始化ViewRootImpl,将View添加在Window上面,执行View的第一次绘制操作
r.window
=
r.activity.getWindow();
View
decor
=
r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager
wm
=
a.getWindowManager();
WindowManager.LayoutParams
l
=
r.window.getAttributes();
a.mDecor
=
decor;
l.type
=
WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode
|=
forwardBit;
if
(r.mPreserveWindow)
{
a.mWindowAdded
=
true;
r.mPreserveWindow
=
false;
//
Normally
the
ViewRoot
sets
up
callbacks
with
the
Activity
//
in
addView->ViewRootImpl#setView.
If
we
are
instead
reusing
//
the
decor
view
we
have
to
notify
the
view
root
that
the
//
callbacks
may
have
changed.
ViewRootImpl
impl
=
decor.getViewRootImpl();
if
(impl
!=
null)
{
impl.notifyChildRebuilt();
}
}
if
(a.mVisibleFromClient)
{
if
(!a.mWindowAdded)
{
a.mWindowAdded
=
true;
wm.addView(decor,
l);
}
else
{
//
The
activity
will
get
a
callback
for
this
{@link
LayoutParams}
change
//
earlier.
However,
at
that
time
the
decor
will
not
be
set
(this
is
set
//
in
this
method),
so
no
action
will
be
taken.
This
call
ensures
the
//
callback
occurs
with
the
decor
set.
a.onWindowAttributesChanged(l);
}
}
//
If
the
window
has
already
been
added,
but
during
resume
//
we
started
another
activity,
then
don't
yet
make
the
//
window
visible.
}
else
if
(!willBeVisible)
{
if
(localLOGV)
Slog.v(TAG,
"Launch
"
+
r
+
"
mStartedActivity
set");
r.hideForNow
=
true;
}
...代码省略...
r.nextIdle
=
mNewActivities;
mNewActivities
=
r;
if
(localLOGV)
Slog.v(TAG,
"Scheduling
idle
handler
for
"
+
r);
Looper.myQueue().addIdleHandler(new
Idler());
}handleResumeActivity的过程自然也不是本文的重点,重点关注最后一句话Looper.myQueue().addIdleHandler(newIdler()),这句话什么作用呢?这里就要重点看下addIdleHandler方法到底添加了什么东西。MessageQueue.java
public
void
addIdleHandler(@NonNull
IdleHandler
handler)
{
if
(handler
==
null)
{
throw
new
NullPointerException("Can't
add
a
null
IdleHandler");
}
synchronized
(this)
{
mIdleHandlers.add(handler);
}
}很简单的代码,只是将IdleHandler添加到mIdleHandlers的列表中,那么什么时候会使用这个对象呢。查看了mIdleHandlers的调用地方。发现除了添加和删除IdleHandler对象以外只有MessageQueue的next方法里面有调用的地方。
Message
next()
{
//
Return
here
if
the
message
loop
has
already
quit
and
been
disposed.
//
This
can
happen
if
the
application
tries
to
restart
a
looper
after
quit
//
which
is
not
supported.
final
long
ptr
=
mPtr;
if
(ptr
==
0)
{
return
null;
}
int
pendingIdleHandlerCount
=
-1;
//
-1
only
during
first
iteration
int
nextPollTimeoutMillis
=
0;
for
(;;)
{
if
(nextPollTimeoutMillis
!=
0)
{
Binder.flushPendingCommands();
}
nativePollOnce(ptr,
nextPollTimeoutMillis);
synchronized
(this)
{
//
获取当前时间
final
long
now
=
SystemClock.uptimeMillis();
Message
prevMsg
=
null;
Message
msg
=
mMessages;
if
(msg
!=
null
&&
msg.target
==
null)
{
//target为空的情况下,才会进入此条件
//
Stalled
by
a
barrier.
Find
the
next
asynchronous
message
in
the
queue.
do
{
prevMsg
=
msg;
msg
=
msg.next;
//遍历messageQueue里面的所有消息,如果存在message是异步的,那么返回给调用者调用。如果不存在异步消息,那么等遍历完退出循环
}
while
(msg
!=
null
&&
!msg.isAsynchronous());
}
if
(msg
!=
null)
{
if
(now
<
msg.when)
{
//when主要是postDelay设置的,通过postDelay可以延迟执行,如果当前时间小于when,那么该消息不会被执行。
nextPollTimeoutMillis
=
(int)
Math.min(msg.when
-
now,
Integer.MAX_VALUE);
}
else
{
//
Got
a
message.
mBlocked
=
false;
if
(prevMsg
!=
null)
{
prevMsg.next
=
msg.next;
}
else
{
mMessages
=
msg.next;
}
msg.next
=
null;
if
(DEBUG)
Log.v(TAG,
"Returning
message:
"
+
msg);
msg.markInUse();
return
msg;
}
}
else
{
//
No
more
messages.
nextPollTimeoutMillis
=
-1;
}
//
Process
the
quit
message
now
that
all
pending
messages
have
been
handled.
if
(mQuitting)
{
dispose();
return
null;
}
//
If
first
time
idle,
then
get
the
number
of
idlers
to
run.
//
Idle
handles
only
run
if
the
queue
is
empty
or
if
the
first
message
//
in
the
queue
(possibly
a
barrier)
is
due
to
be
handled
in
the
future.
if
(pendingIdleHandlerCount
<
0
&&
(mMessages
==
null
||
now
<
mMessages.when))
{
pendingIdleHandlerCount
=
mIdleHandlers.size();
}
if
(pendingIdleHandlerCount
<=
0)
{
//
No
idle
handlers
to
run.
Loop
and
wait
some
more.
mBlocked
=
true;
continue;
}
if
(mPendingIdleHandlers
==
null)
{
mPendingIdleHandlers
=
new
IdleHandler[Math.max(pendingIdleHandlerCount,
4)];
}
mPendingIdleHandlers
=
mIdleHandlers.toArray(mPendingIdleHandlers);
}
//
Run
the
idle
handlers.
//
We
only
ever
reach
th
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025买卖合同范本(宅基地)
- 科技赋能下的宠物托儿所财务风险识别与防范
- 课题申报参考:量子信息产业劳动力教育需求调查与教育资源开发
- 课题申报参考:劳动力流动、代际居住分离与农村养老服务整合研究
- 知识经济时代的终身学习与发展
- 2025年华师大新版七年级生物下册月考试卷含答案
- 2025年湘教新版九年级历史下册阶段测试试卷含答案
- 2025年浙教版必修1历史下册月考试卷
- 2025年人教A新版七年级科学下册阶段测试试卷含答案
- 2025年苏教新版九年级历史下册月考试卷
- 【语文】第23课《“蛟龙”探海》课件 2024-2025学年统编版语文七年级下册
- 加强教师队伍建设教师领域学习二十届三中全会精神专题课
- 2024-2025学年人教版数学七年级上册期末复习卷(含答案)
- 2024年决战行测5000题言语理解与表达(培优b卷)
- 四年级数学上册人教版24秋《小学学霸单元期末标准卷》考前专项冲刺训练
- 2025年慢性阻塞性肺疾病全球创议GOLD指南修订解读课件
- (完整版)减数分裂课件
- 银行办公大楼物业服务投标方案投标文件(技术方案)
- 第01讲 直线的方程(九大题型)(练习)
- 微粒贷逾期还款协议书范本
- 人教版七年级上册数学全册课时练习带答案
评论
0/150
提交评论