赞
踩
目录
要监听 EditText 中文本内容的变化,可以使用 TextWatcher。
TextWatcher 是一个接口,TextWatcher 接口包含了三个方法,分别用于监听文本内容变化的不同阶段。(一般重写得较多的是第三个方法)
首先,在 XML 布局文件中添加自定义的 EditText:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
-
- <com.example.myapplication2.ClearableEditText
- android:id="@+id/editText"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
- </RelativeLayout>
然后,在 Java 代码中创建 ClearableEditText 类并继承 EditText
- package com.example.myapplication2;
-
- import android.content.Context;
- import android.graphics.drawable.Drawable;
- import android.text.Editable;
- import android.text.TextWatcher;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
-
- import androidx.appcompat.widget.AppCompatEditText;
- import androidx.core.content.ContextCompat;
-
- public class ClearableEditText extends AppCompatEditText {
-
- private Drawable clearDrawable; // 清空按钮的图标
-
- public ClearableEditText(Context context) {
- super(context);
- init();
- }
-
- public ClearableEditText(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- public ClearableEditText(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
-
- // 初始化方法
- private void init() {
- // 设置清空按钮图标
- clearDrawable = ContextCompat.getDrawable(getContext(), R.drawable.baseline_block_24);
- if (clearDrawable != null) {
- clearDrawable.setBounds(0, 0, clearDrawable.getIntrinsicWidth(), clearDrawable.getIntrinsicHeight());
- }
- setClearIconVisible(false); // 初始时隐藏清空按钮
- addTextChangedListener(textWatcher); // 监听文本变化
- setOnTouchListener(touchListener); // 监听触摸事件
- }
-
- // 文本变化监听器
- private TextWatcher textWatcher = new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- setClearIconVisible(s.length() > 0); // 根据文本长度显示/隐藏清空按钮
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- }
- };
-
- // 触摸事件监听器
- private OnTouchListener touchListener = new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- final int x = (int) event.getX();
- if (clearDrawable.isVisible() && x > getWidth() - getPaddingRight() - clearDrawable.getIntrinsicWidth()) {
- if (event.getAction() == MotionEvent.ACTION_UP) {
- setText(""); // 点击清空按钮时清空文本框内容
- }
- return true;
- }
- return false;
- }
- };
-
- // 设置清空按钮可见性
- private void setClearIconVisible(boolean visible) {
- setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1],
- visible ? clearDrawable : null, getCompoundDrawables()[3]);
- }
- }
在Android开发中,Handler是一个非常核心的组件,用于在不同线程之间传递消息,尤其是用于在后台线程和主UI线程之间进行通信。它使得我们能够将一些耗时的操作放在后台线程进行,而在操作完成后能够安全地更新UI。
Handler依赖于两个重要的组件:MessageQueue(消息队列)和Looper(循环处理器)。每个线程可以拥有一个Looper对象,该对象会循环地从MessageQueue中取出消息,并将这些消息分发给目标Handler处理。
在Android开发中,Handler类提供了一系列方法用于消息的发送和处理。这些方法使得Handler成为了线程间通信和UI更新的强大工具。
下面是一些核心方法的详细说明:
处理消息
发送消息
检查消息
移除消息
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/timerTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="30sp"
- android:text="0" />
- </LinearLayout>
- package com.example.myapplication2;
-
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.widget.TextView;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- public class MainActivity extends AppCompatActivity {
-
- private int counter = 0;
- private TextView timerTextView;
- private Handler handler = new Handler(Looper.getMainLooper());
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- timerTextView = findViewById(R.id.timerTextView);
-
- // 启动后台线程进行计时
- new Thread(new Runnable() {
- @Override
- public void run() {
- while (true) {
- try {
- Thread.sleep(1000); // 暂停1秒
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- counter++;
-
- // 使用Handler更新UI
- handler.post(new Runnable() {
- @Override
- public void run() {
- timerTextView.setText(String.valueOf(counter));
- }
- });
- }
- }
- }).start();
- }
- }
在这个例子中,我们首先定义了一个counter变量来记录计时器的值,以及一个TextView来显示这个值。接着,我们在onCreate方法中启动了一个新的线程,这个线程每隔一秒就会增加counter的值,并使用handler来更新UI上TextView的显示内容。
AsyncTask是Android提供的一个抽象类,用于简化在后台线程上执行长时间运行的任务,并在执行完毕后更新UI的过程。它允许执行后台操作并在UI线程上发布结果,而不需要操作线程或处理Handler。
多线程是现代编程中一个非常重要的概念,它允许程序同时执行多个任务。为了更好地理解多线程,我们需要先明白应用程序、进程和线程这几个基本概念。
应用程序(Application):应用程序是为了完成特定任务,用某种编程语言编写的一组指令集合。这些指令以静态代码的形式存在,当它们被执行时,会变成一个或多个进程。
进程(Process):进程是运行中的程序。它是系统进行资源分配和调度的基本单位。操作系统为每个进程分配独立的内存空间,确保它可以顺序地执行代码。从概念上讲,进程是程序的动态执行过程,包括代码加载、执行和执行完毕等阶段。
线程(Thread):线程是比进程更小的执行单元。一个进程可以包含多个线程,每个线程都共享进程的资源,如内存和文件句柄等,但是每个线程有自己的执行路径。线程由程序负责管理,而进程则是由操作系统调度的。
多线程(Multithreading):多线程指的是在一个进程中并行地执行多条指令。通过操作系统的调度算法,CPU的时间片被分配给不同的线程执行。实际上,由于CPU切换线程的速度非常快,虽然在任意给定的瞬间只有一个线程在执行,但用户感觉就像是多个线程在同时执行一样。
多线程的优点
多线程的挑战
尽管多线程带来了许多好处,但它也引入了一些复杂性和挑战。
同步(Synchronous)和异步(Asynchronous)是计算机科学中描述两种操作执行方式的术语,它们在多线程编程、网络请求、数据库交互等多个领域都有广泛应用。
同步(Synchronous)
同步操作指的是任务按顺序一次完成一个,后一个操作必须等前一个操作完成后才能开始执行。在同步操作中,执行流程是连续的,即一个任务的完成直接导致下一个任务的开始。这意味着在当前任务完成之前,程序不会执行或者转向下一个任务。
同步的特点:
异步(Asynchronous)
异步操作允许任务在等待期间不阻塞主程序的运行,可以同时进行多个操作。在异步操作中,可以启动一个任务,并在等待这个任务完成的同时继续执行其他任务。当异步任务完成时,通常通过回调函数、事件、Promise等机制通知调用者。
异步的特点:
选择同步还是异步
在Android开发中引入异步任务是为了解决几个核心问题,主要包括保持应用界面的响应性、避免Application Not Responding(ANR)异常以及遵守Android平台的规则。
1. 保持UI的响应性
Android应用的用户界面(UI)操作都是在主线程(也称为UI线程)中执行的。如果在这个线程上执行耗时的任务,如文件读写、网络请求或复杂的计算,会阻塞主线程,导致界面无法更新、响应用户操作,从而影响用户体验。通过使用异步任务,耗时操作可以在后台线程中执行,而不会阻塞UI线程,从而保持应用界面的流畅和响应性。
2. 避免ANR(Application Not Responding)异常
Android系统要求应用程序保持良好的响应性。如果UI线程被阻塞超过5秒钟(对于Broadcast Receiver是10秒),系统就会向用户显示ANR对话框。这通常是因为UI线程正在进行耗时操作而无法处理用户输入或系统事件。通过将耗时操作移到异步任务中,可以避免ANR异常。
3. 遵守Android平台的规则
从Android 3.0(Honeycomb)开始,Android平台不允许在主线程(UI线程)中进行网络操作,如果违反这一规则,应用会抛出NetworkOnMainThreadException异常。这一规定强制开发者将网络请求等耗时操作放在异步任务中处理,以避免阻塞UI线程和提高应用性能。
异步任务的实现方式
虽然AsyncTask是实现异步操作的一种方便方法,但Android开发中有多种方式可以实现异步任务:
AsyncTask是Android提供的一个用于简化异步任务执行的抽象类。它允许开发者在后台线程中执行耗时操作,然后在UI线程中更新UI或处理结果,而不会阻塞UI线程。AsyncTask通过泛型参数来指定启动任务执行时输入的参数类型、后台任务执行进度的类型以及后台任务执行完毕后返回的结果类型。以下是这三个泛型参数的详细说明:
AsyncTask<Params, Progress, Result> 参数说明
使用AsyncTask的基本步骤
AsyncTask是Android提供的一个用于简化在后台线程上执行任务并在前台更新UI的抽象类。它定义了一系列回调方法,允许开发者在不同阶段对任务进行控制和UI的更新。
onPreExecute():
doInBackground(Params... params):
onPostExecute(Result result):
onProgressUpdate(Progress... values):
onCancelled():
使用AsyncTask的注意事项
虽然AsyncTask为异步任务提供了方便的实现方式,但由于其存在一些局限性,如容易引起内存泄露、处理并发不够灵活等问题,因此在新的Android开发实践中,AsyncTask已经被标记为过时(deprecated)。
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout 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">
-
- <ProgressBar
- android:id="@+id/progressBar"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="50dp" />
-
- <TextView
- android:id="@+id/resultTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/progressBar"
- android:layout_marginTop="20dp"
- android:textSize="18sp"
- android:textColor="@android:color/black" />
-
- </RelativeLayout>
- package com.example.myapplication2;
-
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.widget.ProgressBar;
- import android.widget.TextView;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- public class MainActivity extends AppCompatActivity {
-
- private ProgressBar progressBar;
- private TextView resultTextView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- progressBar = findViewById(R.id.progressBar);
- resultTextView = findViewById(R.id.resultTextView);
-
- MyAsyncTask myAsyncTask = new MyAsyncTask();
- myAsyncTask.execute();
- }
-
- private class MyAsyncTask extends AsyncTask<Void, Integer, String> {
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- // 执行后台耗时操作前做一些初始化工作,显示进度条
- progressBar.setMax(100);
- }
-
- @Override
- protected String doInBackground(Void... voids) {
- // 模拟耗时操作
- for (int i = 0; i <= 100; i += 10) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // 更新进度
- publishProgress(i);
- }
- return "任务完成!";
- }
-
- @Override
- protected void onProgressUpdate(Integer... values) {
- super.onProgressUpdate(values);
- // 更新UI界面的进度条
- progressBar.setProgress(values[0]);
- }
-
- @Override
- protected void onPostExecute(String result) {
- super.onPostExecute(result);
- // 后台任务执行完毕,更新UI界面显示结果
- resultTextView.setText(result);
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。