一.第一步首先先搞懂:什么是外部类,什么是内部类,什么是匿名内部类
外部类在我的理解就是在外边的类,这样可能不好理解直接上代码就懂了:
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表达式由三部分组成:
- (arg1,arg2…) 参数部分
- -> goes to符号
- {} 方法代码块
这都是他的一些规范和理解的文字概念之类的,看的不是很懂,我们拿上面的匿名内部类的例子改成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
为了还债,必须坚持学习