Android中EditText setText方法的踩坑实战

1、平平常常中就这样开始

某一天,我准备做一个搜索功能,这个搜索功能呢大概是在主活动A中,用EditText接收输入,当EditText监听到输入框中内容有变化,跳转到活动B中,活动B中准备有搜索历史记录等等,等在活动B中确定好搜索关键词后,跳回到活动A中,执行搜索,并显示搜索结果……一切顺顺利利,然后呢,懵逼了,我回不了活动A了。

当时的情况大致是这样的,

布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
 android:orientation="vertical"
 tools:context=".ActivityA">
 <EditText
 android:inputType="text"
 android:singleLine="true"
 android:imeOptions="actionSearch"
 android:id="@+id/et_search"
 android:textSize="24sp"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:hint="输入点啥呗"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintLeft_toLeftOf="parent"
 app:layout_constraintRight_toRightOf="parent"
 app:layout_constraintTop_toTopOf="parent" />
 <TextView
 android:textSize="24sp"
 android:gravity="center"
 android:layout_weight="1"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="我是主活动啦"/>

</LinearLayout>

活动A:AcitivityA.java

public class ActivityA extends AppCompatActivity {
 private EditText searchEditText;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 //找到EditText,添加文本监听
 searchEditText=findViewById(R.id.et_search);
 searchEditText.addTextChangedListener(new TextWatcher() {
  @Override
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  Log.d("editTextSetText","beforeTextChanged");
  }

  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
  Log.d("editTextSetText","onTextChanged");
  }

  @Override
  public void afterTextChanged(Editable s) {
  Log.d("editTextSetText","afterTextChanged");
  startActivity(new Intent(ActivityA.this,ActivityB.class));
  }
 });
 //接收B活动传递过来的keywords,并显示在输入框中
 String keyword=getIntent().getStringExtra("keywords");
 if(keyword!=null)
  searchEditText.setText(keyword);
 }

活动B布局文件:activity_search.xml

<?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:orientation="vertical">

 <EditText
 android:id="@+id/et_search_keywords"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:hint="输入你想要找的东西"
 android:textSize="24sp"
 android:inputType="text"
 android:singleLine="true"
 android:imeOptions="actionSearch"/>

 <TextView
 android:textSize="24sp"
 android:gravity="center"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:text="我就是那个准备搜索关键词,历史记录等等等等的活动B啦" />
</LinearLayout>

活动B:ActivityB.java

public class ActivityB extends AppCompatActivity {
 private EditText editTextKeyWords;

 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_search);
 editTextKeyWords = findViewById(R.id.et_search_keywords);
 editTextKeyWords.setOnEditorActionListener(new TextView.OnEditorActionListener() {
  @Override
  public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
  if (actionId == EditorInfo.IME_ACTION_SEARCH) {
   //将取得关键字传递到A中
   String keywords = v.getText().toString().trim();
   Intent intent = new Intent(ActivityB.this, ActivityA.class);
   intent.putExtra("keywords", keywords);
   Log.d("editTextSetText", "B keywords:" + keywords);
   startActivity(intent);

   ActivityB.this.finish();
  }
  return false;
  }
 });

 }
}

OK,至此大功告成,我成功复原了当时我大致做法,也还原了当时的Bug:在A中有输入时,跳到B,在B中确定好关键词后,点击搜索(你的搜索在哪里,让你们看下图吧)

看到右下角我圈起来的那个搜索按钮了吗,布局文件照着我那个写,监听就是editTextKeyWords.setOnEditorActionListener(……),布局中重要的是

 android:inputType="text"
 android:singleLine="true"
 android:imeOptions="actionSearch"

这个主要是参看这位大大的,当然了,在此这不算重点,重点是我又成功写了个Bug。当时项目挺急的,我弄了半天没弄明白,(我一直以为是A活动因为setText而崩溃了,然而没有log……当然,最终证明似乎不是这样子。),无奈之下,福灵心至,想到:

2、用了setHint()解决了当务之急

无奈之下选择了该方法,问题成功解决,也没什么明显瑕疵,就是心理一直惦记着,这他丫的问题出在什么地方呢,定位当然是定位到了A活动中的searchEditText.setText(keyword)这一句。

后来加了几天班,等稍微有空了,我再回头瞧瞧,莫非,谷歌给我们写了个小bug,结果嘛:事实证明,好像这东西是自己的锅。

3、发现敌踪迹

当时我实在onResume()调用searchEditText.setText(keyword)这几句的,所以问题显得比我上面写的要隐蔽些。当然,有空了之后,我进入setText方法,一步步执行,当然了,没发现明显问题。只是我偶尔会发现它会不经意间往beforeTextChanged等这一两个方法中眺一下,那么想一想我在里面又做了什么……,似乎我发现问题所在了。那么有了猜测,对该方法添加log,我们队log做下修改,使其能明确地显示程序执行顺序,修改代码如下:

ActivityA.java

public class ActivityA extends AppCompatActivity {
 private EditText searchEditText;
 public static int executeOrder=0;//表示log执行顺序,进而推测代码执行顺序
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  Log.d("editTextSetText","after setContentView "+executeOrder++);
  //找到EditText,添加文本监听
  searchEditText=findViewById(R.id.et_search);
  searchEditText.addTextChangedListener(new TextWatcher() {
   @Override
   public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    Log.d("editTextSetText","beforeTextChanged "+executeOrder++);
   }

   @Override
   public void onTextChanged(CharSequence s, int start, int before, int count) {
    Log.d("editTextSetText","onTextChanged "+executeOrder++);
   }

   @Override
   public void afterTextChanged(Editable s) {
    Log.d("editTextSetText","afterTextChanged "+executeOrder++);
    startActivity(new Intent(ActivityA.this,ActivityB.class));
   }
  });
  //接收B活动传递过来的keywords,并显示在输入框中
  String keyword=getIntent().getStringExtra("keywords");
  if(keyword!=null) {
   searchEditText.setText(keyword);
   Log.d("editTextSetText","after set text "+executeOrder++);
   /*searchEditText.setHint(keyword);*/
  }
 }
}

ActivityB.java

public class ActivityB extends AppCompatActivity {
 private EditText editTextKeyWords;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_search);
  Log.d("editTextSetText", "B after setContentView " +ActivityA.executeOrder++);
  editTextKeyWords = findViewById(R.id.et_search_keywords);
  editTextKeyWords.setOnEditorActionListener(new TextView.OnEditorActionListener() {
   @Override
   public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
    if (actionId == EditorInfo.IME_ACTION_SEARCH) {
      //将取得关键字传递到A中
      String keywords = v.getText().toString().trim();
      Intent intent = new Intent(ActivityB.this, ActivityA.class);
      intent.putExtra("keywords", keywords);
      Log.d("editTextSetText", "B keywords:" + keywords+" " +ActivityA.executeOrder++);
      startActivity(intent);
      ActivityB.this.finish();
    }
    return false;
   }
  });
 }
}

执行一遍,log如下:

上述log显示,做如下解读:

1、 启动应用,执行初始化,打印 0

2、输入内容,执行1,2,3,到启动活动B

3、活动B初始化执行 4

5、 活动B中点击搜索 5,并启动活动A

6、A再一次初始化 执行6

7、问题出来了,为什么会执行7、8、9,此时我们并没有EditText输入内容,但是监听触发了。

8、 执行9之后,启动活动B,执行11没问题,但是10的顺序按理说应该在6之后、紧接着6.

尽管未能完全解读这个执行顺序,但是,写的程序陷入了一个类似死循环的bug是没有问题的,这也就解开了为什么返回不了A活动的问题,并不是不能返回A,而是返回A之后又跳转到B了。

进一步调试,在关键节点增加log,我们再setText前后增加log

if(keyword!=null) {
   Log.d("editTextSetText","after set text "+executeOrder++);
   searchEditText.setText(keyword);
   Log.d("editTextSetText","after set text "+executeOrder++);
   /*searchEditText.setHint(keyword);*/
  }

log信息:

关键点我已经标出来了,在7和11间,有了监听方法的执行,说明:EditText的setText方法会触发 文本变化的监听,这就是此次踩坑的根源。

4、 捕获凶手:setText()方法会触发EditText文本变化的监听

5、解决方案:将setText设置在设置监听之前,或者用setHint也可以。

如上,找出问题症结之后,解决办法就很简单了,我们将setText写在设置监听之前就可以避免该坑,或者干脆用setHint方法。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Android高级组件ImageSwitcher图像切换器使用方法详解

    图像切换器(ImageSwitcher),用于实现类似于Windows操作系统的"Windows照片查看器"中的上一张.下一张切换图片的功能.在使用ImageSwitcher时,必须实现ViewSwitcher.ViewFactory接口,并通过makeView()方法来创建用于显示图片的ImageView.makeView()方法将返回一个显示图片的ImageView.在使用图像切换器时,还有一个方法非常重要,那就是setImageResource方法,该方法用于指定要在ImageS

  • Android高级组件Gallery画廊视图使用方法详解

    画廊视图(Gallery)表示,能够按水平方向显示内容,并且可用手指直接拖动图片移动,一般用来浏览图片,被选中的选项位于中间,并且可以响应事件显示信息.在使用画廊视图时,首先需要在屏幕上添加Gallery组件,通常使用<Gallery>标记在XML布局文件中添加.其基本语法如下: <Gallery     属性列表   > </Gallery> Gallery组件支持的XML属性表如下: android:animationDuration  用于设置列表切换时的动画持续

  • 浅析Android Studio 3.0 升级各种坑(推荐)

    点击 Check for Updates 增量更新: 下载完成,会提示更新 您将 Gradle 更新至 4.1: 这里建议您对老项目先暂时点击 Don't remind me on this project,以防有坑.当然我不入地狱谁入地狱,我点 Update,于是问题来了,一直处于下载中,不过,莫担心,我下载好了,公众号聊天界面回复「 gradle-4.1-all 」,下载 gradle-4.1-all.zip 文件,放到: 重启 Android Studio. gradle 目录: Mac系

  • Android WebView使用的技巧与一些坑

    随着手机性能的提高,以及iOS和Android两个平台的普及,更多的App都会选择两个平台的App都进行开发,在有些时候,为了更加快速的开发,我们会采用hybird方式开发,这个时候我们需要使用webview并且自己进行一些配置.Android的webview在低版本和高版本采用了不同的webkit版本内核,4.4后直接使用了chrome,因此问题很多,这里分享一些我使用过程的一些技巧和遇到的坑. ###webview配置### mWebview.getSettings().setJavaScr

  • Android中ViewPager组件的基本用法及实现图片切换的示例

    ViewPager是android-support-v4.jar包里的组件.在布局文件里标签需要连包名一起 写全称<android.support.v4.view.ViewPager /> 基本用法 ViewPager的基本用法我概括为三步 第一步 在主布局文件里放一个ViewPager组件 第二步 为每个页面建立布局文件,把界面写好 第三步 在主Activity里获取ViewPager组件,并为它设定Adapter. Adapter详细讲讲,ViewPager对应的Adapter继承自Pag

  • Android组件Glide实现图片平滑滚动效果

    Glide是一款基于Android的图片加载和图片缓存组件,它可以最大性能地在Android设备上读取.解码.显示图片和视频.Glide可以将远程的图片.视频.动画图片等缓存在设备本地,便于提高用户浏览图片的流畅体验. Glide最核心的功能就是提高滚动图片列表的性能,并且Glide还能满足对远程图片的读取.改变尺寸以及展示的性能要求. Glide使用方法 最简单的示例代码如下: // For a simple view: @Override public void onCreate(Bundl

  • Android可循环显示图像的Android Gallery组件用法实例

    本文实例分析了Android可循环显示图像的Android Gallery组件用法.分享给大家供大家参考,具体如下: Gallery组件主要用于横向显示图像列表,不过按常规做法.Gallery组件只能有限地显示指定的图像.也就是说,如果为Gallery组件指定了10张图像,那么当Gallery组件显示到第10张时,就不会再继续显示了.这虽然在大多数时候没有什么关系,但在某些情况下,我们希望图像显示到最后一张时再重第1张开始显示,也就是循环显示.要实现这种风格的Gallery组件,就需要对Gall

  • Android开发之StackView用法和遇到的坑分析

    本文实例分析了Android开发之StackView用法和遇到的坑.分享给大家供大家参考,具体如下: 关于StackView网上已经有很多内容了 这里我着重将一些使用过程中遇到的坑吧 先看下效果,和很多人一样 很多人加完图片后发现图片不显示,这里可能有两个原因: 一.直接闪退,然后报错.一般会有头这么一句话: Failed to allocate a 74649612 byte allocation with 16765728 free bytes and 59MB until OOM 提示一个

  • android Gallery组件实现的iPhone图片滑动效果实例

    实现的效果图,可左右滑动: 一.先在将Gallery标签放入: 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical"     android:layo

  • Android自定义组件获取本地图片和相机拍照图片

    iOS中有封装好的选择图片后长按出现动画删除效果,效果如下 而Android找了很久都没有找到有这样效果的第三方组件,最后懒得找了还是自己实现这效果吧 选择图片后还可对图片进行剪裁 当然,代码中还有很多不完善的地方,我接下来会继续完善这个组件的 已经上传到开源社区,欢迎大家来Star啊~ Demo源码:传送门 设计中的碰到的一些问题和解决思路 1.如何让加号图片显示在GridView最后面 首先在调用GridAdapter构造方法时就加载加号图片 /** * 图片适配器 * @param con

随机推荐