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