zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

详细介绍Android中回调函数机制

Android 函数 详细 介绍 机制 回调
2023-06-13 09:15:15 时间

提示:在阅读本文章之前,请确保您对Touch事件的分发机制有一定的了解

在Android的学习过程中经常会听到或者见到“回调”这个词,那么什么是回调呢?所谓的回调函数就是:在A类中定义了一个方法,这个方法中用到了一个接口和该接口中的抽象方法,但是抽象方法没有具体的实现,需要B类去实现,B类实现该方法后,它本身不会去调用该方法,而是传递给A类,供A类去调用,这种机制就称为回调。

下面我们拿具体的Button的点击事件进行模拟分析:

首先,在View类中我们能找到setOnClickListener(OnClickListenerl)方法:

复制代码代码如下:


publicvoidsetOnClickListener(OnClickListenerl){

    if(!isClickable()){

        setClickable(true);

    }

    getListenerInfo().mOnClickListener=l;

}

可以看到,在该方法中将OnClickListener赋值给了mOnClickListener,那么我们继续向下找,会看到在performClick()方法中执行了我们实现的onClick()方法。

复制代码代码如下:


publicbooleanperformClick(){

    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

    ListenerInfoli=mListenerInfo;

    if(li!=null&&li.mOnClickListener!=null){

        playSoundEffect(SoundEffectConstants.CLICK);

        li.mOnClickListener.onClick(this);

        returntrue;

    }

    returnfalse;

}

由此我们可以清楚的看不到,在父类中我们要用到onClick()方法,但是父类却没有去实现该方法,而是定义了一个方法setOnClickListener(OnClickListenerl),如果子类想要自己能够响应点击事件,则它就必须重写父类的该方法,实现OnClickListener接口和它的onClick()方法。在子类实现该接口和方法后,将其通过参数传递给父类,在父类中执行onClick()方法。

那么,为什么会在父类中执行到该方法呢,这就要说到Android中的另一个重要的机制——触摸事件的传递机制。

我们知道,只要我们的手指触摸到手机屏幕,就一定会执行dispatchTouchEvent(MotionEventevent)方法,接下来我们就看一下dispatchTouchEvent方法中都有哪些内容:

复制代码代码如下:
publicbooleandispatchTouchEvent(MotionEventevent){

       if(mInputEventConsistencyVerifier!=null){

           mInputEventConsistencyVerifier.onTouchEvent(event,0);

       }

 

       if(onFilterTouchEventForSecurity(event)){

           //noinspectionSimplifiableIfStatement

           ListenerInfoli=mListenerInfo;

           if(li!=null&&li.mOnTouchListener!=null

                   &&(mViewFlags&ENABLED_MASK)==ENABLED

                   &&li.mOnTouchListener.onTouch(this,event)){

               returntrue;

           }

 

           if(onTouchEvent(event)){

               returntrue;

           }

       }

 

       if(mInputEventConsistencyVerifier!=null){

           mInputEventConsistencyVerifier.onUnhandledEvent(event,0);

       }

       returnfalse;

}

这里我们不细讲Touch事件的分发机制,因为网上有哥们已经讲的很清楚了。请参看篇首提供的链接。

我们看一下第17行,由于我们没有实现OnTouchListener接口,而onTouch()方法的默认返回值为false,所以第一个if语句中的代码不会被执行到,进入第二个if语句中,执行了onTouchEvent()方法。那么我们再来看一下该方法:

