Android Launcher解析和批改9——Launcher启动APP流程

来源:互联网 发布:网络安全教育黑板报 编辑:程序博客网 时间:2024/04/30 04:34

底本想解析AppsCustomizePagedView类,不过今天忽然接到一个姑且任务。客户反馈说机械界面的图标很难点击启动法度,经常点击了没有反响,Boss说要优先解决这题目。没办法,只能看看是怎么回事。今天解析一下Launcher启动APP的过程。从用户点击到法度启动的流程,下面针对WorkSpace上的快捷图标点击启动流程进行解析。(若是分不清WorkSpace是什么或者不知道快捷体式格式和其他图标差别,请看我前面的Launcher解析文章)


PS:新建的QQ群,有爱好可以参加一路评论辩论:Android群:322599434


  下面我们先看看Launcher启动APP的可能流程:






(鉴于很多转载文章的人把作者信息都删除了,只能在上参加水印,不会给大师浏览造成影响)


  上方就是手指触摸屏幕开端,到点击响应的流程。Launcher里面因为有滑动、拖曳、点击等手势操纵,所以区分了很多流程断定。最后调用Launcher.java里面的onClick()办法响应点击,启动法度。下面我们针对关键流程做解析。


 


1、WorkSpace触摸


  前面我们解析Launcher的设备文件时就说过,Launcher外面的界面首要就是经由过程WorkSpace来显示的。它是一个ViewGroup的自定义类。下面我们先看看WorkSpace的onInterceptTouchEvent做了什么。



//Edited by mythou
//http://www.cnblogs.com/mythou/

   public boolean onInterceptTouchEvent(MotionEvent ev)
{
if(OWL_DEBUG) Log.d(OWL, "onInterceptTouchEvent enter");
     //对ACTION_DOWN和ACTION_UP做一些标识表记标帜处理惩罚。
switch (ev.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
mXDown = ev.getX();
mYDown = ev.getY();
break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
if (mTouchState == TOUCH_STATE_REST)
{
final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);
if (!currentPage.lastDownOnOccupiedCell())
{
onWallpaperTap(ev);
}
}
}

if(OWL_DEBUG) Log.d(OWL, "onInterceptTouchEvent call super InterceptTouch");
//调用父类的onInterceptTouchEvent,这里是调用了SmoothPagedView
return super.onInterceptTouchEvent(ev);
}


   在WorkSpace里面并没有阻碍消息,主如果调用父类的办法,也就是PagedView的onInterceptTouchEvent()办法。因为WorkSpace的直接父类SmoothPagedView也是持续了PagedView类,有关PagedView的onInterceptTouchEvent()办法,我在前面的文章已经解析过。这里不做多说,不懂得的伴侣可以看看(点这里)。


 


 2、CellLayout的onInterceptTouchEvent()办法


CellLayout也是一个持续了ViewGroup的类,首要用来显示桌面控件。刚开端解析Launcher的时辰,我们解析设备文件的时辰也说过WorkSpace就是由5个CellLayout构成的。是以我们点击WorkSpace里面图标的时辰,天然会调用CellLayout里面的器材。CellLayout里面的onInterceptTouchEvent()做的工作并不久不多:




//Edited by mythou
//http://www.cnblogs.com/mythou/

  public boolean onInterceptTouchEvent(MotionEvent ev) 
{
if(OWL_DEBUG) Log.d(OWL, "onInterceptTouchEvent enter");

final int action = ev.getAction();

if (action == MotionEvent.ACTION_DOWN)
{
       //清除所有触摸标识表记标帜
clearTagCellInfo();
}
     //mInterceptTouchListener是WorkSpace的onTouch办法回调,下面会解析
    //把握这点很首要,因为onInterceptTouchEvent的返回值直接决意了触摸事务的传递标的目标 mythou
if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev))
{
//截断Touch传输,直接处理惩罚 ,返回true会直接调用onTouchEvent处理惩罚。 mythou
if(OWL_DEBUG) Log.d(OWL, "onInterceptTouchEvent return true Intercept msg");
return true;
}

