基于Android的小巫新闻客户端开发---显示新闻详细内容业务逻辑实现

2013年2月27日,继续小巫新闻客户端的开发。

上一篇忘记谈及一个比较重要的内容,有些网友留言给小巫问:Json数据的明细是怎样的?,在这里小巫先声明一点,小巫对Json数据的格式也是刚接触,这是稍微知道其的结构组成,关于是否尤其内容并不是很清楚。但小巫对与怎么进行JSON格式的解析已经比较清晰了。下面就接这篇博客来介绍一下,新闻详细内容的JSON数据是怎样的,通过浏览器得到的数据到底是怎样的。

如果得到小巫所共享的资源的话,服务端的项目是一个叫web的JavaEE项目,如果有看过里面的具体实现的话,读者可能就会明白,服务端是如何与数据库进行交互的了。那好,部署好项目到Tomcat中,在浏览器就可以得到相应的JSON数据源。

获取新闻详细内容的Servlet代码如下:注:(这是服务端的代码),关于解析JSON数据的解析,在介绍客户端业务逻辑实现的时候会说明。

package com.szy.web.servlet;import java.io.IOException;import java.io.PrintWriter;import java.util.ArrayList;import java.util.HashMap;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.json.JSONException;import org.json.JSONObject;import sun.reflect.generics.reflectiveObjects.NotImplementedException;import com.szy.web.dao.CommentDAO;import com.szy.web.dao.NewsDAO;import com.szy.web.model.News;import com.szy.web.util.TextUtility;/** *@author coolszy *@date Feb 19, 2012 *@blog http://blog.92coding.com *http://localhost:8080/web/getNews?nid=1 */public class GetNewsServlet extends HttpServlet{private static final long serialVersionUID = -7715894432269979527L;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{response.setContentType("text/html;charset=UTF-8");String nidStr= request.getParameter("nid");int nid = 0;nid = TextUtility.String2Int(nidStr);JSONObject jObject = new JSONObject();try{CommentDAO commentDAO = new CommentDAO();long commentCount = commentDAO.getSpecifyNewsCommentsCount(nid);NewsDAO newsDAO = new NewsDAO();News news = newsDAO.getNews(nid);JSONObject jObject2 = new JSONObject();if (!TextUtility.isNull(news.getTitle())){HashMap<String, Object> hashMap = new HashMap<String, Object>();/***************后期增加代码,主要用于测试TextView显示图片功能********************/String newsbody = news.getBody();ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String,Object>>();HashMap<String, Object> hashMap1 = new HashMap<String, Object>();hashMap1.put("index", 0);hashMap1.put("type", "image");hashMap1.put("value", "http://www.eportfolio.wtuc.edu.tw/blog/attach/35/16035/95/bf_22696_7751198_66497_4.jpg");HashMap<String, Object> hashMap2 = new HashMap<String, Object>();hashMap2.put("index", 1);hashMap2.put("type", "text");hashMap2.put("value", newsbody);list.add(hashMap1);list.add(hashMap2);/********************************************************/hashMap.put("nid", news.getNid());hashMap.put("title", news.getTitle());//hashMap.put("body", news.getBody());hashMap.put("body", list);hashMap.put("source", news.getSource());hashMap.put("replycount", commentCount);hashMap.put("ptime", news.getPtime());hashMap.put("imgsrc", news.getImgSrc());jObject2.put("news", hashMap);}jObject.put("ret", 0);jObject.put("msg", "ok");jObject.put("data", jObject2);} catch (Exception e){e.printStackTrace();try{jObject.put("ret", 1);jObject.put("msg", e.getMessage());jObject.put("data", "");} catch (JSONException ex){ex.printStackTrace();}}PrintWriter out = response.getWriter();out.println(jObject);out.flush();out.close();}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{throw new NotImplementedException();}}

这就是服务端从数据库获取新闻详细内容的Servlet,当然这只是Servlet的代码,查询数据库的代码需要到web项目查看。

在浏览器敲入如下URL:http://localhost:8080/web/getNews?nid=2

就会得到数据nid为2的新闻内容如下:

{"ret":0,"data":{"news":{"body":[{"index":0,"value":"http://www.eportfolio.wtuc.edu.tw/blog/attach/35/16035/95/bf_22696_7751198_66497_4.jpg","type":"image"},{"index":1,"value":"

新华网十八大快讯:党的十八届一中全会选举习近平、李克强、张德江、俞正声、刘云山、王岐山、张高丽为中央政治局常委。<\/p>","type":"text"}],"title":"党的十八届一中全会选举习近平、李克强、张德江、俞正声、刘云山、王岐山、张高丽为中央政治局常委 ","source":"来源: 新华网","nid":2,"replycount":1,"ptime":"2012年11月15日 11:45:36"}},"msg":"ok"}

这样看是比较乱的,需要将这些数据进行一下格式化,看起来比较舒服。

{  "ret": 0,   "data": {    "news": {      "body": [        {          "index": 0,           "value": "http://www.eportfolio.wtuc.edu.tw/blog/attach/35/16035/95/bf_22696_7751198_66497_4.jpg",           "type": "image"        },         {          "index": 1,           "value": " <p>新华网十八大快讯:党的十八届一中全会选举习近平、李克强、张德江、俞正声、刘云山、王岐山、张高丽为中央政治局常委。</p>",           "type": "text"        }      ],       "title": "党的十八届一中全会选举习近平、李克强、张德江、俞正声、刘云山、王岐山、张高丽为中央政治局常委 ",       "source": "来源: 新华网",       "nid": 2,       "replycount": 1,       "ptime": "2012年11月15日 11:45:36"    }  },   "msg": "ok"}


那好,关于JSON数据的明细,就说到这里。从格式化的JSON数据是可以很清楚得到新闻的组成结构的,接下来就是要在客户端解析这些数据,并把它们显示到手机界面上,这才是我们花那么大功夫去解析JSON数据的原因。

贴上代码之前,当然需要看一下最终需要实现的效果图:

关于这个界面我就不做过多的说明了,最重要的是具体实现。

package com.xiaowu.news;import java.io.Serializable;import java.util.ArrayList;import java.util.HashMap;import org.json.JSONArray;import org.json.JSONObject;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnTouchListener;import android.view.inputmethod.InputMethodManager;import android.widget.Button;import android.widget.EditText;import android.widget.ImageButton;import android.widget.LinearLayout;import android.widget.TextView;import android.widget.Toast;import android.widget.ViewFlipper;import com.xiaowu.news.service.SyncHttp;import com.xiaowu.news.thread.PostCommentsThread;public class NewsDetailActivity extends Activity {private final int FINISH = 0;//代表线程的状态的结束private LayoutInflater mNewsbodyLayoutInflater;private ViewFlipper mNewsBodyFlipper;//屏幕切换控件private ArrayList<HashMap<String, Object>> mNewsData;private float mStartX;//手指按下的开始位置private int mPosition = 0;//点击新闻位置private int mCursor = 0;//用来标记新闻点击的位置private int mNid;//新闻编号private Button mNewsDetailTitleBarComm;//显示评论条数的按钮private ConstomTextView mNewsBodyDetail;//新闻详细内容private LinearLayout mNewsReplyEditLayout;//新闻回复的布局private LinearLayout mNewsReplyImgLayout;//新闻图片回复的布局private EditText mNewsReplyEditText;//新闻回复的文本框private ImageButton mShareNewsButton;//分享新闻的按钮private ImageButton mFavoritesButton;//收藏新闻的按钮private boolean keyboardShow;//键盘是否显示private Handler mHandler = new Handler() {@SuppressWarnings("unchecked")@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubswitch (msg.arg1) {case FINISH://把获取到的新闻显示到界面上ArrayList<HashMap<String, Object>> bodyList = (ArrayList<HashMap<String, Object>>) msg.obj;mNewsBodyDetail.setText(bodyList);break;}}};@SuppressWarnings("unchecked")@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.newsdetails_layout);mNewsReplyEditLayout = (LinearLayout) findViewById(R.id.news_reply_edit_layout);mNewsReplyImgLayout = (LinearLayout) findViewById(R.id.news_reply_img_layout);Button newsDetailPrev = (Button) findViewById(R.id.newsdetail_titlebar_previous);Button newsDetailNext = (Button) findViewById(R.id.newsdetail_titlebar_next);mNewsDetailTitleBarComm = (Button) findViewById(R.id.newsdetail_titlebar_comments);mNewsReplyEditText = (EditText) findViewById(R.id.news_reply_edittext);mShareNewsButton = (ImageButton) findViewById(R.id.news_share_btn);mFavoritesButton = (ImageButton) findViewById(R.id.news_favorites_btn);NewsDetailOnClickListener newsDetailOnClickListener = new NewsDetailOnClickListener();newsDetailPrev.setOnClickListener(newsDetailOnClickListener);newsDetailNext.setOnClickListener(newsDetailOnClickListener);mNewsDetailTitleBarComm.setOnClickListener(newsDetailOnClickListener);mShareNewsButton.setOnClickListener(newsDetailOnClickListener);mFavoritesButton.setOnClickListener(newsDetailOnClickListener);Button newsReplyPost = (Button) findViewById(R.id.news_reply_post);newsReplyPost.setOnClickListener(newsDetailOnClickListener);ImageButton newsReplyImgBtn = (ImageButton) findViewById(R.id.news_reply_img_btn);newsReplyImgBtn.setOnClickListener(newsDetailOnClickListener);//获取传送的数据Intent intent = getIntent();Bundle bundle = intent.getExtras();String categoryName = bundle.getString("categoryTitle");TextView titleBarTitle = (TextView) findViewById(R.id.newsdetail_titlebar_title);//设置标题栏的标题titleBarTitle.setText(categoryName);//获取新闻集合Serializable serializable = bundle.getSerializable("newsData");mNewsData = (ArrayList<HashMap<String, Object>>) serializable;//获取点击位置mCursor = mPosition = bundle.getInt("position");mNewsBodyFlipper = (ViewFlipper) findViewById(R.id.news_body_flipper);// 获取LayoutInflater对象mNewsbodyLayoutInflater = getLayoutInflater();inflateView(0);//启动线程new UpdateNewsThread().start();}/** * 显示上一条新闻 */private void showPrevious() {if(mPosition > 0) {mPosition--;//记录当前新闻编号HashMap<String, Object> hashMap = mNewsData.get(mPosition);mNid = (Integer) hashMap.get("nid");if(mCursor > mPosition){mCursor = mPosition;inflateView(0);mNewsBodyFlipper.showNext();}mNewsBodyFlipper.setInAnimation(this, R.anim.push_right_in);//设置下一页进来时的动画mNewsBodyFlipper.setOutAnimation(this, R.anim.push_right_out);//设置当前页出去的动画mNewsBodyFlipper.showPrevious();}else {Toast.makeText(NewsDetailActivity.this, "没有上一篇新闻", Toast.LENGTH_SHORT).show();}}/** * 显示下一条新闻 */private void showNext() {if(mPosition < mNewsData.size() - 1){// 设置下一屏动画mNewsBodyFlipper.setInAnimation(this, R.anim.push_left_in);mNewsBodyFlipper.setOutAnimation(this, R.anim.push_left_out);mPosition++;//记录当前新闻编号HashMap<String, Object> hashMap = mNewsData.get(mPosition);mNid = (Integer) hashMap.get("nid");if(mPosition >= mNewsBodyFlipper.getChildCount()){inflateView(mNewsBodyFlipper.getChildCount());}mNewsBodyFlipper.showNext();} else {Toast.makeText(NewsDetailActivity.this, "没有下篇新闻", Toast.LENGTH_SHORT).show();}}private void inflateView(int index) {//获取点击新闻信息HashMap<String, Object> hashMap = mNewsData.get(mPosition);mNid = (Integer) hashMap.get("nid");View mNewsBodyView = mNewsbodyLayoutInflater.inflate(R.layout.newsbody_layout, null);mNewsDetailTitleBarComm.setText(hashMap.get("newslist_item_comments").toString() + "跟帖");//新闻标题TextView newsTitle = (TextView) mNewsBodyView.findViewById(R.id.news_body_title);newsTitle.setText(hashMap.get("newslist_item_title").toString());//新闻的出处和发布时间TextView newsPtimeAndSource = (TextView) mNewsBodyView.findViewById(R.id.news_body_ptime_source);newsPtimeAndSource.setText(hashMap.get("newslist_item_source").toString() + "" + hashMap.get("newslist_item_ptime").toString());mNewsBodyDetail = (ConstomTextView) mNewsBodyView.findViewById(R.id.news_body_details);mNewsBodyDetail.setText(getNewsBody());mNewsBodyFlipper.addView(mNewsBodyView, index);mNewsBodyDetail.setOnTouchListener(new NewsBodyOntouchListener());}// 定义内部类--用于处理标题栏的按钮的触发事件private class NewsDetailOnClickListener implements OnClickListener {@Overridepublic void onClick(View v) {InputMethodManager m = (InputMethodManager) mNewsReplyEditText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);// TODO Auto-generated method stubswitch (v.getId()) {//上一篇case R.id.newsdetail_titlebar_previous:showPrevious();break;//下一篇case R.id.newsdetail_titlebar_next:showNext();break;//跟帖case R.id.newsdetail_titlebar_comments:Intent intent = new Intent(NewsDetailActivity.this,CommentsActivity.class);intent.putExtra("nid", mNid);startActivity(intent);break;//“写跟帖”图片case R.id.news_reply_img_btn:mNewsReplyEditLayout.setVisibility(View.VISIBLE);mNewsReplyImgLayout.setVisibility(View.GONE);mNewsReplyEditText.requestFocus();//显示输入法m.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);keyboardShow = true;break;//分享按钮case R.id.news_share_btn:Intent shareIntent = new Intent(Intent.ACTION_SEND);//纯文本shareIntent.setType("text/plain");shareIntent.putExtra(Intent.EXTRA_SUBJECT, "分享");shareIntent.putExtra(Intent.EXTRA_TEXT, "我想将这个分享给你...."+ getTitle());startActivity(Intent.createChooser(shareIntent, getTitle()));break;//收藏按钮case R.id.news_favorites_btn:Toast.makeText(NewsDetailActivity.this, "收藏成功", Toast.LENGTH_SHORT).show();break;//发表按钮case R.id.news_reply_post://隐藏输入法m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);String str = mNewsReplyEditText.getText().toString();if(str.equals("")){Toast.makeText(NewsDetailActivity.this, "不能为空",Toast.LENGTH_SHORT).show();}else {mNewsReplyEditLayout.post(new PostCommentsThread(mNid, "广州市",str + "",new NewsDetailActivity()));mNewsReplyEditLayout.setVisibility(View.GONE);mNewsReplyImgLayout.setVisibility(View.VISIBLE);}break;}}}private class NewsBodyOntouchListener implements OnTouchListener {@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction()) {//手指按下case MotionEvent.ACTION_DOWN:if(keyboardShow){mNewsReplyEditLayout.setVisibility(View.GONE);mNewsReplyImgLayout.setVisibility(View.VISIBLE);//隐藏输入法InputMethodManager m = (InputMethodManager) mNewsReplyEditText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);keyboardShow = false;}//得到按下的横坐标的位置mStartX = event.getX();break;case MotionEvent.ACTION_UP:// 往左滑动if (event.getX() < mStartX) {showNext();}// 往右滑动else if (event.getX() > mStartX) {showPrevious();}break;}return true;}}/** * 定义一个线程类,用来更新获取到新闻的信息 * @author Administrator * */private class UpdateNewsThread extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubArrayList<HashMap<String, Object>> newsStr = getNewsBody();Message msg = mHandler.obtainMessage();//获取msgmsg.arg1 = FINISH;msg.obj = newsStr;mHandler.sendMessage(msg);//给Handler发送信息}}/** * 获取新闻详细信息 * @return */private ArrayList<HashMap<String, Object>> getNewsBody(){//String retStr = "网络连接失败,请稍后再试";ArrayList<HashMap<String, Object>> bodylist = new ArrayList<HashMap<String,Object>>();SyncHttp syncHttp = new SyncHttp();//模拟器:url = "http://10.0.2.2:8080/web/getNews";//本机:http://127.0.0.1:8080//wifi局域网:http://192.168.220.1:8080String url = "http://10.0.2.2:8080/web/getNews";String params = "nid=" + mNid;try {String retString = syncHttp.httpGet(url, params);JSONObject  jsonObject = new JSONObject(retString);//获取返回码,0表示成功int retCode = jsonObject.getInt("ret");if(retCode == 0) {JSONObject dataObject = jsonObject.getJSONObject("data");JSONObject newsObject = dataObject.getJSONObject("news");//retStr = newsObject.getString("body");JSONArray bodyArray = newsObject.getJSONArray("body");for(int i = 0; i < bodyArray.length(); i++) {JSONObject object = (JSONObject) bodyArray.opt(i);HashMap<String, Object> hashMap = new HashMap<String, Object>();hashMap.put("index", object.get("index"));hashMap.put("type", object.get("type"));hashMap.put("value", object.get("value"));bodylist.add(hashMap);}}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}return bodylist;}@Overridepublic boolean onCreatePanelMenu(int featureId, Menu menu) {// TODO Auto-generated method stubmenu.add(0, 0, 0, "分享");return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// TODO Auto-generated method stubswitch(item.getItemId()) {case 0:Intent shareIntent = new Intent(Intent.ACTION_SEND);//纯文本shareIntent.setType("text/plain");shareIntent.putExtra(Intent.EXTRA_SUBJECT, "分享");shareIntent.putExtra(Intent.EXTRA_TEXT, "我想把这个分享给你:" + getTitle());shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(Intent.createChooser(shareIntent, getTitle()));System.out.println(getTitle());break;}return super.onOptionsItemSelected(item);}}


这段代码设计到以下几个关键点:

1.异步更新新闻详细内容。 这里是用Handler来实现线程异步。

2.实现上下篇新闻切换的功能。

3.自定义TextView的实现类ConstomTextView。

关于上面的代码已经实现得比较完善了,不知道是否还可以进行优化。

那么关于新闻详细内容显示的业务逻辑实现就写到这里,然后关于小巫新闻客户端开发的系列博客就暂时记录到这里,感谢网友们的支持。因为新闻回复的内容具体实现没什么可说的,只要把前面的业务逻辑实现弄懂了,新闻回复的业务逻辑也就没什么难的。

如果网友们对小巫新闻客户端那部分有疑问,可以给我留言,小巫会把自己知道的东西都写出来。

更多相关文章

  1. Android拍照或从系统相册获取图片
  2. 基于Android小巫新闻客户端开发---显示新闻详细内容UI设计
  3. Assets 与 Res android的两大资源的获取 与android studio中asse
  4. Android分享笔记(3)Android(安卓)使用存放在存assets文件夹下的S
  5. android集成Umeng推送获取不到device_token也收不到消息,但是在Um
  6. Android获取usb上的U盘存储路径
  7. Android实时获取音量(单位:分贝)
  8. Android-如何稳定获取IMEI1、IMEI2、MEID,以及获取其他设备ID闲谈
  9. Android按钮控制加减,,(购物车中的加减器)

随机推荐

  1. 【python】字符串输出和输入
  2. 新手衣服怎么绘画?板绘画衣服教程!
  3. 如何学手绘插画?零基础学手绘动漫技巧!
  4. iOS调试Block引用对象无法被释放的小技巧
  5. 深入垂直业务场景,SaaS版供应商业务协同平
  6. 淘宝移动端首页的商品列表
  7. 淘宝移动端首页的商品列表
  8. 详解MacOs免密登录CentOs操作步骤
  9. iOS组件依赖避免冲突的小技巧分享
  10. 移动端布局学习小结与实践