2023年6月20日发(作者:)

java历史记录_简单的带历史记录的搜索功能实现这两天闲来⽆事,就把前短时间项⽬中的搜索功能抽取出来,重新写⼀下,搜索功能虽然简单,但是设计到得知识点也挺多的,就当做⼀个总结吧。代码地址在最后⾯,话不多说,上效果图 _历史记录的存储⾸先来说下关于历史记录的存储,历史记录的存储⽅式其实可以有很多⽅法,可以⽤sp,数据库等等,那么就直接开撸吧。说开撸你还真以为就直接开撸了,还是先想想吧,我们做历史记录存储的时候需要提供什么给调⽤者,其实很简单⽆⾮就是可以增删改查吗。为了遵守⾥⽒替换原则,就先写了个抽象类BaseHistoryStorage,⾥⾯有⼏个抽象⽅法,⾄于是什么⾃⼰看吧。这样不管你是⽤SP还是数据库甚⾄其他更⽜的技术,只需要集成Base类,实现这些抽象⽅法就⾏了,⾄于你是怎么实现的,我才不管呢。/*** 历史信息存储基类* Created by Zellerpooh on 17/1/18.*/public abstract class BaseHistoryStorage {/*** 保存历史记录时调⽤** @param value*/public abstract void save(String value);/*** 移除单条历史记录** @param key*/public abstract void remove(String key);/*** 清空历史记录*/public abstract void clear();/*** ⽣成key** @return*/public abstract String generateKey();/*** 返回排序好的历史记录** @return*/public abstract ArrayList sortHistory();}上⾯的代码很好理解,SearchHistoryModel是我写的⼀个JavaBean,⾥⾯就放了两个String,⼀个是历史搜索的内容,⼀个是历史记录的Key,其实你直接返回⼀个String泛型的ArrayList的就⾏,但是我这⾥为了⽤SP实现的时候跟快速偷了个懒,好了⾃⼰去实现⼀个历史记录存储功能把。通过SharedPreference实现数据存储听到让你⾃⼰去实现是不是⼼凉了⼀半,当然是逗你的了,既然都来了怎么能不给你点福利呢,下⾯我就实现⼀个简单的通过SharedPreference实现的数据存储吧,来抛砖迎⽟吧。private static SpHistoryStorage instance;private SpHistoryStorage(Context context, int historyMax) {t = licationContext();Y_MAX = historyMax;}public static synchronized SpHistoryStorage getInstance(Context context, int historyMax) {if (instance == null) {synchronized () {if (instance == null) {instance = new SpHistoryStorage(context, historyMax);}}}return instance;}作为⼀个励志成为⾼逼格的⾼级程序员的菜鸟,当然不会放过任何装逼的机会,对于这种⽐较耗资源的数据存储,将他设计为单例模式当然最合适不过了,上⾯就是⼀个简单的DCL的单例模式实现,在安卓中将Context传⼊到单例中是⼀个⼤忌,你试想⼀下你的activity永远得不到释放是⼀件多么恐怖的事情,所以我就换成了applicationContext,反正他是跟随程序⼀直在的。然后来看看⾥⾯的⽅法实现吧private static SimpleDateFormat mFormat = new SimpleDateFormat("yyyyMMddHHmmss");@Overridepublic String generateKey() {return (new Date());}上⾯这个⽅法就是为了存储的时候根据当前时间⽣成的⼀个Key,⽤来判断先后顺序。@Overridepublic ArrayList sortHistory() {Map allHistory = getAll();ArrayList mResults = new ArrayList<>();Map hisAll = (Map) getAll();//将key排序升序Object[] keys = ().toArray();(keys);int keyLeng = ;//这⾥计算 如果历史记录条数是⼤于 可以显⽰的最⼤条数,则⽤最⼤条数做循环条件,防⽌历史记录条数-最⼤条数为负值,数组越界int hisLeng = keyLeng > HISTORY_MAX ? HISTORY_MAX : keyLeng;for (int i = 1; i <= hisLeng; i++) {(new SearchHistoryModel((String) keys[keyLeng - i], (keys[keyLeng - i])));}return mResults;}public Map getAll() {SharedPreferences sp = redPreferences(SEARCH_HISTORY,_PRIVATE);return ();}这个⽅法就是从SharedPreferences取出所有的值并且按照时间先后进⾏排序。@Overridepublic void save(String value) {Map historys = (Map) getAll();for ( entry : et()) {if ((ue())) {remove(());}}put(generateKey(), value);}保存的⽅法,需要先判断是否已经存在,存在的话就先删除然后根据最新的时间保存。剩下两个移除和清空的⽅法就⾃⼰看吧。@Overridepublic void remove(String key) {SharedPreferences sp = redPreferences(SEARCH_HISTORY,_PRIVATE); editor = ();(key);();}@Overridepublic void clear() {SharedPreferences sp = redPreferences(SEARCH_HISTORY,_PRIVATE); editor = ();();();}好了,通过sharedPreferences存储历史记录的功能就这样完成了,但是⼼⾥⼀想好久没有写数据库相关的代码了,就简单的撸了⼀个通过数据库存储的⽅法,篇幅有限代码就不贴了,想看的点这⾥。其实这⾥的代码借鉴了remusic的搜索记录存储的实现,有什么问题找他去→_→。界⾯的实现界⾯的实现就⽐较朴素了,毕竟我们都是⽐较注重内在的⼈,代码就不贴了,上⾯⼀个EditText,下⾯⼀个ListView再带上⼀个清空的按钮。界⾯写好了之后呢,先给ListView撸个adapter吧,也很简单继承BaseAdapter,实现下⽅法,然后暴露个接⼝出来,⽤于单条历史记录被点击和删除的时候⽤。public interface OnSearchHistoryListener {void onDelete(String key);void onSelect(String content);}lickListener(new kListener() {@Overridepublic void onClick(View v) {if (onSearchHistoryListener != null) {te((position).getTime());}}});lickListener(new kListener() {@Overridepublic void onClick(View v) {if (onSearchHistoryListener != null) {ct((position).getContent());}}});数据绑定界⾯撸完了,接着就需要将数据和界⾯联系起来了,这⾥就不得不再推荐⼀下MVP模式了,Model和View都由中间层Presenter来控制,使得逻辑看起来变得很清晰,所以这⾥就⽤MVP模式写了,其实我是怕⾃⼰把各位绕糊涂。public interface SearchPresenter {void remove(String key);void clear();void sortHistory();void search(String value);}public interface SearchView {void showHistories(ArrayList results);void searchSuccess(String value);}public interface SearchModel {void save(String value);void search(String value,OnSearchListener onSearchListener);void remove(String key);void clear();void sortHistory(OnSearchListener onSearchListener);}presenter要做的事情就是,当View被操作后,通知它去做数据操作,即增删改查,⽽Model只需要在presenter告诉它做什么的时候去做就⾏,成功之后再回调presenter去通知View,这⾥View就只需要两个操作,搜索成功后界⾯的切换以及历史记录的显⽰。那接下来就来实现⼀下model,presenter和View。public class SearchPresenterImpl implements SearchPresenter, OnSearchListener {private static final int historyMax = 10;private SearchView searchView;private SearchModel searchModel;public SearchPresenterImpl(SearchView searchView, Context context) {View = searchView;Model = new SearchModelImpl(context, historyMax);}//移除历史记录@Overridepublic void remove(String key) {(key);story(this);}@Overridepublic void clear() {();story(this);}//获取所有的历史记录@Overridepublic void sortHistory() {story(this);}@Overridepublic void search(String value) {(value);(value, this);}@Overridepublic void onSortSuccess(ArrayList results) {stories(results);}@Overridepublic void searchSuccess(String value) {Success(value);}}在初始化presenter的同时引⽤了View和Model,然后实现OnSearchListener当model完成操作是回调view中的⽅法。代码⾃⼰看吧,应该没有任何疑问。public class SearchModelImpl implements SearchModel {private BaseHistoryStorage historyStorage;public SearchModelImpl(Context context, int historyMax) {// historyStorage = tance(context, historyMax);historyStorage = tance(context, historyMax);}@Overridepublic void save(String value) {(value);}@Overridepublic void search(String value, OnSearchListener onSearchListener) {Success(value);}@Overridepublic void remove(String key) {(key);}@Overridepublic void clear() {();}@Overridepublic void sortHistory(OnSearchListener onSearchListener) {Success(story());}}model中的内容就简单了,创建⼀个前⾯实现的BaseStorage对象,对数据进⾏操作,这⾥没有对搜索做什么处理直接通过回调返回了传进来的字符串,在实际开发中应该是去请求接⼝,返回参数,所以在View中也没有做具体的处理,实际开发中可以打开⼀个新的页⾯后者,切换列表显⽰搜索到的内容。@Overridepublic void showHistories(ArrayList results) {ibility(0 != () ? E : );hData(results);}@Overridepublic void searchSuccess(String value) {xt(this, value, _SHORT).show();}上⾯就是View中实现的⽅法,获得历史记录是,告诉adapter去刷新列表就⾏了。接下来就只剩下View中⼀些简单的点击事件的处理了,搜索的时候调⽤(value);,清空的时候调⽤();是不是感觉so easy,妈妈再也不⽤担⼼我的学习了,当然别忘了presenter需要在activity的onCreate⽅法中进⾏实例化。最后呢,再给⼤家介绍⼏个技巧:不要忘记把搜索框EditText设置成Search模式 android:imeOptions="actionSearch"设置完以后不要忘记对键盘上的搜索按钮的监听ditorActionListener(new orActionListener() {@Overridepublic boolean onEditorAction(TextView v, int actionId, KeyEvent event) {if (actionId == _ACTION_SEARCH) {search(t().toString());return true;}return false;}});我们看到很多软件都会做模糊搜索的操作,你⼀输⼊列表就会弹出很多相关的词汇供你点击,顿时感觉好贴⼼哦,其实这个功能要实现也不能,通过给editText设置监听以及Handler延时发送消息就能够实现了。private TextWatcher textWatcher = new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {//在500毫秒内改变时不发送if (sages(MSG_SEARCH)) {Messages(MSG_SEARCH);}if (y(s)) {ibility(E);story();} else {ibility();//否则延迟500ms开始模糊搜索Message message = Message(); = s; = MSG_SEARCH;ssageDelayed(message, 500); //⾃动搜索功能 删除}} };//模糊搜索 private static final int MSG_SEARCH = 1;private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {search(t().toString().trim());}};啰嗦了这么半天,最后还是附上代码吧,searchBar有什么Bug和可以优化的地⽅还是希望⼤家能够留⾔,你们都将是菜鸡成长路上的恩师。

2023年6月20日发(作者:)

java历史记录_简单的带历史记录的搜索功能实现这两天闲来⽆事,就把前短时间项⽬中的搜索功能抽取出来,重新写⼀下,搜索功能虽然简单,但是设计到得知识点也挺多的,就当做⼀个总结吧。代码地址在最后⾯,话不多说,上效果图 _历史记录的存储⾸先来说下关于历史记录的存储,历史记录的存储⽅式其实可以有很多⽅法,可以⽤sp,数据库等等,那么就直接开撸吧。说开撸你还真以为就直接开撸了,还是先想想吧,我们做历史记录存储的时候需要提供什么给调⽤者,其实很简单⽆⾮就是可以增删改查吗。为了遵守⾥⽒替换原则,就先写了个抽象类BaseHistoryStorage,⾥⾯有⼏个抽象⽅法,⾄于是什么⾃⼰看吧。这样不管你是⽤SP还是数据库甚⾄其他更⽜的技术,只需要集成Base类,实现这些抽象⽅法就⾏了,⾄于你是怎么实现的,我才不管呢。/*** 历史信息存储基类* Created by Zellerpooh on 17/1/18.*/public abstract class BaseHistoryStorage {/*** 保存历史记录时调⽤** @param value*/public abstract void save(String value);/*** 移除单条历史记录** @param key*/public abstract void remove(String key);/*** 清空历史记录*/public abstract void clear();/*** ⽣成key** @return*/public abstract String generateKey();/*** 返回排序好的历史记录** @return*/public abstract ArrayList sortHistory();}上⾯的代码很好理解,SearchHistoryModel是我写的⼀个JavaBean,⾥⾯就放了两个String,⼀个是历史搜索的内容,⼀个是历史记录的Key,其实你直接返回⼀个String泛型的ArrayList的就⾏,但是我这⾥为了⽤SP实现的时候跟快速偷了个懒,好了⾃⼰去实现⼀个历史记录存储功能把。通过SharedPreference实现数据存储听到让你⾃⼰去实现是不是⼼凉了⼀半,当然是逗你的了,既然都来了怎么能不给你点福利呢,下⾯我就实现⼀个简单的通过SharedPreference实现的数据存储吧,来抛砖迎⽟吧。private static SpHistoryStorage instance;private SpHistoryStorage(Context context, int historyMax) {t = licationContext();Y_MAX = historyMax;}public static synchronized SpHistoryStorage getInstance(Context context, int historyMax) {if (instance == null) {synchronized () {if (instance == null) {instance = new SpHistoryStorage(context, historyMax);}}}return instance;}作为⼀个励志成为⾼逼格的⾼级程序员的菜鸟,当然不会放过任何装逼的机会,对于这种⽐较耗资源的数据存储,将他设计为单例模式当然最合适不过了,上⾯就是⼀个简单的DCL的单例模式实现,在安卓中将Context传⼊到单例中是⼀个⼤忌,你试想⼀下你的activity永远得不到释放是⼀件多么恐怖的事情,所以我就换成了applicationContext,反正他是跟随程序⼀直在的。然后来看看⾥⾯的⽅法实现吧private static SimpleDateFormat mFormat = new SimpleDateFormat("yyyyMMddHHmmss");@Overridepublic String generateKey() {return (new Date());}上⾯这个⽅法就是为了存储的时候根据当前时间⽣成的⼀个Key,⽤来判断先后顺序。@Overridepublic ArrayList sortHistory() {Map allHistory = getAll();ArrayList mResults = new ArrayList<>();Map hisAll = (Map) getAll();//将key排序升序Object[] keys = ().toArray();(keys);int keyLeng = ;//这⾥计算 如果历史记录条数是⼤于 可以显⽰的最⼤条数,则⽤最⼤条数做循环条件,防⽌历史记录条数-最⼤条数为负值,数组越界int hisLeng = keyLeng > HISTORY_MAX ? HISTORY_MAX : keyLeng;for (int i = 1; i <= hisLeng; i++) {(new SearchHistoryModel((String) keys[keyLeng - i], (keys[keyLeng - i])));}return mResults;}public Map getAll() {SharedPreferences sp = redPreferences(SEARCH_HISTORY,_PRIVATE);return ();}这个⽅法就是从SharedPreferences取出所有的值并且按照时间先后进⾏排序。@Overridepublic void save(String value) {Map historys = (Map) getAll();for ( entry : et()) {if ((ue())) {remove(());}}put(generateKey(), value);}保存的⽅法,需要先判断是否已经存在,存在的话就先删除然后根据最新的时间保存。剩下两个移除和清空的⽅法就⾃⼰看吧。@Overridepublic void remove(String key) {SharedPreferences sp = redPreferences(SEARCH_HISTORY,_PRIVATE); editor = ();(key);();}@Overridepublic void clear() {SharedPreferences sp = redPreferences(SEARCH_HISTORY,_PRIVATE); editor = ();();();}好了,通过sharedPreferences存储历史记录的功能就这样完成了,但是⼼⾥⼀想好久没有写数据库相关的代码了,就简单的撸了⼀个通过数据库存储的⽅法,篇幅有限代码就不贴了,想看的点这⾥。其实这⾥的代码借鉴了remusic的搜索记录存储的实现,有什么问题找他去→_→。界⾯的实现界⾯的实现就⽐较朴素了,毕竟我们都是⽐较注重内在的⼈,代码就不贴了,上⾯⼀个EditText,下⾯⼀个ListView再带上⼀个清空的按钮。界⾯写好了之后呢,先给ListView撸个adapter吧,也很简单继承BaseAdapter,实现下⽅法,然后暴露个接⼝出来,⽤于单条历史记录被点击和删除的时候⽤。public interface OnSearchHistoryListener {void onDelete(String key);void onSelect(String content);}lickListener(new kListener() {@Overridepublic void onClick(View v) {if (onSearchHistoryListener != null) {te((position).getTime());}}});lickListener(new kListener() {@Overridepublic void onClick(View v) {if (onSearchHistoryListener != null) {ct((position).getContent());}}});数据绑定界⾯撸完了,接着就需要将数据和界⾯联系起来了,这⾥就不得不再推荐⼀下MVP模式了,Model和View都由中间层Presenter来控制,使得逻辑看起来变得很清晰,所以这⾥就⽤MVP模式写了,其实我是怕⾃⼰把各位绕糊涂。public interface SearchPresenter {void remove(String key);void clear();void sortHistory();void search(String value);}public interface SearchView {void showHistories(ArrayList results);void searchSuccess(String value);}public interface SearchModel {void save(String value);void search(String value,OnSearchListener onSearchListener);void remove(String key);void clear();void sortHistory(OnSearchListener onSearchListener);}presenter要做的事情就是,当View被操作后,通知它去做数据操作,即增删改查,⽽Model只需要在presenter告诉它做什么的时候去做就⾏,成功之后再回调presenter去通知View,这⾥View就只需要两个操作,搜索成功后界⾯的切换以及历史记录的显⽰。那接下来就来实现⼀下model,presenter和View。public class SearchPresenterImpl implements SearchPresenter, OnSearchListener {private static final int historyMax = 10;private SearchView searchView;private SearchModel searchModel;public SearchPresenterImpl(SearchView searchView, Context context) {View = searchView;Model = new SearchModelImpl(context, historyMax);}//移除历史记录@Overridepublic void remove(String key) {(key);story(this);}@Overridepublic void clear() {();story(this);}//获取所有的历史记录@Overridepublic void sortHistory() {story(this);}@Overridepublic void search(String value) {(value);(value, this);}@Overridepublic void onSortSuccess(ArrayList results) {stories(results);}@Overridepublic void searchSuccess(String value) {Success(value);}}在初始化presenter的同时引⽤了View和Model,然后实现OnSearchListener当model完成操作是回调view中的⽅法。代码⾃⼰看吧,应该没有任何疑问。public class SearchModelImpl implements SearchModel {private BaseHistoryStorage historyStorage;public SearchModelImpl(Context context, int historyMax) {// historyStorage = tance(context, historyMax);historyStorage = tance(context, historyMax);}@Overridepublic void save(String value) {(value);}@Overridepublic void search(String value, OnSearchListener onSearchListener) {Success(value);}@Overridepublic void remove(String key) {(key);}@Overridepublic void clear() {();}@Overridepublic void sortHistory(OnSearchListener onSearchListener) {Success(story());}}model中的内容就简单了,创建⼀个前⾯实现的BaseStorage对象,对数据进⾏操作,这⾥没有对搜索做什么处理直接通过回调返回了传进来的字符串,在实际开发中应该是去请求接⼝,返回参数,所以在View中也没有做具体的处理,实际开发中可以打开⼀个新的页⾯后者,切换列表显⽰搜索到的内容。@Overridepublic void showHistories(ArrayList results) {ibility(0 != () ? E : );hData(results);}@Overridepublic void searchSuccess(String value) {xt(this, value, _SHORT).show();}上⾯就是View中实现的⽅法,获得历史记录是,告诉adapter去刷新列表就⾏了。接下来就只剩下View中⼀些简单的点击事件的处理了,搜索的时候调⽤(value);,清空的时候调⽤();是不是感觉so easy,妈妈再也不⽤担⼼我的学习了,当然别忘了presenter需要在activity的onCreate⽅法中进⾏实例化。最后呢,再给⼤家介绍⼏个技巧:不要忘记把搜索框EditText设置成Search模式 android:imeOptions="actionSearch"设置完以后不要忘记对键盘上的搜索按钮的监听ditorActionListener(new orActionListener() {@Overridepublic boolean onEditorAction(TextView v, int actionId, KeyEvent event) {if (actionId == _ACTION_SEARCH) {search(t().toString());return true;}return false;}});我们看到很多软件都会做模糊搜索的操作,你⼀输⼊列表就会弹出很多相关的词汇供你点击,顿时感觉好贴⼼哦,其实这个功能要实现也不能,通过给editText设置监听以及Handler延时发送消息就能够实现了。private TextWatcher textWatcher = new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {//在500毫秒内改变时不发送if (sages(MSG_SEARCH)) {Messages(MSG_SEARCH);}if (y(s)) {ibility(E);story();} else {ibility();//否则延迟500ms开始模糊搜索Message message = Message(); = s; = MSG_SEARCH;ssageDelayed(message, 500); //⾃动搜索功能 删除}} };//模糊搜索 private static final int MSG_SEARCH = 1;private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {search(t().toString().trim());}};啰嗦了这么半天,最后还是附上代码吧,searchBar有什么Bug和可以优化的地⽅还是希望⼤家能够留⾔,你们都将是菜鸡成长路上的恩师。