if (action == MotionEvent.ACTION_DOWN)
{
setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
}

if(OWL_DEBUG) Log.d(OWL, "onInterceptTouchEvent return false");
     //重视这里返回的是false ,onInterceptTouchEvent的返回值决意了触摸事务的传递体式格式。mythou
return false;
}


  这里须要重视的是onInterceptTouchEvent()的返回值,若是是返回true,触摸消息会直接被CellLayout的onTouchEvent()处理惩罚,一般点击启动法度返回的都是false,因为消息最后是TextView处理惩罚(workspace上的快捷体式格式都是TextView的子类)。Android的触摸消息传递机制和消息阻碍机制,须要好好懂得好才干熟悉打听Launcher的触摸事务处理惩罚。因为小我感觉Launcher里面事务处理惩罚层次还是斗劲多,若是对Android的事务传递机制懂得不深,就很难懂得Launcher的事务处理惩罚。若是对这方面不懂得的伴侣,可以查查网上相干材料。后面有空我也会写一篇深切解析Android触摸事务处理惩罚的文章。


 


 3、WorkSpace的onTouch()事务


WorkSpace里面还处理惩罚了onTouch事务,这里的onTouch事务是因为WorkSpace应用了View.OnTouchListener接口,所以实现了onTouch事务的回调。



//Edited by mythou
//http://www.cnblogs.com/mythou/

public boolean onTouch(View v, MotionEvent event) 
{
  return (isSmall() || !isFinishedSwitchingState());
}


  onTouch里面其实没做什么工作,就是按照两个办法返回值,断定onTouch是返回false还是返回true,返回值是什么决意了触摸事务的传递标的目标,上方已经说过了。这里的onTouch是给WorkSpace里面的装载的View应用的,也就是CellLayout。我们可以看看每次调用WorkSpace的onChildViewAdded()办法,会设置CellLayout的onTouch器。



//Edited by mythou
//http://www.cnblogs.com/mythou/

public void onChildViewAdded(View parent, View child) { if (!(child instanceof CellLayout)) 
{
   throw new IllegalArgumentException("A Workspace can only have CellLayout children."); }
   CellLayout cl = ((CellLayout) child);
   //设置onTouch的器,CellLayout的onInterceptTouchEvent()办按照onTouch器断定是否须要阻碍onTouch事务。
cl.setOnInterceptTouchListener(this);
cl.setClickable(true);
cl.setContentDescription(getContext().getString(
R.string.workspace_description_format, getChildCount()));
}


上方第二点CellLayout的onInterceptTouchEvent()办法的解析里面,return ture的时辰,断定的根据mInterceptTouchListener和mInterceptTouchListener.onTouch()办法的返回值就是从这里设置的,他们也就是调用了WorkSpace的onTouch办法。


 


4、BubbleTextView


   BubbleTextView是持续了TextView的子类,在Launcher里面所有的WorkSpace的快捷体式格式都是应用BubbleTextView绘画的,它的感化相当于一个按钮。在解析BubbleTextView的触摸响应前,我们先看看Launcher里面如何创建快捷体式格式。前面的文章我解析过Launcher加载界面数据的流程,不过没有细心解析如何创建相干对象,下面我们先看看WorkSpace的快捷体式格式如何创建:


 



//Edited by mythou
//http://www.cnblogs.com/mythou/

View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) 
{
  BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
  favorite.applyFromShortcutInfo(info, mIconCache);
  //重视这里设置了onClickListener OWL
favorite.setOnClickListener(this);
return favorite;
}


 


上方就是创建快捷体式格式的办法,这里面我们须要重视的是,BubbleTextView调用了SetOnClickListener()办法,设置点击器。器的回调函数就是Launcher.java类里面的onCLick办法。因为Launcher类持续了View.OnClickListener接口,当然Launcher里面还持续了其他的接口,例如触摸、长按的Listener。下面我们先看看BUbbleTextView的onTouchEvent办法:



