1、平平常常中就这样开始
某一天,我准备做一个搜索功能,这个搜索功能呢大概是在主活动A中,用EditText接收输入,当EditText监听到输入框中内容有变化,跳转到活动B中,活动B中准备有搜索历史记录等等,等在活动B中确定好搜索关键词后,跳回到活动A中,执行搜索,并显示搜索结果……一切顺顺利利,然后呢,懵逼了,我回不了活动A了。
当时的情况大致是这样的,
布局文件:activity_main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<? 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<? 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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(……),布局中重要的是
1
2
3
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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
1
2
3
4
5
6
|
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方法。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://www.jianshu.com/p/abcdcfeeedd1