求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
基于Android的小巫新闻客户端开发--主界面业务逻辑实现
 

.发布于2013-3-5,来源:CSDN

 

现在直接进入主题,业务逻辑的实现,由于项目的开发总是在不断的完善的,最初实现的效果,总会随项目的进度而做出相应的改变,小巫也不可能从新开发整个客户端,然后再一步一步记录,那没有必要,学习东西,只需要知道关键点在哪里就行了,关于细节方面,遇到再去解决。就是这么简单。

主界面的最终实现效果如下;

下面是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类的内部类,并实现三个方法,比较灵活。具体实现看代码。

以上三点是小巫认为比较核心的地方,具体的需要动手之后才知道。



 
分享到
 
 


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...