又是一輪新需求,實現本地搜索,估計其實很多地方都有用到過,尤其電商類APP。作爲自己親歷實現的又一功能,自己做一個小的標註。
閒話少敘,直入主題~_~ ~_~ ~_~ ~_~
需求:
1,實現搜索功能,將搜索關鍵詞保存並展示;
2,搜索關鍵詞輸入內容無限制;
3,APP關閉重啓後,歷史搜索可展示;
4,歷史搜索關鍵詞重複則將其提至最開始;【去重複,佔首位】
技術實現:
1,本地文件保存,使用SP,將關鍵詞串成字符串保存;
2,分割符使用空格,在內容輸入空格時,保存關鍵詞時將空格過濾。
編碼過程:
1,xml實現佈局;
2,類承接獲取View;
3,初始化數據,並刷新頁面;
4,交互操作,保存更新數據,刷新頁面;
5,異常情形考慮,細節維護。
佈局文件:
<?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:background="@color/page_bg_color"
android:orientation="vertical">
<!--搜索頁面佈局文件-->
<!-- ***************************** title ********************************* -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="13dp"
android:layout_weight="1"
android:background="@mipmap/search_title_bg_pic"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:src="@mipmap/search_inner_pic" />
<EditText
android:id="@+id/search_key_words_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="1"
android:background="@null"
android:hint="字體名"
android:imeOptions="actionSearch"
android:maxLines="1"
android:padding="10dp"
android:textSize="16sp" />
<ImageView
android:id="@+id/clear_content_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginRight="10dp"
android:src="@mipmap/del_search_content_pic"
android:visibility="invisible" />
</LinearLayout>
<TextView
android:id="@+id/search_cancel_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="10dp"
android:clickable="true"
android:text="取消"
android:textSize="16sp" />
</LinearLayout>
<!-- ***************************** title ********************************* -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="搜索歷史"
android:textSize="15sp" />
<ImageView
android:id="@+id/clear_history_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:src="@mipmap/del_history_pic"
android:visibility="gone" />
</RelativeLayout>
<ListView
android:id="@+id/search_history_lv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:headerDividersEnabled="true"
android:scrollbars="none" />
</LinearLayout>
代碼實現:
public class MainActivity extends Activity implements View.OnClickListener {
//=========常量================================================================
/**
* 搜索歷史關鍵字
*/
private static final String SEARCH_HISTORY_KEY = "seach_history_key";
//==========View================================================================
/**
* 搜索關鍵字輸入
*/
private EditText searchKeyWordsET;
/**
* 標題欄 - 取消
*/
private TextView topCancelTV;
/**
* 清除歷史搜索
*/
private ImageView clearHistoryIV;
/**
* 搜索歷史展示
*/
private ListView searchHistoryLV;
/**
* 清除輸入內容
*/
private ImageView clearContentIV;
//=========數據================================================================
/**
* 搜索歷史具體內容
*/
private List<String> searchHistoryList;
/**
* 搜索歷史適配器
*/
private ArrayAdapter<String> adapter;
/**
* 已經開啓了新的Activity
*/
private boolean startedActivity = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_search);
initView();
initListener();
initData();
refreshPageView();
showSoftInputFromWindow(MainActivity.this, searchKeyWordsET);
}
/**
* 初始化頁面控件
*/
private void initView() {
searchKeyWordsET = (EditText) findViewById(R.id.search_key_words_et);
topCancelTV = (TextView) findViewById(R.id.search_cancel_tv);
clearHistoryIV = (ImageView) findViewById(R.id.clear_history_iv);
searchHistoryLV = (ListView) findViewById(R.id.search_history_lv);
clearContentIV = (ImageView) findViewById(R.id.clear_content_iv);
searchHistoryLV.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
/**
* 初始化監聽器
*/
private void initListener() {
topCancelTV.setOnClickListener(this);
clearHistoryIV.setOnClickListener(this);
clearContentIV.setOnClickListener(this);
searchKeyWordsET.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEND || (event != null && event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) {
/**
* 點擊“搜索”後的處理
*/
String keyWord = searchKeyWordsET.getText().toString().trim();
keyWord = keyWord.replace(" ", "");
if (!TextUtils.isEmpty(keyWord)) {//爲空不處理
searchHistoryLV.setVisibility(View.VISIBLE);
clearHistoryIV.setVisibility(View.VISIBLE);
//去重複、保存內容、長度確認
/**
* 保存長串中出現短串 會出現異常
* 只能在數組中判斷
*/
/*
String historyContent = SharedPreferencesUtil.getString(ActivitySearch.this, SEARCH_HISTORY_KEY, "");
if (historyContent.length() > 0) {
if (historyContent.contains(keyWord)) {//有重複
String historySubContent = getSubString(historyContent, keyWord + " ");
SharedPreferencesUtil.putString(ActivitySearch.this, SEARCH_HISTORY_KEY, keyWord + " " + historySubContent);
} else {
SharedPreferencesUtil.putString(ActivitySearch.this, SEARCH_HISTORY_KEY, keyWord + " " + historyContent);
}
} else {//沒有保存過內容
SharedPreferencesUtil.putString(ActivitySearch.this, SEARCH_HISTORY_KEY, keyWord + " ");
}
*/
if (searchHistoryList == null) {
initData();
}
//去重複
Iterator<String> iterator = searchHistoryList.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (keyWord.equals(item)) {
iterator.remove();
}
}
searchHistoryList.add(0, keyWord);
//數據量控制
if (searchHistoryList.size() > 5) {
for (int i = 4; i < searchHistoryList.size(); i++) {
searchHistoryList.remove(5);
}
}
if (adapter != null) {
adapter.notifyDataSetChanged();
} else {
refreshPageView();
}
/**
* 當前監聽器會執行兩次
*/
if (!startedActivity) {
startedActivity = true;
startSearchResultActivity(keyWord);
}
return true;
} else {
return false;
}
}
return false;
}
});
searchHistoryLV.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final String keyword = searchHistoryList.get(position - 1);
searchHistoryList.remove(position - 1);
searchHistoryList.add(0, keyword);
adapter.notifyDataSetChanged();
searchKeyWordsET.setText(keyword);
searchKeyWordsET.setSelection(keyword.length());
startSearchResultActivity(keyword);
}
});
searchKeyWordsET.addTextChangedListener(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) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
clearContentIV.setVisibility(View.VISIBLE);
} else {
clearContentIV.setVisibility(View.INVISIBLE);
}
}
});
}
/**
* 跳轉結果頁面
*
* @param keyWord
*/
private void startSearchResultActivity(String keyWord) {
if (keyWord == null || "".equalsIgnoreCase(keyWord) || keyWord.length() <= 0) {
return;
}
/**
* 跳轉結果頁面
*/
// Intent intent = new Intent(MainActivity.this, ActivitySearchResult.class).putExtra("keyWord", keyWord);
// startActivity(intent);
}
/**
* 初始化數據
*/
private void initData() {
searchHistoryList = new ArrayList<>();
String historyContent = SharedPreferencesUtil.getString(MainActivity.this, SEARCH_HISTORY_KEY, "");
if (!"".equalsIgnoreCase(historyContent)) {
/**
* 保存有效內容
* 篩選掉最後保存內容有空格的情形
* 也可以在保存內容時,最後一個值加判斷條件,過濾掉空格
*/
String[] historys = historyContent.split(" ");
if (historys.length > 0) {
for (int i = 0; i < historys.length; i++) {
String history = historys[i].trim();
if (history.length() > 0) {
searchHistoryList.add(history);
}
}
}
}
}
/**
* 刷新頁面
*/
private void refreshPageView() {
/**
* 篩選組合完歷史消息
*/
if (searchHistoryList != null && searchHistoryList.size() > 0) {
searchHistoryLV.setVisibility(View.VISIBLE);
clearHistoryIV.setVisibility(View.VISIBLE);
adapter = new ArrayAdapter<String>
(MainActivity.this, R.layout.item_search_history, searchHistoryList);//item佈局及內容關聯??
searchHistoryLV.setAdapter(adapter);
adapter.notifyDataSetChanged();
} else {
searchHistoryLV.setVisibility(View.GONE);
clearHistoryIV.setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
/**
* 取消
*/
case R.id.search_cancel_tv:
finish();//關閉當前頁面
break;
/**
* 清除歷史
*/
case R.id.clear_history_iv:
SharedPreferencesUtil.putString(MainActivity.this, SEARCH_HISTORY_KEY, "");
searchHistoryList.clear();
adapter.notifyDataSetChanged();
searchHistoryLV.setVisibility(View.GONE);
clearHistoryIV.setVisibility(View.GONE);
break;
/**
* 內容輸入清空
*/
case R.id.clear_content_iv:
clearContentIV.setVisibility(View.INVISIBLE);
searchKeyWordsET.setText("");
break;
}
}
/**
* EditText獲取焦點並顯示軟鍵盤
*/
public void showSoftInputFromWindow(Activity activity, EditText editText) {
editText.setFocusable(true);
editText.setFocusableInTouchMode(true);
editText.requestFocus();
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
}
/**
* 字符串刪除指定子串
*
* @param s 是需要刪除某個子串的字符串 【原字符串】
* @param s1 是需要刪除的子串
* @return
*/
public String getSubString(String s, String s1) {
int postion = s.indexOf(s1);
int length = s1.length();
int Length = s.length();
String newString = s.substring(0, postion) + s.substring(postion + length, Length);
return newString;//返回已經刪除好的字符串
}
@Override
protected void onStop() {
super.onStop();
/**
* 保存歷史搜索到文件
*/
if (searchHistoryList != null && searchHistoryList.size() > 0) {
String result = "";
for (int i = 0; i < searchHistoryList.size(); i++) {
result += searchHistoryList.get(i) + " ";
}
SharedPreferencesUtil.putString(MainActivity.this, SEARCH_HISTORY_KEY, result);
}
}
@Override
protected void onResume() {
super.onResume();
startedActivity = false;
}
/**
* 涉及點考慮:
* 1,內容是需要能夠在應用再次重啓的時候展示的,需要文件化保存,選擇SP,將所有內容保存成爲字符串;
* 2,分割符:表示所有符號均可以輸入,只能選擇其中特殊的符號,選擇了空格;
* 3,空格作爲內容輸入時,在保存成爲單個關鍵詞時,篩除所有空格;
* 4,保存一個關鍵詞,後跟一個空格,在最後一個也有,再從文件讀取時,壓入數組,需要做去空格處理;
* 5,實際操作中,創建該背時,從文件加載歷史;類存在過程中,一直使用數組;在離開頁面時,再次保存到文件中;
* 6,另一個思路是所有直接操作文件,使用字符串刪除的指定串的方法;
* 文件操作中不能直接用於頁面渲染;
* 存在先有長串關鍵詞,之後有包含關係子串,篩選錯誤,比較多的控制;
* 7,邏輯方面:
* 【1】保存內容到文件;
* 【2】去處重複考慮;
* 【3】搜索過的內容排序到最前面;
* 【4】歷史內容保存數量限制;
*
* 細節處理:
* 1,進入頁面,獲取焦點,軟件盤彈出;---- 減少用戶操作,從細節出發;
* 2,內容輸入,保留清除內容助手 X;
* 3,EditText監聽器的多次執行,使用變量控制執行次數;【管控目的頁面的啓動模式】
*
*/
}
異次元傳送門:
心靈雞湯:
這一切點滴小事,或許好,或許差,爲的就是讓自己瞭解、認知平凡的自己和平凡的生活。也希望自己能永葆在平凡生活中活出不平凡的動力~_~