Android APP完整基础教程(04)UI-事件机制

49 篇文章 15 订阅

上一节UI组件的学习和练习主要是让我们对绘制有一定的了解,接下来主要谈论UI组件对触摸、滑动。。。等动作的响应和处理部分,而这就涉及到android中的事件处理机制。android系统中提供2种事件处理机制:

  • 基于监听的事件处理:绑定事件监听器,事件发生则调用对应方法处理。使用设计模式中的观察者模式。
  • 基于回调的事件处理:重写组件的回调方法,代码相对简洁,使用设计模式中的外观模式。

1 基于监听的事件处理

监听模式关键三要素:事件源(事件发生场所,通常为各个组件)、事件(封装了一次用户操作)、事件监听器(监听事件源发生的事件)

基于监听的事件处理机制是一种委派式(Delegation)事件处理方式。普通组件将整个事件处理委托给事件监听器,当事件源发生指定的事件时,就通知所委托的事件监听器,由事件监听器来处理该事件。事件流程如下:

监听器实现的4种方式:匿名内部类、外部类实现、接口实现、xml文件中配置。

@1 匿名内部类。当只有一套UI组件使用该监听器时适合使用该方式。代码实现如下:

public class ActivityTest extends AppCompatActivity {
    private TextView textview;
    private Button button;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(layout.activity_main);
        textview=(TextView)findViewById(id.tv);
        textview.setText("start");
        button=(Button)findViewById(id.bt);
        //一气呵成,创建监听器,实现监听方法,UI组件注册监听器
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                textview.setText("clicked");
            }
        });
    }
}

@2 内/外部类实现。当很多UI组件都使用同一套监听器时,适合使用该方式。这里以内部类实现为例(外部类实现是在ActivityTest类之外实现该类,除此之外一致),代码实现如下:

public class ActivityTest extends AppCompatActivity {
    private TextView textview;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(layout.activity_main);
        textview=(TextView)findViewById(id.tv);
        textview.setText("start");
        button=(Button)findViewById(id.bt);
		//关键点2,UI组件注册监听器
        button.setOnClickListener(new ButtonListener());
    }
	
	//关键点1,创建一个实现监听接口的类并实现监听
    class ButtonListener implements View.OnClickListener{
        public void onClick(View v){
            textview.setText("clicked");
        }

    }
}

@3 接口实现。ActivityTest类不但要继承Activity,还要实现监听器的接口,代码实现如下:

//关键点1,接口实现,实现监听器
public class ActivityTest extends AppCompatActivity implements View.OnClickListener {  
    private TextView textview;  
    private Button bn;  
      
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        textview = (TextView)findViewById(R.id.tv);  
        bn = (Button)findViewById(R.id.bn);  
        bn.setOnClickListener(this);//关键点3,UI组件注册监听器
    }  
  
    @Override//关键点2,UI组件实现监听
    public void onClick(View v) {  
        textview.setText("clicked");  
    }
}

@4 xml配置。Layout中UI组件中定义 onClick="XXX",如下所示:

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
...
android:onClick="ClickFunc"/>

然后在该布局对应的Activity中定义一个 void XXX(void source)方法即可。代码如下所示:

public class ActivityTest extends AppCompatActivity {
    private TextView textview ;
    private Button button;
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(layout.activity_main);
		textview = (TextView)findViewById(R.id.tv);
		textview.setText("start");  
    }

    public void ClickFunc(View v){
		textview.setText("clicked");
    }
}

这里只是以onClickListener为例来解读了监听器的4种实现方式,关于更多监听器的API,参照文档:Android 组件之View各种监听器API总结

2 基于回调的事件处理

在 Android系统中,除了可以使用监听器进行事件处理之外,还可以通过回调机制进行事件处理。回调事件的处理模式中,用户在UI组件上触发某个事件时,UI组件方法会负责处理该事件。为了使用回调机制处理UI组件中的事件,一般是自定义新UI组件,之后重写该类事件的处理方法来实现。这里以自定义Button方式为例,代码如下:

public class MainActivity extends AppCompatActivity {
    private TestButton tbt;//定义自定义Button对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tbt = findViewById(R.id.testbutton);
    }
}

class TestButton extends androidx.appcompat.widget.AppCompatButton {
    private String TAG = "TestButton UI";
    public TestButton(Context context) {
        super(context);
    }

    //触摸屏事件触发该方法
    //重写Button组件的onTouchEvent方法
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        Log.d(TAG, "onTouchEvent in TestButton");
        return true;//返回值true,表示该事件已消费
    }
    //...
}

xml文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical">
    <com.ags.myapplication.TestButton
        android:id="@+id/testbutton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TestButton" />
</LinearLayout>

以上案例主要解读了自定义UI组件 重写方法的模式,该过程便是实现回调的方式(注意:UI组件回调方法(比如onTouchEvent)中返回值为true表示事件已处理,不会再传播;为false表示会继续传播并处理)

关于事件的传播顺序,一般事件是先触发UI组件的监听器,之后触发处理方法。在重写方法上处上是先触发子类处理方法,之后:

  • 如果子类方法返回false,继续触发父类处理方法。
  • 如果子类方法返回true,事件消费掉,后面不再处理。

对比监听方式 和 回调方式 两者的区别:

  • 基于监听的事件处理模型,事件源和事件监听器是分离的,事件源出发事件时交给事件监听器负责。监听模型用的是观察者模式。
  • 基于回调的事件处理模型,当事件源发生特定事件时,该事件由事件源本身处理。回调方法用的是外观模式。

3 Configuration获取系统设置

这是一种 当系统设置改变时应用也可以跟着系统配置改变而改变的机制(比如屏幕方向、触摸屏的类型等)。关于Configuration的XML属性和方法使用参照文档:Android之Configuration类

4 handler Message机制

handler机制设计的关键类有:

  • handler:主要2个作用,新线程中发送消息,主线程中接收&处理消息。
  • Message:handler接收和处理的消息对象。
  • MessageQueue:消息队列,先进先出,提供消息处理方法,比如消息的读取和发送。
  • Looper:每个线程只有一个Looper,负责读取MessageQueue中的消息,读到后交给handler的handleMessage方法中处理。

关于更多handler相关原理内容可以查看文章:

android系统核心机制 基础(04)handler message机制 java

android系统核心机制 基础(06)handler message机制 Native

handler使用案例可查看文章:

android系统核心机制 基础(05)handler使用案例(Java)

5 AsyncTask机制

目前官方已经不推荐使用。AsyncTask机制主要用于执行一些不太长的异步任务。作为用来替代Thread+Handler的辅助类,AsyncTask可以很轻松地执行异步任务并更新UI,但由于context泄露,回调遗漏,configuration变化导致崩溃,平台差异性等原因,已被弃用(在API 30,Android 11版本中AsyncTask被正式废弃,在API 29,Android10.0 平台上已经不推荐使用)

关于AsyncTask被弃用,说的比较全面的一篇文章是:AsyncTask将被弃用? CSDN博客,感兴趣的朋友可以更深入、更系统地了解原因。

总结

  • 了解监听模式和回调模式的概念和使用方法。了解Configuration类及使用方法。
  • 熟练使用监听器、了解常见的组件回调方法。深入理解Handler Message机制和内部原理(java层和native层),能够自己写出handler的常见使用案例。
  • 了解AsyncTask 被弃用的根本原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值