又是一轮新需求,实现本地搜索,估计其实很多地方都有用到过,尤其电商类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监听器的多次执行,使用变量控制执行次数;【管控目的页面的启动模式】
*
*/
}
实现效果展示:
心灵鸡汤:
这一切点滴小事,或许好,或许差,为的就是让自己了解、认知平凡的自己和平凡的生活。也希望自己能永葆在平凡生活中活出不平凡的动力~_~