Jamendo学习笔记之七:搜索页面实现及数据加载
2012-06-02 11:27
579 查看
Mike按:
前一段时间,在工作学习方面有点迷茫。请教了两个高人。分别给出了两个互补的建议,受益匪浅,感谢!一是学习开源项目,二是在应用的实际开发中学习东西(按照自己的思路写一个app)。最近主要是优化重构之前的代码,将开源项目中比较好的部分应用到自己的项目中。本文就是基于此。
(一) 应用场景:刷新数据,显示加载进度条,数据准备,数据准备完毕,进度条消失,显示结果。
可能出现的状况:
1, 无网络,无法获取数据,有网络,显示提示
![](http://img1.51cto.com/attachment/201206/112946231.png)
2, 一切正常,显示数据
![](http://img1.51cto.com/attachment/201206/113204172.png)
3, 搜索无结果,各种错误:协议错误,超时
![](http://img1.51cto.com/attachment/201206/113234267.png)
之前的思路,先显示Dialog,新启线程加载数据,数据加载完毕后,Handler发送消息,UI中刷新,Dialog消失。结果的显示使用帧布局。功能实现上ok,但是封装上不好,感觉代码分散,混乱。
(二) Jamendo的处理
将这个处理过程封装成LoadingDialog(继承AsyncTask),结果的显示上使用ViewFlipper。思路非常清晰。
1, 加载处理的基类LoadingDialog
a) Jamendo将加载的处理均使用LoadingDialog的实现子类。相关继承树(extend tree)如下图所示:
![](http://img1.51cto.com/attachment/201206/113408404.png)
b) LoadingDialog继承AsyncTask,这样的好处是容易控制流程的先后顺序,而且UI线程和其他线程的切换非常的平滑。其类的结构如下图所示:
![](http://img1.51cto.com/attachment/201206/113444845.png)
c) 定义
泛型的使用,代码如下:
d) 流程
绘制其流程图如下:
![](http://img1.51cto.com/attachment/201206/075627884.jpg)
i. onPreExecute()
显示Dialog,这个创建方法第一次见到,Dialog可被cancel掉,代码如下:
ii. doInBackground()-------抽象方法
这里是处理数据的地方,Jamendo在这里定义了抽象方法doInBackGround(),以应对不同的需求,子类各自实现即可。代码如下:
iii. onPostExecute()
代码如下:
数据获取结束之后,Dialog dismiss掉。数据获取有两种情况:
l 获取数据正常
调用doStuffWithResult(Result result)方法处理数据,此方法为抽象方法,需要子类实现,按照自己的需求处理,代码如下:
l 获取数据异常
调用failMsg()方法。即Toast,代码如下:
iv. onProgressUpdate()
显然,doInBackGround()方法中,可以实时的将一些信息(错误信息即WSError的Message)publish到本方法 。一旦出现问题:首先,toast,其次,取消本次异步任务,最后,Dialog dismiss掉。代码如下:
2, 实现类SearchDialog(以此为例,说明其实现,只说明最重要的)
a) SearchActvity内容部分的布局,效果图,参看上面彩图。
布局虽是自定义ViewFlipper,我在实际使用中使用原生ViewFlipper也ok,Xml文件如下:
b) 多态的使用
我是在这个类中深深体会多态的妙处。搜索有很多的分类,每一类可能对应不同的Adapter,那么对结果的处理就成了一个问题。在SearchDialog中定义BaseAdapter。对于所有的搜索结果的处理就smooth了。代码如下:
c) 错误信息的捕获
Jamendo自己定义了Throwable类WSError,捕获Exception之后(就是主要的网络连接错误:请求异常,连接超时,下载超时等),将错误信息封装之后,向上抛出。分两步处理方式(以AlbumSearch为例):
第一步:catch
第二步:publishProgress
代码如下:
d) 对结果的处理
多态的使用,使得ListView的数据填充很easy。代码很清晰,不用作解释,代码如下:
3, 搜索状态的保存
Jamendo对搜索状态的保存,是基于其的搜索页面是Activity之间的跳转。所以有必要保存。不做解释了,代码如下:
(三) 思考
前面的博文分析提到,Jamendo中有一个RequestCache,缓存10次请求。觉得意义不大,因为点开任意一个页面,滚动一下,很快就超过10个url请求。在Search这里,发现RequestCache的好处。搜索在短时间内,结果基本不会发生差别,所以阻止重复搜索很有必要。在实时性要求特别高的weibo里,RequestCache的使用也不用影响其刷新到最新数据,因为10次很容易超过,之前保留的刷新最新数据的老数据将被remove掉。
注:重构代码时,发现一个奇怪的问题,当前Activity有EditText(即有组件被focus到时),其继承的BaseActivity的无法显示showDialog()所对应的Dialog不会显示,但new出的Dialog可以显示。查看文档后,showDialog()方法不建议使用。文档如下:
本文出自 “小新专栏” 博客,请务必保留此出处http://mikewang.blog.51cto.com/3826268/885431
前一段时间,在工作学习方面有点迷茫。请教了两个高人。分别给出了两个互补的建议,受益匪浅,感谢!一是学习开源项目,二是在应用的实际开发中学习东西(按照自己的思路写一个app)。最近主要是优化重构之前的代码,将开源项目中比较好的部分应用到自己的项目中。本文就是基于此。
(一) 应用场景:刷新数据,显示加载进度条,数据准备,数据准备完毕,进度条消失,显示结果。
可能出现的状况:
1, 无网络,无法获取数据,有网络,显示提示
![](http://img1.51cto.com/attachment/201206/112946231.png)
2, 一切正常,显示数据
![](http://img1.51cto.com/attachment/201206/113204172.png)
3, 搜索无结果,各种错误:协议错误,超时
![](http://img1.51cto.com/attachment/201206/113234267.png)
之前的思路,先显示Dialog,新启线程加载数据,数据加载完毕后,Handler发送消息,UI中刷新,Dialog消失。结果的显示使用帧布局。功能实现上ok,但是封装上不好,感觉代码分散,混乱。
(二) Jamendo的处理
将这个处理过程封装成LoadingDialog(继承AsyncTask),结果的显示上使用ViewFlipper。思路非常清晰。
1, 加载处理的基类LoadingDialog
a) Jamendo将加载的处理均使用LoadingDialog的实现子类。相关继承树(extend tree)如下图所示:
![](http://img1.51cto.com/attachment/201206/113408404.png)
b) LoadingDialog继承AsyncTask,这样的好处是容易控制流程的先后顺序,而且UI线程和其他线程的切换非常的平滑。其类的结构如下图所示:
![](http://img1.51cto.com/attachment/201206/113444845.png)
c) 定义
泛型的使用,代码如下:
public abstract class LoadingDialog<Input, Result> extends AsyncTask<Input, WSError, Result>
d) 流程
绘制其流程图如下:
![](http://img1.51cto.com/attachment/201206/075627884.jpg)
i. onPreExecute()
@Override public void onPreExecute() { String title = ""; String message = mActivity.getString(mLoadingMsg); mProgressDialog = ProgressDialog.show(mActivity, title, message, true, true, new OnCancelListener(){ @Override public void onCancel(DialogInterface dialogInterface) { LoadingDialog.this.cancel(true); } }); super.onPreExecute(); }
显示Dialog,这个创建方法第一次见到,Dialog可被cancel掉,代码如下:
@Override public void onCancelled() { if( mActivity instanceof PlayerActivity) { PlayerActivity pa = (PlayerActivity)mActivity; pa.doCloseActivity(); } failMsg(); super.onCancelled(); }
ii. doInBackground()-------抽象方法
这里是处理数据的地方,Jamendo在这里定义了抽象方法doInBackGround(),以应对不同的需求,子类各自实现即可。代码如下:
@Override public abstract Result doInBackground(Input... params);
iii. onPostExecute()
代码如下:
@Override public void onPostExecute(Result result) { super.onPostExecute(result); mProgressDialog.dismiss(); if(result != null){ doStuffWithResult(result); } else { if( mActivity instanceof PlayerActivity) { PlayerActivity pa = (PlayerActivity)mActivity; pa.doCloseActivity(); } failMsg(); } }
数据获取结束之后,Dialog dismiss掉。数据获取有两种情况:
l 获取数据正常
调用doStuffWithResult(Result result)方法处理数据,此方法为抽象方法,需要子类实现,按照自己的需求处理,代码如下:
/** * Very abstract function hopefully very meaningful name, * executed when result is other than null * * @param result * @return */ public abstract void doStuffWithResult(Result result);
l 获取数据异常
调用failMsg()方法。即Toast,代码如下:
protected void failMsg(){ Toast.makeText(mActivity, mFailMsg, 2000).show(); }
iv. onProgressUpdate()
显然,doInBackGround()方法中,可以实时的将一些信息(错误信息即WSError的Message)publish到本方法 。一旦出现问题:首先,toast,其次,取消本次异步任务,最后,Dialog dismiss掉。代码如下:
@Override protected void onProgressUpdate(WSError... values) { Toast.makeText(mActivity, values[0].getMessage(), Toast.LENGTH_LONG).show(); this.cancel(true); mProgressDialog.dismiss(); super.onProgressUpdate(values); }
2, 实现类SearchDialog(以此为例,说明其实现,只说明最重要的)
a) SearchActvity内容部分的布局,效果图,参看上面彩图。
布局虽是自定义ViewFlipper,我在实际使用中使用原生ViewFlipper也ok,Xml文件如下:
<com.teleca.jamendo.util.FixedViewFlipper android:id="@+id/SearchViewFlipper" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:background="#fff" > <ListView android:id="@+id/SearchListView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:divider="#000" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/no_results" > </TextView> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/search_list_hint" > </TextView> </com.teleca.jamendo.util.FixedViewFlipper>
b) 多态的使用
我是在这个类中深深体会多态的妙处。搜索有很多的分类,每一类可能对应不同的Adapter,那么对结果的处理就成了一个问题。在SearchDialog中定义BaseAdapter。对于所有的搜索结果的处理就smooth了。代码如下:
AlbumAdapter albumAdapter = new AlbumAdapter(SearchActivity.this); albumAdapter.setList(albums); albumAdapter.setListView(mSearchListView); mAdapter = albumAdapter;
c) 错误信息的捕获
Jamendo自己定义了Throwable类WSError,捕获Exception之后(就是主要的网络连接错误:请求异常,连接超时,下载超时等),将错误信息封装之后,向上抛出。分两步处理方式(以AlbumSearch为例):
第一步:catch
第二步:publishProgress
代码如下:
catch (JSONException e) { e.printStackTrace(); } catch (WSError e) { publishProgress(e); this.cancel(true); }
d) 对结果的处理
多态的使用,使得ListView的数据填充很easy。代码很清晰,不用作解释,代码如下:
@Override public void doStuffWithResult(Integer result) { mSearchListView.setAdapter(mAdapter); if(mSearchListView.getCount() > 0){ mViewFlipper.setDisplayedChild(0); // display results } else { mViewFlipper.setDisplayedChild(1); // display no results message } // results are albums if(mSearchMode.equals(0) || mSearchMode.equals(1) || mSearchMode.equals(3)){ mSearchListView.setOnItemClickListener(mAlbumClickListener); } // results are playlists if(mSearchMode.equals(2)){ mSearchListView.setOnItemClickListener(mPlaylistClickListener); } }
3, 搜索状态的保存
Jamendo对搜索状态的保存,是基于其的搜索页面是Activity之间的跳转。所以有必要保存。不做解释了,代码如下:
@SuppressWarnings("unchecked") @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { mSearchMode = (SearchMode) savedInstanceState.getSerializable("mode"); if(mSearchMode != null){ if(mSearchMode.equals(SearchMode.Artist) || mSearchMode.equals(SearchMode.Tag) || mSearchMode.equals(SearchMode.UserStarredAlbums)){ AlbumAdapter adapter = new AlbumAdapter(this); adapter.setList((ArrayList<Album>) savedInstanceState.get("values")); mSearchListView.setAdapter(adapter); mSearchListView.setOnItemClickListener(mAlbumClickListener); } if(mSearchMode.equals(SearchMode.UserPlaylist)) { PlaylistRemoteAdapter adapter = new PlaylistRemoteAdapter(this); adapter.setList((ArrayList<PlaylistRemote>) savedInstanceState.get("values")); mSearchListView.setAdapter(adapter); mSearchListView.setOnItemClickListener(mPlaylistClickListener); } mViewFlipper.setDisplayedChild(savedInstanceState.getInt("flipper_page")); } super.onRestoreInstanceState(savedInstanceState); } @Override protected void onSaveInstanceState(Bundle outState) {//保存上次的搜索结果,返回时还在 if(mSearchMode != null){ outState.putSerializable("mode", mSearchMode); if(mSearchMode.equals(SearchMode.Artist) || mSearchMode.equals(SearchMode.Tag) || mSearchMode.equals(SearchMode.UserStarredAlbums)){ AlbumAdapter adapter = (AlbumAdapter)mSearchListView.getAdapter(); outState.putSerializable("values", adapter.getList()); } if(mSearchMode.equals(SearchMode.UserPlaylist)) { PlaylistRemoteAdapter adapter = (PlaylistRemoteAdapter)mSearchListView.getAdapter(); outState.putSerializable("values", adapter.getList()); } outState.putInt("flipper_page", mViewFlipper.getDisplayedChild()); } super.onSaveInstanceState(outState); }
(三) 思考
前面的博文分析提到,Jamendo中有一个RequestCache,缓存10次请求。觉得意义不大,因为点开任意一个页面,滚动一下,很快就超过10个url请求。在Search这里,发现RequestCache的好处。搜索在短时间内,结果基本不会发生差别,所以阻止重复搜索很有必要。在实时性要求特别高的weibo里,RequestCache的使用也不用影响其刷新到最新数据,因为10次很容易超过,之前保留的刷新最新数据的老数据将被remove掉。
注:重构代码时,发现一个奇怪的问题,当前Activity有EditText(即有组件被focus到时),其继承的BaseActivity的无法显示showDialog()所对应的Dialog不会显示,但new出的Dialog可以显示。查看文档后,showDialog()方法不建议使用。文档如下:
本文出自 “小新专栏” 博客,请务必保留此出处http://mikewang.blog.51cto.com/3826268/885431
相关文章推荐
- Jamendo学习笔记之四:Home页面的实现
- Android异步加载学习笔记之二:实现ListView中的图片数据从网络加载
- 安卓智慧上海学习笔记系列——禁用ViewPager页面切换效果及不自动加载下一页数据
- Android 学习笔记之Volley(八)实现网络图片的数据加载
- Android菜鸟学习笔记(WebView加载html页面,页面提交数据问题)
- Android 学习笔记之Volley(七)实现Json数据加载和解析...
- Android异步加载学习笔记之三:用AsyncTask实现ListView中的图片数据加载
- JAVA学习笔记_JS实现刷新_重新加载页面
- ArcGIS实现矢量数据的拼接(学习笔记)
- 【Spring学习笔记-MVC-5】利用spring MVC框架,实现ajax异步请求以及json数据的返回
- 【数据分析 R语言实战】学习笔记 第八章 方差分析与R实现
- SilverLight学习笔记--使用WebClient实现通讯(一)(上传和下载字符串数据)
- ASP.Net MVC开发基础学习笔记(7):数据查询页面
- React-Native学习笔记 使用ListView加载网络数据
- angular实现页面数据动态加载
- OAF学习笔记-18- Update后页面显示不是最新的数据的解决方法
- 数据结构与算法学习笔记——动态规划的入门与编程实现
- Android 学习笔记之ContentProvider实现数据共享....
- Andorid学习笔记 :实现对ListView列表数据添加字母索引效果
- 摄像头驱动之实现数据传输5_调试_学习笔记