版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/qq_30552095/article/details/87932081
最近有一個(gè)需求,
現(xiàn)象:播放音樂(lè)時(shí),點(diǎn)擊多任務(wù)中的“全部清除”按鈕,音樂(lè)未停止;
預(yù)期:音樂(lè)停止。
于是去看看這個(gè)按鈕的點(diǎn)擊事件,本來(lái)以為這就是一個(gè)簡(jiǎn)單的onclick事件,可是并沒(méi)有這么簡(jiǎn)單,首先找到這個(gè)按鈕:
com.android.systemui.recents.views.RecentsView中的mStackActionButton,這個(gè)就是按鈕的對(duì)象了,可是這個(gè)按鈕并沒(méi)有找到onclick事件,所以猜測(cè)是不是在onTouchEvent中處理的
com.android.systemui.recents.views.RecentsView -> onTouchEvent()
@Override
public boolean onTouchEvent(MotionEvent ev) {
return mTouchHandler.onTouchEvent(ev);
}
繼續(xù)跟,RecentsViewTouchHandler這個(gè)類很像是專門處理recentsView的touch事件的
com.android.systemui.recents.views.RecentsViewTouchHandler ->onTouchEvent();
public boolean onTouchEvent(MotionEvent ev) {
handleTouchEvent(ev);
if (ev.getAction() == MotionEvent.ACTION_UP && mRv.getStack().getStackTaskCount() == 0) {
EventBus.getDefault().send(new HideRecentsEvent(false, true));
}
return true;
}
在com.android.systemui.recents.views.RecentsViewTouchHandler -> handleTouchEvent(ev)
中的ACTION_UP事件中找到了
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
if (mRv.getStackActionButton().isPressed() && isWithinStackActionButton(evX, evY)) {
EventBus.getDefault().send(new DismissAllTaskViewsEvent());
consumed = true;
}
......
}
這里就是處理點(diǎn)擊事件的地方了,繼續(xù)跟到EventBus中
com.android.systemui.recents.events.EventBus -> send();
public void send(Event event) {
......
queueEvent(event);
}
com.android.systemui.recents.events.EventBus -> queueEvent();
private void queueEvent(final Event event) {
ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass());
if (eventHandlers == null) {
// This is just an optimization to return early if there are no handlers. However, we
// should still ensure that we call pre/post dispatch callbacks so that AnimatedEvents
// are still cleaned up correctly if a listener has not been registered to handle them
event.onPreDispatch();
event.onPostDispatch();
return;
}
// Prepare this event
boolean hasPostedEvent = false;
event.onPreDispatch();
// We need to clone the list in case a subscriber unregisters itself during traversal
// TODO: Investigate whether we can skip the object creation here
eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone();
int eventHandlerCount = eventHandlers.size();
for (int i = 0; i < eventHandlerCount; i++) {
final EventHandler eventHandler = eventHandlers.get(i);
if (eventHandler.subscriber.getReference() != null) {
if (event.requiresPost) {
mHandler.post(new Runnable() {
@Override
public void run() {
processEvent(eventHandler, event);
}
});
hasPostedEvent = true;
} else {
processEvent(eventHandler, event);
}
}
}
// Clean up after this event, deferring until all subscribers have been called
if (hasPostedEvent) {
mHandler.post(new Runnable() {
@Override
public void run() {
event.onPostDispatch();
}
});
} else {
event.onPostDispatch();
}
}
通過(guò)打斷點(diǎn)發(fā)現(xiàn)走的是 processEvent(eventHandler, event);
com.android.systemui.recents.events.EventBus -> processEvent();
private void processEvent(final EventHandler eventHandler, final Event event) {
// Skip if the event was already cancelled
if (event.cancelled) {
if (event.trace || DEBUG_TRACE_ALL) {
logWithPid("Event dispatch cancelled");
}
return;
}
try {
if (event.trace || DEBUG_TRACE_ALL) {
logWithPid(" -> " + eventHandler.toString());
}
Object sub = eventHandler.subscriber.getReference();
if (sub != null) {
long t1 = 0;
if (DEBUG_TRACE_ALL) {
t1 = SystemClock.currentTimeMicro();
}
eventHandler.method.invoke(sub, event);
if (DEBUG_TRACE_ALL) {
long duration = (SystemClock.currentTimeMicro() - t1);
mCallDurationMicros += duration;
mCallCount++;
logWithPid(eventHandler.method.toString() + " duration: " + duration +
" microseconds, avg: " + (mCallDurationMicros / mCallCount));
}
} else {
Log.e(TAG, "Failed to deliver event to null subscriber");
}
} catch (IllegalAccessException e) {
Log.e(TAG, "Failed to invoke method", e.getCause());
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
}
}
這里調(diào)用的反射,仍然是通過(guò)斷點(diǎn),發(fā)現(xiàn)走的是eventHandler.method.invoke(sub, event);
sub是com.android.systemui.recents.views.TaskStackView
event是com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent
在TaskStackView中找到這個(gè)方法
com.android.systemui.recents.views.TaskStackView -> onBusEvent();
public final void onBusEvent(final DismissAllTaskViewsEvent event) {
// Keep track of the tasks which will have their data removed
ArrayList<Task> tasks = new ArrayList<>(mStack.getStackTasks());
mAnimationHelper.startDeleteAllTasksAnimation(
getTaskViews(), useGridLayout(), event.getAnimationTrigger());
event.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
// Announce for accessibility
announceForAccessibility(getContext().getString(
R.string.accessibility_recents_all_items_dismissed));
// Remove all tasks and delete the task data for all tasks
mStack.removeAllTasks(true /* notifyStackChanges */);
for (int i = tasks.size() - 1; i >= 0; i--) {
EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
}
MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS_ALL);
}
});
}
找到關(guān)鍵的一句代碼EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
這里又走到了EventBus中,同樣的在
com.android.systemui.recents.events.EventBus -> processEvent();
這個(gè)方法中的eventHandler.method.invoke(sub, event);
sub是com.android.systemui.recents.RecentsActivity
event是com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
找到這個(gè)方法
com.android.systemui.recents.RecentsActivity -> onBusEvent();
public final void onBusEvent(DeleteTaskDataEvent event) {
// Remove any stored data from the loader
RecentsTaskLoader loader = Recents.getTaskLoader();
loader.deleteTaskData(event.task, false);
// Remove the task from activity manager
SystemServicesProxy ssp = Recents.getSystemServices();
ssp.removeTask(event.task.key.id);
}
跟到SystemServicesProxy中看看
com.android.systemui.recents.misc.SystemServicesProxy -> removeTask();
public void removeTask(final int taskId) {
if (mAm == null) return;
if (RecentsDebugFlags.Static.EnableMockTasks) return;
// Remove the task.
mUiOffloadThread.submit(() -> {
mAm.removeTask(taskId);
});
}
這個(gè)就比較明確了,就是調(diào)用了ActivityManager中的removeTask方法。
由此可見(jiàn),recents中的task都是放在了ActivityManger中的。
--------------------------------------------------------------------分割線-------------------------------------------------------------------
回到我的需求,需要在移除task的時(shí)候,將音樂(lè)停止,那就在這個(gè)地方將這個(gè)package停止
增加方法
com.android.systemui.recents.misc.SystemServicesProxy
public void removeTask(final Task.TaskKey key) {
removeTask(key.id);
if (mAm == null || key.getComponent() == null || TextUtils.isEmpty(key.getComponent().getPackageName())) {
return;
}
mAm.forceStopPackage(key.getComponent().getPackageName());
}
在com.android.systemui.recents.RecentsActivity -> onBusEvent();中調(diào)用新增的方法
public final void onBusEvent(DeleteTaskDataEvent event) {
// Remove any stored data from the loader
RecentsTaskLoader loader = Recents.getTaskLoader();
loader.deleteTaskData(event.task, false);
// Remove the task from activity manager
SystemServicesProxy ssp = Recents.getSystemServices();
// ssp.removeTask(event.task.key.id);
ssp.removeTask(event.task.key);
}
————————————————
版權(quán)聲明:本文為CSDN博主「Shawn」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_30552095/article/details/87932081