基於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")
- @Override
- public void handleMessage(Message msg) {
- // TODO Auto-generated method stub
- switch (msg.arg1) {
- case FINISH:
- //把獲取到的新聞顯示到界面上
- ArrayList<HashMap<String, Object>> bodyList = (ArrayList<HashMap<String, Object>>) msg.obj;
- mNewsBodyDetail.setText(bodyList);
- break;
- }
- }
- };
- @SuppressWarnings("unchecked")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.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 {
- @Override
- public void onClick(View v) {
- InputMethodManager m = (InputMethodManager) mNewsReplyEditText.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- // TODO Auto-generated method stub
- switch (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 {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // TODO Auto-generated method stub
- switch (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 {
- @Override
- public void run() {
- // TODO Auto-generated method stub
- ArrayList<HashMap<String, Object>> newsStr = getNewsBody();
- Message msg = mHandler.obtainMessage(); //獲取msg
- msg.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:8080
- String 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 exception
- e.printStackTrace();
- }
- return bodylist;
- }
- @Override
- public boolean onCreatePanelMenu(int featureId, Menu menu) {
- // TODO Auto-generated method stub
- menu.add(0, 0, 0, "分享");
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // TODO Auto-generated method stub
- switch(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。
關於上面的代碼已經實現得比較完善了,不知道是否還可以進行優化。
那麼關於新聞詳細內容顯示的業務邏輯實現就寫到這裏,然後關於小巫新聞客戶端開發的系列博客就暫時記錄到這裏,感謝網友們的支持。因爲新聞回覆的內容具體實現沒什麼可說的,只要把前面的業務邏輯實現弄懂了,新聞回覆的業務邏輯也就沒什麼難的。
如果網友們對小巫新聞客戶端那部分有疑問,可以給我留言,小巫會把自己知道的東西都寫出來。