//Edited by mythou
//http://www.cnblogs.com/mythou/

   public boolean onTouchEvent(MotionEvent event) 
  {
// 调用TextView的onToucEvent办法,主如果获取返回值,这个返回值感化很大,会响应点击事务的回调。
// 可以把这返回值打印出来看看。当点击启动法度时,这里必然会返回true。

     //原因上方已经说了很多次,这里不再烦琐 OWL  
boolean result = super.onTouchEvent(event);

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//下面这里主如果按照触摸状况值,做快捷体式格式的状况显示,例如是否须要显示按下状况。
if (mPressedOrFocusedBackground == null) {
mPressedOrFocusedBackground = createGlowingOutline(
mTempCanvas, mPressedGlowColor, mPressedOutlineColor);
}
if (isPressed())
         {
mDidInvalidateForPressedState = true;
setCellLayoutPressedOrFocusedIcon();
} else {
mDidInvalidateForPressedState = false;
}

mLongPressHelper.postCheckForLongPress();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (!isPressed()) {
mPressedOrFocusedBackground = null;
}
          //这里按照状况断定是否作废长按的触摸
mLongPressHelper.cancelLongPress();
break;
}
     //返回值十分首要,直接影响是否会掉用onCLick办法。
return result;
}


上方就是BubbleTextView的onTouchEvent的办法,上方夸大很多次返回值,这里若是是点击流程,会返回true。然后履行onClick办法。


 


5、onClick()办法


  最后点击会调用Launcher里面的onClick办法,不管你是点击快捷体式格式、文件夹、还是AllAPP的按钮,都是从这里响应回调。



//Edited by mythou
//http://www.cnblogs.com/mythou/

  public void onClick(View v) {
    //..........

Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
//这里点击打开我们上方解析的快捷体式格式图标。打开的体式格式也是调用startActivity,
       // 只是这里调用的startActivitySafely对startActivity进行了封装 mythou
      final Intent intent = ((ShortcutInfo) tag).intent;
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1],
pos[0] + v.getWidth(), pos[1] + v.getHeight()));

boolean success = startActivitySafely(v, intent, tag);

if (success && v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v;
mWaitingForResume.setStayPressed(true);
}
     //文件夹点击响应
} else if (tag instanceof FolderInfo) {
if (v instanceof FolderIcon) {
FolderIcon fi = (FolderIcon) v;
handleFolderClick(fi);
}
     //AllAPP按钮点击响应
} else if (v == mAllAppsButton) {
if (isAllAppsVisible()) {
showWorkspace(true);
} else {
onClickAllAppsButton(v);
}
}
}


  上方给出了最后点击启动快捷体式格式图标的体式格式,最后调用的也是startActivity,不过Launcher对它进行了封装,里面参加异常处理惩罚,包含是否启动成功等操纵。并且里面分隔了startActivity和startActivityForResult两种体式格式。然则最后启动的时辰,还是调用了我们日常平凡应用的启动Activity的办法。下面给出我参加打印消息后的代码流程跟踪截图。

 


 


6、总结


  Launcher里面有关点击启动法度的办法流程就是上述所说的那样,当然,里面有些办法断定履行了很多办法,这里不做具体解析,又爱好的伴侣可以跟我一样参加一些打印消息,跟踪Log解析代码流程。里面还有一个相当首要的项目组就是如何区分是页面滑动还是按钮点击。文章开首说的题目就是因为把点击事务断定为页面滑动,导致经常点击按钮的时辰履行了滑动页面的操纵,导致用户感觉点击按钮都没反响。我最后的批改办法是批改了断定是否进行页面滑动的办法,解决了该题目。


  今天就说到这里,这个流程解析小我感觉还是有点错杂,因为涉及了Android触摸事务的传递体式格式,若是不懂得这个,无法懂得Launcher是如何处理惩罚这些事务的

 

0 0
原创粉丝点击