【问题标题】:How or why do listener interfaces work? And do interfaces have any other use rather than being a listener?侦听器接口如何或为什么工作?除了作为侦听器之外,接口还有其他用途吗?
【发布时间】:2019-05-03 11:13:51
【问题描述】:

每当我们想要创建一个监听器时,我们都会实现一个监听器接口。例如,让我们实现SensorEventListener

现在我们必须重写这个监听器接口的方法。

public void onSensorChanged(SensorEvent event);

public void onAccuracyChanged(Sensor sensor, int accuracy);

我不明白的是:

  1. 当我自动使用这些方法时,它们为什么以及如何工作?
  2. 为什么在精度发生变化时会调用onAccuracyChanged 方法?
  3. 毕竟,onAccuracyChanged 只是一个我们重写的空方法,因为我们的公式(或我们实现的接口)要求我们这样做。如果是低层造成的神奇的东西
  4. 某人何时以及为什么会在他/她实际使用接口 自主项目,不管安卓?

【问题讨论】:

    标签: java android listener implements


    【解决方案1】:

    在计算中,接口是一个共享边界,计算机系统的两个或多个独立组件通过该边界交换信息。(*)

    您可能希望响应某些事件,无论是系统事件还是用户事件。但为此,您需要知道您希望捕获的事件何时发生,以及当时必须做什么。

    为此,您打开一个机密 EAR 来收听事件。但这还不够,因为您还需要收到通知,以便您可以根据事件进行回复。您设置了回调,以便在事件发生时发出通知。我们在接口中创建的那些空体方法。

    侦听器是通过回调收听并通知回来的接口。

    那么如何使用所有这些?以及所有这些是如何相互作用的?

    • 首先创建一个带有空主体方法的接口,您打算在事件发生时调用这些方法:
    public interface MyListener{
    
          void actionOneHappens(Object o);
          void actionTwo();
          void actionThree();
    
    }
    
    • 创建一个类来处理一些事情,例如计数:
    public class MyCounter{
    //create a member of type MyListener if you intend to exchange infos
    
    private MyListener myListener;
    
    //let's create a setter for our listener
    public void setMyListener(MyListener listener)
    {
    this.myListener=listener;
    }
    
      MyCounter(){
    
      }
    //this method will help us count
    public void startCounting()
    {
      new CountDownTimer(10000,1000)
           {
    
               @Override
               public void onTick(long millisUntilFinished) {
    
                //I want to notify at third second after counter launched
    
                if(millisUntilFinished/1000==3)
                {
                  // I notify if true :
                  //as someone can forget to set the listener let's test if it's not //null
                  if(myListener!=null){
                     myListener.actionThree();
                  }
    
    
                }
    
               }
    
               @Override
               public void onFinish() {
    
               }
           }.start();
    }
    
    
    
    
    }
    
    • 然后您可以创建一个MyCounter 类型的对象并知道它什么时候是三点:

    MyCounter myCounter=new MyCounter();
    
    myCounter.setMyListener(new MyListener()
    {
    //then override methods here
      @override
      void actionOneHappens(Object o){
      }
      @override
      void actionTwo()
      {}
    
      @override
      void actionThree()
      {
       //Add you code here
       Toast.makeText(getApplicationContext(),"I'm at 3",Toast.LENGTH_LONG).show()
       }
    
    
    
    });
    
    //start your counter
    myCounter.startCounting();

    完成了!!我们就是这样进行的。

    【讨论】:

      【解决方案2】:

      这是suitable answer。请允许我举一个关于听众的例子。

      听众:

      假设有一个在后台获取数据的类Worker,以及另一个对该数据感兴趣的类InterestedClass

      public class Worker extends Thread{
        interface DataFetchedListener{
          void onDataFetched(String data);
        }
      
        private DataFetchedListener listener;
      
        @Override
        public void run(){
         String data = fetchData();
         // Data fetched inform your listener so he can take action
         listener.onDataFetched(data);
        }
      
        public void setDataFetchedListener(DataFetchedListener listener){
         this.listener = listener;
        }
      
        private String fetchData(){
          // returns the fetched data after some operations
          return "Data";
        }
      }
      
      
      public class InterestedClass implements Worker.DatafetchedListener{
      
       @Override
       public void onDataFetched(String data){
        doSomethingWith(data);
       }
      
       private doSomethingWith(String data){
        // just print it in the console
        System.out.println("Data fetched is -> " + data);
       }
      
      }
      

      Worker 不关心哪个类将操纵其数据,只要该类遵循DataFetchedListener 的合同

      同样这意味着任何类都可以对数据做一些事情(InterestedClass 只是在控制台中打印它)但Worker 不需要知道是哪个类,只是它实现了它的接口。

      主线可以这样...

      public class Application{
        public static void main(String[] args){
         InterestedClass interested = new InterestedClass();
         Worker worker = new Worker();
         worker.setDataFetchedListener(intereseted);
         worker.start(); // Starts Worker's thread
        }
      } 
      

      Worker 将获取数据时,它将通知其侦听器(当前为interested 对象)并且侦听器将采取相应的行动(interested 会将数据打印到控制台)。

      【讨论】:

      • 我明白了,但有一点我不清楚,您的界面是Worker 的某种“内部类”。但在 Android 中,监听器本身就是接口。所以那部分让我很困惑。
      • 哦...您可以在任何地方定义界面。我只是在 Worker 中定义它以保持一致性。只要接口对 Worker 和实现它的类可见,就没有问题!
      【解决方案3】:

      没有什么神奇的东西。事件监听机制一般如下:

      对于某些实体,可以监听该实体上的某些事件(让该实体命名为事件生成器)。因此,其他实体应该存在某种方式来监听这些变化(让这些实体命名为监听器)。现在监听器将自己注册为事件生成器的监听器。当事件生成器发生事件时,它会调用注册监听器的相关方法。

      作为一个简单的例子,假设一个按钮。按钮可能会为某些操作(例如单击)生成事件。现在,如果一个监听器想要知道何时单击了按钮,它应该将自己注册为该按钮的监听器。另一方面,按钮应该提供注册监听器的统一方式。这种统一的方式就是接口。每个实现该接口的实体都可以将自己注册为单击该按钮的侦听器:

      1- 监听器实现接口 2-侦听器将自己注册为按钮的侦听器(事件生成器) 3- 事件生成器调用所有注册监听器的相应方法(该方法是接口的一个方法)。

      对于您的情况,android 提供了一个管理器,您可以通过它在某些传感器上注册一个侦听器:android.hardware.SensorManager.registerListener()。一切都发生在这里(这不是魔术!)。当您将实体(实现相关接口SensorEventListener)注册为传感器侦听器时,该传感器的更改将导致调用侦听器的方法)。

      【讨论】:

      • 但我不明白的部分是,这些“生成器”与“听众”的关系是什么。 SensorManager 中是否定义了当精度发生变化时,SensorManager 期望调用者类中存在 onAccuracyChanged 方法?
      【解决方案4】:

      接口没有实现,为了使用它们,我们有两个选择:

      1. 实现它们的类
      2. 匿名类

      并考虑以下代码:

      interface TestInterface {
          void doSomething();
      }
      
      class TestClass{
          private TestInterface ti;
          public TestClass(TestInterface ti){
              this.ti = ti;
          }
      
          public void testActionMethod(){
              ti.doSomething();
              //some other codes
          }
      }
      
      class OurOwnLauncherApp{
          public static void main(String[] args) {
              TestClass tc = new TestClass(new TestInterface() {
                  @Override
                  public void doSomething() {
                      System.out.println("Hi!");
                  }
              });
      
              tc.testActionMethod();
      
              TestClass tc2 = new TestClass(new TestInterface() {
                  @Override
                  public void doSomething() {
                      System.out.println("Bye!");
                  }
              });
      
              tc2.testActionMethod();
          }
      }
      

      在这里我们有:

      1. 一个界面(就像你问的那样)
      2. 使用该接口的函数类
      3. 某个我们不知道的应用程序(可能是您的手机应用程序,也可能是您朋友的手机应用程序等)

      这段代码做了什么,它为 testActionMethod 提供了一个匿名类(实现了 TestInterface),并在 testActionMethod 中调用 doSomething 方法, 我们将调用反转为我们自己的方法。这就是你会看到这个结果的原因:

      嗨!

      再见!

      这正是监听器接口及其工作原理的简化版本

      【讨论】: