Android中EditTextsetText⽅法的踩坑实战
1、平平常常中就这样开始
某⼀天,我准备做⼀个搜索功能,这个搜索功能呢⼤概是在主活动A中,⽤EditText接收输⼊,当EditText监听到输⼊框中内容有变化,跳转到活动B中,活动B中准备有搜索历史记录等等,等在活动B中确定好搜索关键词后,跳回到活动A中,执⾏搜索,并显⽰搜索结果……⼀切顺顺利利,然后呢,懵逼了,我回不了活动A了。
当时的情况⼤致是这样的,
布局⽂件:l
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="schemas.android/apk/res/android"
xmlns:app="schemas.android/apk/res-auto"
xmlns:tools="schemas.android/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) {
setContentView(R.layout.activity_main);
//到EditText,添加⽂本监听
searchEditText=findViewById(_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布局⽂件:l
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="schemas.android/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 {
android layout布局private EditText editTextKeyWords;
@Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_search);
editTextKeyWords = findViewById(_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) {
setContentView(R.layout.activity_main);
Log.d("editTextSetText","after setContentView "+executeOrder++);
//到EditText,添加⽂本监听
searchEditText=findViewById(_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) {
setContentView(R.layout.activity_search);
Log.d("editTextSetText", "B after setContentView " +uteOrder++);
editTextKeyWords = findViewById(_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+" " +uteOrder++);
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⽅法。
总结
以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。