按钮点击事件通过外部类、内部类、匿名内部类和Lambda表达式来实现

一.第一步首先先搞懂:什么是外部类,什么是内部类,什么是匿名内部类

外部类在我的理解就是在外边的类,这样可能不好理解直接上代码就懂了:
class A{ }
class B{ }
这就是外部类,也可以说B是A的外部类。那内部类也应该很简单了:
class A{ classB{} }
这样,B就是A的内部类。
那什么是匿名内部类,匿名内部类也就是没有名字的内部类,可以理解成就用这一次,名字都不想取了,是不命名的内部类。
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
外部类,内部类,匿名内部类的详解:
https://blog.csdn.net/weixin_41244495/article/details/82873489

二.用内部类来解决按钮点击问题

AS中布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="按钮1"
        android:id="@+id/btn"/>

</LinearLayout>

就一个线性布局加一个按钮,很简单的一个布局。

然后就是来通过内部类来实现按钮点击事件,分为以下几步:
1.首先你要给按钮设置一个id,这样就可以通过id来找到有关按钮的组件。

android:id="@+id/btn"

然后你通过调用findViewById方法来找到按钮组件,同时创建了一个button对象

Button button=(Button)findViewById(R.id.btn);

2.接下来你要把button变成全局变量,因为你的onClickListener方法是在onCreate方法外面去执行。局部变量只能调用局部内的方法和变量这大家都清楚。把button这个对象变成全局变量就行了。
从局部变量变成全局变量快捷键Ctrl+Alt+F

private Button button;
button = (Button) findViewById(R.id.btn);

3.就是创建一个监听器,直接上代码吧。

button.setOnClickListener(new ClickListener());

new ClickListener()就是实现OnClickListener接口的方法,匿名内部类就是把ClickListener这个名字给省了,就这么简单。

4.第四步才是开始敲点击事件的方法OnClick方法

private class ClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            button.setText("我被点击了");
        }
    }
}
private class ClickListener implements View.OnClickListener

这一步就是告诉你ClickListener是实现OnClickListener接口的方法,建议不要将@Override去掉,这样你打错字母什么的会帮你报错来排查错误!!!
然后你点击按钮就会执行OnClick方法,我被点击了,这就是通过内部类的方法来实现按钮点击。

接下来是完整的MainActivity的Java代码截图:

public class MainActivity extends AppCompatActivity {


    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.btn1);
        button.setOnClickListener(new ClickListener());
    }

    private class ClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            button.setText("我被点击了");
        }
    }
}

三.通过匿名内部类的方式实现按钮点击事件

当你把内部类怎么实现按钮点击事件搞懂后,匿名内部类就会特别简单,直接给你先上代码,然后再分析:

public class MainActivity extends AppCompatActivity {


    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.btn1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                button.setText("我被点击了");
            }
        });
    }
}

匿名内部类和内部类的区别,也就是把上面ClickListener方法的名字直接给省了,就这么简单。
但是在这里要提个醒,匿名内部类使用条件是有限制的:
1.匿名内部类只能使用一次,它通常用来简化代码编写
2.必须继承一个父类或实现一个接口
具体参考:匿名内部类https://blog.csdn.net/hellocsz/article/details/81974251

四.Activity实现OnClickListener接口的方式设置点击事件

我第一个博客写过这个,就是用自身所在的这个Activity这个类实现OnClickListener接口,通俗来讲就是把你在的这个Activity当作ClickListener,用this指针来指定Activity。
具体代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.btn);
        button = (Button) findViewById(R.id.btn_one);
        button.setOnClickListener(this);
}

    @Override
    public void onClick(View v) {
        button.setText("我被点击了");
    }
}

五.通过外部类来实现按钮点击事件

我们了解了内部类怎么实现按钮点击事件,那么通过外部类来实现按钮点击和内部类实现有什么区别呢?

首先我们得先了解一个概念,内部类是可以访问外部类的成员,内部类具有成员属性
那这个概念是什么意思呢?button我们是不是这个按钮设置成了类成员,所以你内部类才可以访问外部类Activity的类成员button,但是外部类不能访问同是外部类的类成员button。
画个图就很明白了:
在这里插入图片描述

那么就涉及到传参问题,把button传出去
有两种方法:
1.通过构造方法将参数button传进来

