1. 程式人生 > >基於Android的小巫新聞客戶端開發--主介面業務邏輯實現

基於Android的小巫新聞客戶端開發--主介面業務邏輯實現

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

基於Android的小巫新聞客戶端開發--主介面業務邏輯實現

 上一篇介紹了主介面的UI設計,現在直接進入主題,業務邏輯的實現,由於專案的開發總是在不斷的完善的,最初實現的效果,總會隨專案的進度而做出相應的改變,小巫也不可能從新開發整個客戶端,然後再一步一步記錄,那沒有必要,學習東西,只需要知道關鍵點在哪裡就行了,關於細節方面,遇到再去解決。就是這麼簡單。

 

主介面的最終實現效果如下;

  

 

下面是MainActivity.java的程式碼

package com.xiaowu.news;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import org.json.JSONArray;import org.json.JSONObject;import android.app.Activity;import android.content.Intent;import android.graphics.Color;import
android.graphics.drawable.ColorDrawable;import android.os.AsyncTask;import android.os.Bundle;import android.view.Gravity;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import
android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.Button;import android.widget.GridView;import android.widget.HorizontalScrollView;import android.widget.LinearLayout;import android.widget.LinearLayout.LayoutParams;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.SimpleAdapter;import android.widget.TextView;import android.widget.Toast;import com.xiaowu.news.custom.ConstomSimpleAdapter;import com.xiaowu.news.model.Category;import com.xiaowu.news.service.SyncHttp;import com.xiaowu.news.update.UpdateManager;import com.xiaowu.news.util.DensityUtil;import com.xiaowu.news.util.StringUtil;/** *  * @author wwj *  */public class MainActivity extends Activity private final int COLUMNWIDTH_PX = 56;     // GridView每個單元格的寬度(畫素) private final int FLINGVELOCITY_PX = 800;    // ViewFilper滑動的距離(畫素) private final int NEWSCOUNT = 5;      // 顯示新聞的條數 private final int SUCCESS = 0;      // 載入新聞成功 private final int NONEWS = 1;      // 沒有新聞 private final int NOMORENEWS = 2;     // 沒有更多新聞 private final int LOADERROR = 3;     // 載入失敗 private long exitTime;        //按返回鍵退出的時間 private int mColumnWidth_dip;       private int mFlingVelocity_dip; private int mCid;          // 新聞編號 private String mCategoryTitle;      // 新聞分類標題 private ListView mNewslist;       // 新聞列表 private SimpleAdapter mNewslistAdapter;    // 為新聞內容提供需要顯示的列表 private ArrayList<HashMap<String, Object>> mNewsData; // 儲存新聞資訊的資料集合 private LayoutInflater mInflater;      // 用來動態載入沒有loadmore_layout介面  private Button category_Button = null;    // 新聞分類標題欄的向右檢視的按鈕  private HorizontalScrollView categoryScrollView = null;// 水平滾動圖 private Button mTitleBarRefresh;     // 標題欄的重新整理按鈕 private ProgressBar mTitleBarProgress;    // 進度條 private Button mLoadmoreButton;      // 載入更多按鈕 private LoadNewsAsyncTack mLoadNewsAsyncTack;  // 宣告LoadNewsAsyncTack引用  @Override public void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.news_home_layout);    //通過id來獲取按鈕的引用  mTitleBarRefresh = (Button) findViewById(R.id.titlebar_refresh);  mTitleBarProgress = (ProgressBar) findViewById(R.id.titlebar_progress);    mTitleBarRefresh.setOnClickListener(loadmoreListener);  // 將px轉換為dip  mColumnWidth_dip = DensityUtil.px2dip(this, COLUMNWIDTH_PX);  mFlingVelocity_dip = DensityUtil.px2dip(this, FLINGVELOCITY_PX);  //初始化新聞分類的編號  mCid = 1;  mCategoryTitle = "焦點";  mInflater = getLayoutInflater();  //儲存新聞資訊的資料集合  mNewsData = new ArrayList<HashMap<String, Object>>();  // 獲取陣列資源  String[] categoryArray = getResources().getStringArray(    R.array.categories);  // 定義一個List陣列,用來存放HashMap物件  final List<HashMap<String, Category>> categories = new ArrayList<HashMap<String, Category>>();  // 分割新聞字串  for (int i = 0; i < categoryArray.length; i++) {   String temp[] = categoryArray[i].split("[|]");   if (temp.length == 2) {    int cid = StringUtil.string2Int(temp[0]);    String title = temp[1];    Category type = new Category(cid, title);    // 定義一個HashMap物件,用來存放鍵值對    HashMap<String, Category> hashMap = new HashMap<String, Category>();    hashMap.put("category_title", type);    categories.add(hashMap);   }  }  ConstomSimpleAdapter categoryAdapter = new ConstomSimpleAdapter(this,    categories, R.layout.category_item_layout,    new String[] { "category_title" },    new int[] { R.id.category_title });  // 建立一個網格檢視, 用於實現新聞標題的佈局  GridView category = new GridView(this);  // 設定單元格的背景色為透明,這樣選擇分類時就不會顯示黃色背景了  category.setSelector(new ColorDrawable(Color.TRANSPARENT));  // 設定每一個新聞標題的寬度  category.setColumnWidth(mColumnWidth_dip);  // 設定網格檢視的列數  category.setNumColumns(GridView.AUTO_FIT);  // 設定對齊方式  category.setGravity(Gravity.CENTER);  // 根據單元格的寬度和數目計算網格檢視的寬度  int width = mColumnWidth_dip * categories.size();  // 獲取佈局引數  LayoutParams params = new LayoutParams(width, LayoutParams.MATCH_PARENT);  // 設定引數  category.setLayoutParams(params);  // 設定Adapter  category.setAdapter(categoryAdapter);  // 通過ID獲取LinearLayout佈局物件  LinearLayout categoryLayout = (LinearLayout) findViewById(R.id.category_layout);  // 將網格檢視元件新增到LinearLayout佈局當中  categoryLayout.addView(category);  // 新增單元格點選事件  category.setOnItemClickListener(new OnItemClickListener() {   TextView categoryTitle;   @Override   public void onItemClick(AdapterView<?> parent, View view,     int position, long id) {    // TODO Auto-generated method stub    for (int i = 0; i < parent.getCount(); i++) {     categoryTitle = (TextView) parent.getChildAt(i);     categoryTitle.setTextColor(0XFFADB2AD);     categoryTitle.setBackgroundDrawable(null);    }    categoryTitle = (TextView) view;    categoryTitle.setTextColor(0xFFFFFFFF);    categoryTitle      .setBackgroundResource(R.drawable.image_categorybar_item_selected_background);    Toast.makeText(MainActivity.this, categoryTitle.getText(),      Toast.LENGTH_SHORT).show();    //獲取新聞分類編號    mCid = categories.get(position).get("category_title").getCid();    mCategoryTitle = categories.get(position).get("category_title").getTitle();    mLoadNewsAsyncTack = new LoadNewsAsyncTack();    mLoadNewsAsyncTack.execute(0, true);   }  });    //第一次獲取新聞列表  getSpecCatNews(mCid, mNewsData, 0, true);  // 箭頭  categoryScrollView = (HorizontalScrollView) findViewById(R.id.categorybar_scrollView);  category_Button = (Button) findViewById(R.id.category_arrow_right);  category_Button.setOnClickListener(new OnClickListener() {   @Override   public void onClick(View v) {    // TODO Auto-generated method stub    categoryScrollView.fling(mFlingVelocity_dip);   }  });  mNewslistAdapter = new SimpleAdapter(this, mNewsData,    R.layout.newslist_item_layout, new String[] {      "newslist_item_title", "newslist_item_digest",      "newslist_item_source", "newslist_item_ptime" },    new int[] { R.id.newslist_item_title,      R.id.newslist_item_digest, R.id.newslist_item_source,      R.id.newslist_item_ptime });  mNewslist = (ListView) findViewById(R.id.news_list);    View footerView = mInflater.inflate(R.layout.loadmore_layout, null);  //在LiseView下面新增“載入更多”  mNewslist.addFooterView(footerView);  //顯示列表  mNewslist.setAdapter(mNewslistAdapter);    mNewslist.setOnItemClickListener(new OnItemClickListener() {   @Override   public void onItemClick(AdapterView<?> parent, View view,     int position, long id) {    // TODO Auto-generated method stub    Intent intent = new Intent(MainActivity.this,      NewsDetailActivity.class);    intent.putExtra("categoryTitle", mCategoryTitle);    intent.putExtra("newsData", mNewsData);    intent.putExtra("position", position);    startActivity(intent);   }  });  mLoadmoreButton = (Button) findViewById(R.id.loadmore_btn);  mLoadmoreButton.setOnClickListener(loadmoreListener);   } /**  * 獲取指定型別的新聞列表  *   * @param cid  * @return  */ private int getSpecCatNews(int cid, List<HashMap<String, Object>> newsList,   int startnid, boolean firstTime) {  // 如果是第一次載入的話  if (firstTime) {   newsList.clear();  }  //本機:http://10.0.2.2:8080/web/getSpecifyCategoryNews  //wifi區域網:192.168.220.1  String url = "http://10.0.2.2:8080/web/getSpecifyCategoryNews";  String params = "startnid=" + startnid + "&count=" + NEWSCOUNT    + "&cid=" + cid;  SyncHttp syncHttp = new SyncHttp();  try {   // 通過Http協議傳送Get請求,返回字串   String retStr = syncHttp.httpGet(url, params);   JSONObject jsonObject = new JSONObject(retStr);   int retCode = jsonObject.getInt("ret");   if (retCode == 0) {    JSONObject dataObj = jsonObject.getJSONObject("data");    // 獲取返回數目    int totalNum = dataObj.getInt("totalnum");    if (totalNum > 0) {     // 獲取返回新聞集合     JSONArray newslistArray = dataObj.getJSONArray("newslist");     // 將用JSON格式解析的資料新增到資料集合當中     for (int i = 0; i < newslistArray.length(); i++) {      JSONObject newsObject = (JSONObject) newslistArray        .opt(i);      HashMap<String, Object> hashMap = new HashMap<String, Object>();      hashMap.put("nid", newsObject.getInt("nid"));      hashMap.put("newslist_item_title",        newsObject.getString("title"));      hashMap.put("newslist_item_digest",        newsObject.getString("digest"));      hashMap.put("newslist_item_source",        newsObject.getString("source"));      hashMap.put("newslist_item_ptime",        newsObject.getString("ptime"));      hashMap.put("newslist_item_comments",        newsObject.getInt("commentcount"));      newsList.add(hashMap);     }     return SUCCESS;    } else {     //第一次載入新聞列表     if (firstTime) {      return NONEWS;   //沒有新聞     } else {      return NOMORENEWS;  //沒有更多新聞     }    }   } else {    return LOADERROR;   //載入新聞失敗   }  } catch (Exception e) {   // TODO Auto-generated catch block   e.printStackTrace();   return LOADERROR;   //載入新聞失敗  } } /**  * 為“載入更多”按鈕定義匿名內部類  */ private OnClickListener loadmoreListener = new OnClickListener() {  @Override  public void onClick(View v) {   mLoadNewsAsyncTack = new LoadNewsAsyncTack();   switch (v.getId()) {   //點選載入更多   case R.id.loadmore_btn:    mLoadNewsAsyncTack.execute(mNewsData.size(), false); //不是第一次載入新聞裡列表    break;   //點選重新整理按鈕   case R.id.titlebar_refresh:    mLoadNewsAsyncTack.execute(0, true);    break;   }  } }; /**  * 非同步更新UI  * @author wwj  *  */ private class LoadNewsAsyncTack extends AsyncTask<Object, Integer, Integer> {  //準備執行  @Override  protected void onPreExecute() {   mTitleBarRefresh.setVisibility(View.GONE);   mTitleBarProgress.setVisibility(View.VISIBLE);   mLoadmoreButton.setText(R.string.loadmore_text);  }  //在後臺執行  @Override  protected Integer doInBackground(Object... params) {   return getSpecCatNews(mCid, mNewsData, (Integer) params[0],     (Boolean) params[1]);  }  //完成後臺任務  @Override  protected void onPostExecute(Integer result) {   switch (result) {   //該欄目沒有新聞   case NONEWS:    Toast.makeText(MainActivity.this, R.string.nonews, Toast.LENGTH_SHORT)      .show();    break;   //該欄目沒有更多新聞   case NOMORENEWS:    Toast.makeText(MainActivity.this, R.string.nomorenews,      Toast.LENGTH_SHORT).show();    break;   //載入失敗   case LOADERROR:    Toast.makeText(MainActivity.this, R.string.loadnewserror, Toast.LENGTH_SHORT)      .show();    break;   }   mTitleBarRefresh.setVisibility(View.VISIBLE);   //重新整理按鈕設定為可見   mTitleBarProgress.setVisibility(View.GONE);    //進度條設定為不可見   mLoadmoreButton.setText(R.string.loadmore_btn);   //按鈕資訊替換為“載入更多”   mNewslistAdapter.notifyDataSetChanged();    //通知ListView更新資料  } }  /**  * 新增選單  */ @Override public boolean onCreateOptionsMenu(Menu menu) {  // TODO Auto-generated method stub  menu.add(1, 1, 1, "更新");  menu.add(1, 2, 2, "退出");  return true; }  @Override public boolean onOptionsItemSelected(MenuItem item) {  switch(item.getItemId()) {  case 1:   UpdateManager updateManager = new UpdateManager(MainActivity.this);   //檢測更新   updateManager.checkUpdate();   break;  case 2:   finish();   break;  }  return true; }  /**  * 按鍵觸發的事件  */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) {  if(keyCode == KeyEvent.KEYCODE_BACK       && event.getAction() == KeyEvent.ACTION_DOWN){      if((System.currentTimeMillis() - exitTime > 2000)){       Toast.makeText(getApplicationContext(), R.string.backcancel         , Toast.LENGTH_LONG).show();       exitTime = System.currentTimeMillis();      }      else{       finish();       System.exit(0);      }      return true;     }  return super.onKeyDown(keyCode, event); }}


 

