优雅的回调

 

看看Android 原生的关于回调函数的用法:

一,旋转角度变化的回调:

  1 /**
  2  * Helper class for receiving notifications from the SensorManager when
  3  * the orientation of the device has changed.
  4  */
  5 public abstract class OrientationEventListener {
  6     private static final String TAG = "OrientationEventListener";
  7     private static final boolean DEBUG = false;
  8     private static final boolean localLOGV = false;
  9     private int mOrientation = ORIENTATION_UNKNOWN;
 10     private SensorManager mSensorManager;
 11     private boolean mEnabled = false;
 12     private int mRate;
 13     private Sensor mSensor;
 14     private SensorEventListener mSensorEventListener;
 15     private OrientationListener mOldListener;
 16     
 17     /**
 18      * Returned from onOrientationChanged when the device orientation cannot be determined
 19      * (typically when the device is in a close to flat position).
 20      *
 21      *  @see #onOrientationChanged
 22      */
 23     public static final int ORIENTATION_UNKNOWN = -1;
 24 
 25     /**
 26      * Creates a new OrientationEventListener.
 27      * 
 28      * @param context for the OrientationEventListener.
 29      */
 30     public OrientationEventListener(Context context) {
 31         this(context, SensorManager.SENSOR_DELAY_NORMAL);
 32     }
 33     
 34     /**
 35      * Creates a new OrientationEventListener.
 36      * 
 37      * @param context for the OrientationEventListener.
 38      * @param rate at which sensor events are processed (see also
 39      * {@link android.hardware.SensorManager SensorManager}). Use the default
 40      * value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL 
 41      * SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
 42      */
 43     public OrientationEventListener(Context context, int rate) {
 44         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
 45         mRate = rate;
 46         mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
 47         if (mSensor != null) {
 48             // Create listener only if sensors do exist
 49             mSensorEventListener = new SensorEventListenerImpl();
 50         }
 51     }
 52     
 53     void registerListener(OrientationListener lis) {
 54         mOldListener = lis;
 55     }
 56 
 57     /**
 58      * Enables the OrientationEventListener so it will monitor the sensor and call
 59      * {@link #onOrientationChanged} when the device orientation changes.
 60      */
 61     public void enable() {
 62         if (mSensor == null) {
 63             Log.w(TAG, "Cannot detect sensors. Not enabled");
 64             return;
 65         }
 66         if (mEnabled == false) {
 67             if (localLOGV) Log.d(TAG, "OrientationEventListener enabled");
 68             mSensorManager.registerListener(mSensorEventListener, mSensor, mRate);
 69             mEnabled = true;
 70         }
 71     }
 72 
 73     /**
 74      * Disables the OrientationEventListener.
 75      */
 76     public void disable() {
 77         if (mSensor == null) {
 78             Log.w(TAG, "Cannot detect sensors. Invalid disable");
 79             return;
 80         }
 81         if (mEnabled == true) {
 82             if (localLOGV) Log.d(TAG, "OrientationEventListener disabled");
 83             mSensorManager.unregisterListener(mSensorEventListener);
 84             mEnabled = false;
 85         }
 86     }
 87 
 88     class SensorEventListenerImpl implements SensorEventListener {
 89         private static final int _DATA_X = 0;
 90         private static final int _DATA_Y = 1;
 91         private static final int _DATA_Z = 2;
 92         
 93         public void onSensorChanged(SensorEvent event) {
 94             float[] values = event.values;
 95             int orientation = ORIENTATION_UNKNOWN;
 96             float X = -values[_DATA_X];
 97             float Y = -values[_DATA_Y];
 98             float Z = -values[_DATA_Z];        
 99             float magnitude = X*X + Y*Y;
100             // Don't trust the angle if the magnitude is small compared to the y value
101             if (magnitude * 4 >= Z*Z) {
102                 float OneEightyOverPi = 57.29577957855f;
103                 float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
104                 orientation = 90 - (int)Math.round(angle);
105                 // normalize to 0 - 359 range
106                 while (orientation >= 360) {
107                     orientation -= 360;
108                 } 
109                 while (orientation < 0) {
110                     orientation += 360;
111                 }
112             }
113             if (mOldListener != null) {
114                 mOldListener.onSensorChanged(Sensor.TYPE_ACCELEROMETER, event.values);
115             }
116             if (orientation != mOrientation) {
117                 mOrientation = orientation;
118                 onOrientationChanged(orientation);
119             }
120         }
121 
122         public void onAccuracyChanged(Sensor sensor, int accuracy) {
123 
124         }
125     }
126     
127     /*
128      * Returns true if sensor is enabled and false otherwise
129      */
130     public boolean canDetectOrientation() {
131         return mSensor != null;
132     }
133 
134     /**
135      * Called when the orientation of the device has changed.
136      * orientation parameter is in degrees, ranging from 0 to 359.
137      * orientation is 0 degrees when the device is oriented in its natural position,
138      * 90 degrees when its left side is at the top, 180 degrees when it is upside down, 
139      * and 270 degrees when its right side is to the top.
140      * {@link #ORIENTATION_UNKNOWN} is returned when the device is close to flat
141      * and the orientation cannot be determined.
142      *
143      * @param orientation The new orientation of the device.
144      *
145      *  @see #ORIENTATION_UNKNOWN
146      */
147     abstract public void onOrientationChanged(int orientation);
148 }