复制代码代码如下:
publicbooleanonTouchEvent(MotionEventevent){

       finalintviewFlags=mViewFlags;

 

       if((viewFlags&ENABLED_MASK)==DISABLED){

           if(event.getAction()==MotionEvent.ACTION_UP

                    &&(mPrivateFlags&PFLAG_PRESSED)!=0){

               setPressed(false);

           }

           //Adisabledviewthatisclickablestillconsumesthetouch

           //events,itjustdoesn"trespondtothem.

           return(((viewFlags&CLICKABLE)==CLICKABLE||

                   (viewFlags&LONG_CLICKABLE)==LONG_CLICKABLE));

       }

 

       if(mTouchDelegate!=null){

           if(mTouchDelegate.onTouchEvent(event)){

               returntrue;

           }

       }

 

       if(((viewFlags&CLICKABLE)==CLICKABLE||

               (viewFlags&LONG_CLICKABLE)==LONG_CLICKABLE)){

           switch(event.getAction()){

               caseMotionEvent.ACTION_UP:

                   booleanprepressed=(mPrivateFlags&PFLAG_PREPRESSED)!=0;

                   if((mPrivateFlags&PFLAG_PRESSED)!=0||prepressed){

                       //takefocusifwedon"thaveitalreadyandweshouldin

                       //touchmode.

                       booleanfocusTaken=false;

                       if(isFocusable()&&isFocusableInTouchMode()&&!isFocused()){

                           focusTaken=requestFocus();

                       }

 

                       if(prepressed){

                           //Thebuttonisbeingreleasedbeforeweactually

                           //showeditaspressed. Makeitshowthepressed

                           //statenow(beforeschedulingtheclick)toensure

                           //theuserseesit.

                           setPressed(true);

                      }

 

                       if(!mHasPerformedLongPress){

                           //Thisisatap,soremovethelongpresscheck

                           removeLongPressCallback();

 

                           //Onlyperformtakeclickactionsifwewereinthepressedstate

                           if(!focusTaken){

                               //UseaRunnableandpostthisratherthancalling

                               //performClickdirectly.Thisletsothervisualstate

                               //oftheviewupdatebeforeclickactionsstart.

                               if(mPerformClick==null){

                                   mPerformClick=newPerformClick();

                               }

                               if(!post(mPerformClick)){

                                   performClick();

                               }

                           }

                       }

 

                       if(mUnsetPressedState==null){

                           mUnsetPressedState=newUnsetPressedState();

                       }

 

                       if(prepressed){

                           postDelayed(mUnsetPressedState,

                                   ViewConfiguration.getPressedStateDuration());

                       }elseif(!post(mUnsetPressedState)){

                           //Ifthepostfailed,unpressrightnow

                           mUnsetPressedState.run();

                       }

                       removeTapCallback();

                   }

                   break;

 

               caseMotionEvent.ACTION_DOWN:

                   mHasPerformedLongPress=false;

 

                   if(performButtonActionOnTouchDown(event)){

                       break;

                   }

 

                   //Walkupthehierarchytodetermineifwe"reinsideascrollingcontainer.

                   booleanisInScrollingContainer=isInScrollingContainer();

 

                   //Forviewsinsideascrollingcontainer,delaythepressedfeedbackfor

                   //ashortperiodincasethisisascroll.

                   if(isInScrollingContainer){

                       mPrivateFlags|=PFLAG_PREPRESSED;

                       if(mPendingCheckForTap==null){

                           mPendingCheckForTap=newCheckForTap();

                       }

                       postDelayed(mPendingCheckForTap,

                                  ViewConfiguration.getTapTimeout());

                   }else{

                       //Notinsideascrollingcontainer,soshowthefeedbackrightaway

                       setPressed(true);

                       checkForLongClick(0);

                   }

                   break;

 

               caseMotionEvent.ACTION_CANCEL:

                   setPressed(false);

                   removeTapCallback();

                   removeLongPressCallback();

                   break;

 

               caseMotionEvent.ACTION_MOVE:

                   finalintx=(int)event.getX();

                   finalinty=(int)event.getY();

 

                   //Belenientaboutmovingoutsideofbuttons

                   if(!pointInView(x,y,mTouchSlop)){

                       //Outsidebutton

                       removeTapCallback();

                       if((mPrivateFlags&PFLAG_PRESSED)!=0){

                           //Removeanyfuturelongpress/tapchecks

                           removeLongPressCallback();

 

                           setPressed(false);

                       }

                   }

                   break;

           }

           returntrue;

       }

 

       returnfalse;

   }

代码太长,我们只看重点,在ACTION_UP这个case当中,我们找到了关键的代码(第109行):performClick()。

至此,我们已经基本搞清楚了回调机制的整个过程。