主介面的業務邏輯實現,要一步就實現是非常困難的,因為專案總是從簡單到複雜,所以小巫只把關鍵點說一下就行了:

這裡主要有三個關鍵點:

1.分類欄的實現?

首先建立一個GridView檢視,通過GridView來填充資料,把每一類新聞分類顯示到GridView檢視中去,最後通過獲取到介面佈局中的LinearLayout物件,把GridView新增到LinearLayout佈局當中去,最終實現效果。

2.獲取新聞分類列表(對JSON格式資料的解析)?

JSON資料的解析並不算太難,主要把JSON資料的資料結構搞清楚,解析起來還是挺方便的。

進行解析雖然方便,但前提是要把資料得到,因為資料是要在伺服器端得到,需要利用Android的Http通訊來實現。

這裡需要利用到httpGet還有httpPost方法,這個程式碼很需要貼一貼滴。自定義的SyncHttp類

package com.xiaowu.news.service;import java.util.ArrayList;import java.util.List;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.client.HttpClient;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.message.BasicNameValuePair;import org.apache.http.params.BasicHttpParams;import org.apache.http.params.HttpConnectionParams;import org.apache.http.params.HttpParams;import org.apache.http.protocol.HTTP;import org.apache.http.util.EntityUtils;import com.xiaowu.news.model.Parameter;public class SyncHttp /**  * 通過Get方式傳送請求  * @param url  * @param params  * @return  * @throws Exception  */ public String httpGet(String url, String params) throws Exception {  String response = null//返回資訊  //拼接請求URl  if(null != params && !params.equals("")) {   url += "?" + params;  }    int timeOutConnection = 3000;  int timeOutSocket = 5000;   HttpParams httpParams = new BasicHttpParams();  HttpConnectionParams.setConnectionTimeout(httpParams, timeOutConnection);  HttpConnectionParams.setSoTimeout(httpParams, timeOutSocket);    //構造HttpClient例項  HttpClient httpClient = new DefaultHttpClient();  //建立GET方法例項  HttpGet httpGet = new HttpGet(url);  try {   HttpResponse httpResponse = httpClient.execute(httpGet);   int statusCode = httpResponse.getStatusLine().getStatusCode();   if(statusCode == HttpStatus.SC_OK) {    //獲得返回結果    response = EntityUtils.toString(httpResponse.getEntity());   }   else{    response = "返回碼:" + statusCode;   }  } catch (Exception e) {   // TODO: handle exception   throw new Exception(e);  }  return response; }  /**  * 通過post方式傳送請求  * @param url  * @param params  * @return  * @throws Exception  */ public String httpPost(String url, List<Parameter> params) throws Exception {  String response  = null;  int timeOutConnection = 3000;  int timeOutSocket = 5000;   HttpParams httpParams = new BasicHttpParams();  HttpConnectionParams.setConnectionTimeout(httpParams, timeOutConnection);  HttpConnectionParams.setSoTimeout(httpParams, timeOutSocket);      //構造HttpClient例項  HttpClient httpClient = new DefaultHttpClient();  HttpPost httpPost = new HttpPost(url);  if(params.size() > 0) {   //設定post請求引數   httpPost.setEntity(new UrlEncodedFormEntity(buildNameValuePair(params), HTTP.UTF_8));  }    //使用execute方法傳送Http Post 請求,並返回HttpResponse物件  HttpResponse httpResponse = httpClient.execute(httpPost);    int statusCode = httpResponse.getStatusLine().getStatusCode();  if(statusCode == HttpStatus.SC_OK) {   //獲得返回結果   response = EntityUtils.toString(httpResponse.getEntity());  }  else {   response = "返回碼:" + statusCode;  }  return response; }   /**  * 把Paramster型別集合轉換為NameValuePair型別集合  * @param params  * @return  */ private List<BasicNameValuePair> buildNameValuePair (List<Parameter> params) {  List<BasicNameValuePair> result = new ArrayList<BasicNameValuePair>();  for(Parameter param : params) {   BasicNameValuePair pair = new BasicNameValuePair(param.getName(), param.getValue());   result.add(pair);  }  return result; }}

定義好了SyncHttp類之後,就可以通過呼叫httpGet方法來獲取資料,在Activity的getSpecCatNews方法有詳細實現,看一下就可以知道了。

3.非同步更新UI的實現?

關於非同步更新UI也算是一個比較難理解的東西,在Activity裡定義了一個繼承AsyncTask類的內部類,並實現三個方法,比較靈活。具體實現看程式碼。

 

以上三點是小巫認為比較核心的地方,具體的需要動手之後才知道。

 

 

 

 

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述