典型用法:

public class DemoActivity extends Activity{
    
    private MyOrientationEventListener mOrientationListener;
    
    private class MyOrientationEventListener extends OrientationEventListener {
        public MyOrientationEventListener(Context context) {super(context);}

        @Override
        public void onOrientationChanged(int orientation) {
            android.util.Log.i(TAG, "onOrientationChanged: "+orientation);
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mOrientationListener = new MyOrientationEventListener(this);
    }

    @Override
    public void onResume() {
        mOrientationListener.enable();
    }

    @Override
    public void onPause() {
        mOrientationListener.disable();
    }
}

 

主要逻辑如下:

1. 构造函数中new SensorEventListenerImpl类型对象mSensorEventListener

     */
    public OrientationEventListener(Context context, int rate) {
        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
        mRate = rate;
        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (mSensor != null) {
            // Create listener only if sensors do exist
            mSensorEventListener = new SensorEventListenerImpl();
        }
    }
    

2. SensorEventListenerImpl的回调函数根据传感器的变化, 计算出一个角度, 传给抽象函数onOrientationChanged(orientation),该抽象函数就是继承类时必须要重写的

  public void onSensorChanged(SensorEvent event) {
            ......
            if (orientation != mOrientation) {
                mOrientation = orientation;
                onOrientationChanged(orientation);
            }
        }

 二,手势变化的回调:

public class GestureDetector {
    /**
     * The listener that is used to notify when gestures occur.
     * If you want to listen for all the different gestures then implement
     * this interface. If you only want to listen for a subset it might
     * be easier to extend {@link SimpleOnGestureListener}.
     */
    public interface OnGestureListener {
   
        boolean onDown(MotionEvent e);
   
        void onShowPress(MotionEvent e);
      
        boolean onSingleTapUp(MotionEvent e);
       
        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);

        void onLongPress(MotionEvent e);
      
        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
    }

    /**
     * The listener that is used to notify when a double-tap or a confirmed
     * single-tap occur.
     */
    public interface OnDoubleTapListener {
      
        boolean onSingleTapConfirmed(MotionEvent e);
        
        boolean onDoubleTap(MotionEvent e);
      
        boolean onDoubleTapEvent(MotionEvent e);
    }

    /**
     * The listener that is used to notify when a context click occurs. When listening for a
     * context click ensure that you call {@link #onGenericMotionEvent(MotionEvent)} in
     * {@link View#onGenericMotionEvent(MotionEvent)}.
     */
    public interface OnContextClickListener {
    
        boolean onContextClick(MotionEvent e);
    }

    /**
     * A convenience class to extend when you only want to listen for a subset
     * of all the gestures. This implements all methods in the
     * {@link OnGestureListener}, {@link OnDoubleTapListener}, and {@link OnContextClickListener}
     * but does nothing and return {@code false} for all applicable methods.
     */
    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
            OnContextClickListener {

        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }

        public void onLongPress(MotionEvent e) {
        }

        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            return false;
        }

        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            return false;
        }

        public void onShowPress(MotionEvent e) {
        }

        public boolean onDown(MotionEvent e) {
            return false;
        }

        public boolean onDoubleTap(MotionEvent e) {
            return false;
        }

        public boolean onDoubleTapEvent(MotionEvent e) {
            return false;
        }

        public boolean onSingleTapConfirmed(MotionEvent e) {
            return false;
        }

        public boolean onContextClick(MotionEvent e) {
            return false;
        }
    }

典型用法:

   mGestureDetector = new GestureDetector(context, new GestureDetectorListener());

  @Override
    public boolean onTouchEvent(MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
        return true;
    }


    public class GestureDetectorListener extends  GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            Log.i(TAG, "onSingleTapConfirmed: ");
            return true;
        }
    }

 值得学习的是SimpleOnGestureListener这种写法,public 静态内部类,保持了代码的模块化,同时方便了调用者,不用再去实现每一个接口方法,因为调用者关心的可能只是某一两个方法

 

三,网络请求的回调

 

 

本质上来讲, 这里其实没有必要用接口回调的,  线程里直接传入一个引用也可以达到同样的目的.

接口主要用在类关系复杂时, 不方便持有对方引用的时候, 才考虑抽象出来一个接口, 但如果从通用性的角度来看, 这里用接口又比较好

posted @ 2018-03-12 10:26  疾风剑  阅读(426)  评论(0编辑  收藏  举报