button.setOnClickListener(new Shijian(button));
public Shijian(Button button) {
        this.button=button;
    }

然后在构造方法指定this.button就是这个button。
接下来的步骤也就和内部类的步骤差不多了,直接上代码就行了。

public class MainActivity extends AppCompatActivity {
    Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button=(Button)findViewById(R.id.btn1);
        button.setOnClickListener(new Shijian(button));
    }
}
public class Shijian implements View.OnClickListener {
    private Button button;

    public Shijian(Button button) {
        this.button=button;
    }
    @Override
    public void onClick(View view) {
        button.setText("我被点击了");
    }
}

2.通过函数的方法把参数传进来。

        Shijian shijian=new Shijian();
        shijian.setButton(button);
        button.setOnClickListener(shijian);
class Shijian implements View.OnClickListener {
    private Button button;

    public void setButton(Button button){
        this.button=button;
    }
    @Override
    public void onClick(View view) {
        button.setText("我被点击了");
    }
}

和上面构造方法传参数方法大同小异,就是通过setButton这个函数把button传进来。

但是我们推荐使用第一种方法,用构造方法传参,但是你上面忘记写了,不会报错

shijian.setButton(button);

假设这步忘记写了,就是编译通过,但是你点击你的按钮就会闪退,这是为什么,因为你没有把button传参传进去,shijian类里面这个button=null,为空,所以就会闪退,同时编译器会报空指针错误,如下图所示。
在这里插入图片描述但是如果你用构造方法来传值你没有写,编译器马上就会报错。方便查找。

同时我也要纠正一个我以前犯过的小错误,就比如你先定义了一个全局变量

private Button button;

但是你又在方法内创建了一个局部变量button

Button button=(Button)findViewById(R.id.btn1);

这样在此方法内全局变量button被局部变量button给隐藏了,简单来讲,你在方法内对button所作的所有操作都是对局部变量button做的操作,全局变量button还是初始的值为null,所以你在外面用button.setText方法时候,你点击按钮也会闪退,编译器在run里面会报出空指针的错误,和上面的错误一样的。

六.Lambda表达式

什么是Lambda表达式?
A lambda expression is a block of code with parameters(Lambda表达式是一个带有参数的表达式)。
Lambda表达式我们叫做函数式接口(functional interface),它有且仅有一个抽象方法的接口(即一个待实现的方法),也可以理解为替换匿名内部类的一种写法。

上面就是Lambda表达式的定义,简单来说你就可以把Lambda表达式当作匿名内部类的一种写法,为什么要又这种写法,因为Lambda写法简单阿,匿名内部类太长了

在新版的AS中要配置Lambda表达式环境,有两种方法,两种操作都是等效的:
1.第一种方法

打开 File->Preferences,搜索closure 把它钩上在这里插入图片描述打开Project Structure,选择使用java1.8
在这里插入图片描述
2.第二种方法:
在build.gradle(Module.app)中把你的目标和源都使用jdk1_8。具体如下图:
在这里插入图片描述

compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }

lambda表达式通用格式:(args)->{body},则lambda表达式由三部分组成:

  1. (arg1,arg2…) 参数部分
  2. -> goes to符号
  3. {} 方法代码块

这都是他的一些规范和理解的文字概念之类的,看的不是很懂,我们拿上面的匿名内部类的例子改成Lambda表达式就很容易理解了

匿名内部类的写法:

       button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                button.setText("我被点击了");
            }
        });

是吧,很长,很厚重。当你代码多的时候就显得无比厚重,当时你改成Lambda就非常简单

button.setOnClickListener(v -> button.setText("我被点击了"));

button.setOnClickListener两个都是一样的,v代表的是OnClick方法里面的View v这个参数,当然这个v你想改成什么就改成什么。然后->就是goes to就是到这个方法,也就是OnClick方法
button.setText也就是OnClick方法体内容,真的巨简单

当然Lambda表达式参数可以零个或多个
参数类型可指定或省略(Java编译器根据表达式的上下文推导出参数的类型)
表达式主体只有一条语句时,花括号可省略

Lambda详细内容:
https://www.jianshu.com/p/46b6918c863e

为了还债,必须坚持学习

发布了3 篇原创文章 · 获赞 4 · 访问量 2634

猜你喜欢

转载自blog.csdn.net/q2020117976/article/details/104707179