今天来进行数据(从开源中国服务器上面get新闻信息)的联网获取,关键步骤就是应用android-async-http框架,输入向服务器post的参数,异步获得服务器的数据。接着异步解析成adapter可以用的ListEntity<T>格式,在ListView中展示出来。
一、定义基类ListBaseAdapter文件
核心数据是mDatas,后面的关键代码就是从服务器获取数据,并将XML异步解析,添加到mDatas中,最后在ListView中展示。获取服务器数据用到了android-async-http框架。这个ListBaseAdapter文件用于存放ListView数据适配的公共方法。
protected ArrayList<T> mDatas = new ArrayList<T>();
@Override
public int getCount() {
return getDataSize();
}
@Override
public Object getItem(int pos) {
if(mDatas.size()>pos)
return mDatas.get(pos);
return null;
}
@SuppressWarnings("deprecation")
@SuppressLint("InflateParams")
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
return getRealView(pos, convertView, parent);
}
public int getDataSize() {
return mDatas.size();
}
protected View getRealView(int position, View convertView, ViewGroup parent) {
return null;
}
public ArrayList<T> getData() {
return mDatas == null ? (mDatas = new ArrayList<T>()) : mDatas;
}
//将转换的数据,添加到mDatas
public void addData(List<T> data) {
if (mDatas != null && data != null && !data.isEmpty()) {
mDatas.addAll(data);
}
notifyDataSetChanged();
Log.i("a", "ss");
}
二、展示新闻数据的适配文件-NewsAdapter
继承于ListBaseAdapter,具体的对layout中的控件进行赋值。
@SuppressLint("InflateParams")
@Override
protected View getRealView(int position, View convertView, ViewGroup parent) {
ViewHolder vh = null;
if (convertView == null || convertView.getTag() == null) {
convertView = getLayoutInflater(parent.getContext()).inflate(
R.layout.list_cell_news, null);
vh = new ViewHolder(convertView);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
News news = mDatas.get(position);
vh.title.setText(news.getTitle());
//给里面的各个控件赋值
………………………………………………………
}
三、Fragment类型文件的界面-BaseListFragment
1、概述
下面为BaseListFragment文件的代码:
public abstract class BaseListFragment<T extends Entity> extends BaseFragment implements
OnItemClickListener, OnScrollListener,SwipeRefreshLayout.OnRefreshListener {
@InjectView(R.id.listview)
protected ListView mListView;
protected ListBaseAdapter<T> mAdapter;
protected abstract ListBaseAdapter<T> getListAdapter();
private ParserTask mParserTask;
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.inject(this, view);
//初始化界面
initView(view);
}
@Override
public void initView(View view) {
mSwipeRefreshLayout.setOnRefreshListener(this);
mListView.setOnItemClickListener(this);
mListView.setOnScrollListener(this);
if (mAdapter != null) {
mListView.setAdapter(mAdapter);
} else {
//根据不同的list 不同子类有不同geiListAdapter的实现
mAdapter = getListAdapter();
mListView.setAdapter(mAdapter);
//获取数据地方
requestData(false);
}
}
2、定义handler处理服务器传回的数据
接收请求结果,一般重写onSuccess及onFailure接收请求成功或失败的消息,还有onStart,onFinish等消息。当接收到服务器传来的信息后,如果成功调用 executeParserTask(responseBytes)方法。向服务器post数据的操作、android-async-http框架的使用在后面介绍,数据请求在NewsFragment文件中执行。
protected AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers,
byte[] responseBytes) {
executeParserTask(responseBytes);
}
}
private void executeParserTask(byte[] data) {
cancelParserTask();
mParserTask = new ParserTask(data);
mParserTask.execute();
}
3、继承于AsyncTask的异步解析任务-ParserTask
- doInBackground(Params…) 后台执行,用来写耗时操作,但这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以 调用publicProgress(Progress…)来更新任务的进度。
- onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回
class ParserTask extends AsyncTask<Void, Void, String> {
private final byte[] reponseData;
private boolean parserError;
private List<T> list;
//从服务器获取的数据保存在形参中,传进来赋值给responseData
public ParserTask(byte[] data) {
this.reponseData = data;
}
@Override
protected String doInBackground(Void... params) {
try {
//解析数据为ListEntity格式
ListEntity<T> data = parseList(new ByteArrayInputStream(
reponseData));
list = data.getList();
} catch (Exception e) {
e.printStackTrace();
parserError = true;
}
return null;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//将数据赋值到mAdapter,在ListView中展示
mAdapter.addData(data);
}
}
四、新闻获取展示界面-NewsFragment
1、概述
根据类的不同,这里发出向服务器获取数据的请求,赋值不同的adapter(这里为NewsAdapter)。因为BlogFragment(从服务器获取博客数据)和NewsFragment同继承于BaseListFragment<T>,所以该类要反映出它们的差异。
/**
* @function 综合-资讯/热点界面
*/
public class NewsFragment extends BaseListFragment<News> {
protected static final String TAG = NewsFragment.class.getSimpleName();
//之前使用的是 在外部定义adapter作为参数传进来
@Override
protected ListBaseAdapter<News> getListAdapter() {
return new NewsAdapter();
}
//解析List
@Override
protected NewsList parseList(InputStream is) throws Exception {
NewsList list = null;
try {
list = XmlUtils.toBean(NewsList.class, is);
} catch (NullPointerException e) {
list = new NewsList();
}
return list;
}
@Override
protected void sendRequestData() {
//mHandler在BaseListFragment中定义,mHandler监测从服务器中获取的数据
OSChinaApi.getNewsList(mCatalog, mCurrentPage, mHandler);
}
}
2、定义用于传递参数获取数据的接口
为获取新闻制定接口。
/**
* 获取新闻列表
* @param catalog
* 类别 (1,2,3)
* @param page
* 第几页
* @param handler
*/
public static void getNewsList(int catalog, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("catalog", catalog);
params.put("pageIndex", page);
params.put("pageSize", 20);//默认分页
if (catalog == NewsList.CATALOG_WEEK) {
params.put("show", "week");
} else if (catalog == NewsList.CATALOG_MONTH) {
params.put("show", "month");
}
//第一个参数为相对地址
ApiHttpClient.get("action/api/news_list", params, handler);
}
3、Android-Async-Http架构的使用
Android- Async-Http的使用非常简单,通过AsyncHttpClient发起请求就可以了,如果需要添加参数,直接传一个RequestParams过 去,而且参数可以是String、File和InputStream,可以很方便地上传文件。在上面的接口,就是用于为AsyncHttpClient准备的。
每个请求都需要传一个ResponseHandlerInterface的实例用以接收请求结果或请求失败,请求结束等通知,一般是AsyncHttpResponseHandler的子类。
基本用法:
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
@Override
public void onSuccess(String response) {
System.out.println(response);
}
});
开源中国源码中,将AsyncHttpResponseHandler的就收请求结果放到了BaseListFragment中,前面介绍过。
public class ApiHttpClient {
public static AsyncHttpClient client;
private static String API_URL = "http://www.oschina.net/%s";
public final static String HOST = "www.oschina.net";
public static void get(String partUrl, AsyncHttpResponseHandler handler) {
//一般的方法中handler为 new AsyncHttpResponseHandler()
client.get(getAbsoluteApiUrl(partUrl), handler);
log(new StringBuilder("GET ").append(partUrl).toString());
}
/*
* 到时候注意handler的触发和来源
*/
public static void get(String partUrl, RequestParams params,
AsyncHttpResponseHandler handler) {
client.get(getAbsoluteApiUrl(partUrl), params, handler);
log(new StringBuilder("GET ").append(partUrl).append("&")
.append(params).toString());
}
public static String getAbsoluteApiUrl(String partUrl) {
String url = String.format(API_URL, partUrl);
Log.d("BASE_CLIENT", "request:" + url);
return url;
}
//配置网络信息
public static void setHttpClient(AsyncHttpClient c) {
client = c;
client.addHeader("Accept-Language", Locale.getDefault().toString());
client.addHeader("Host", HOST);
client.addHeader("Connection", "Keep-Alive");
client.getHttpClient().getParams()
.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
setUserAgent(ApiClientHelper.getUserAgent(AppContext.getInstance()));
}
}
4、存储系统信息的全局类-AppContext
AppContext类继承于Application,Application是android框架的一个系统组件,当android程序启动时系统会创建一个 application对象,用来存储系统的一些信息。android系统会为每个程序运行时创建一个Application类的对象且仅创建一个,所以Application可以说是单例 (singleton)模式的一个类.且application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。
在这里初始化网络请求。
public class AppContext extends BaseApplication{
//BaseApplication继承于Application
private static AppContext instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
init();
}
private void init() {
// 初始化网络请求
AsyncHttpClient client = new AsyncHttpClient();
ApiHttpClient.setHttpClient(client);
}
}
demo图片展示,就这一个界面。demo地址 开源中国源码学习数据篇(一)之android-async-http框架和AsyncTask 。
Android- Async-Http的使用非常简单,通过AsyncHttpClient发起请求就可以了,如果需要添加参数,直接传一个RequestParams过 去,而且参数可以是String、File和InputStream,可以很方便地上传文件。在上面的接口,就是用于为AsyncHttpClient准备的。
每个请求都需要传一个ResponseHandlerInterface的实例用以接收请求结果或请求失败,请求结束等通知,一般是AsyncHttpResponseHandler的子类。
基本用法:
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://www.google.com", new AsyncHttpResponseHandler() {
@Override
public void onSuccess(String response) {
System.out.println(response);
}
});
public class ApiHttpClient {
public static AsyncHttpClient client;
private static String API_URL = "http://www.oschina.net/%s";
public final static String HOST = "www.oschina.net";
public static void get(String partUrl, AsyncHttpResponseHandler handler) {
//一般的方法中handler为 new AsyncHttpResponseHandler()
client.get(getAbsoluteApiUrl(partUrl), handler);
log(new StringBuilder("GET ").append(partUrl).toString());
}
/*
* 到时候注意handler的触发和来源
*/
public static void get(String partUrl, RequestParams params,
AsyncHttpResponseHandler handler) {
client.get(getAbsoluteApiUrl(partUrl), params, handler);
log(new StringBuilder("GET ").append(partUrl).append("&")
.append(params).toString());
}
public static String getAbsoluteApiUrl(String partUrl) {
String url = String.format(API_URL, partUrl);
Log.d("BASE_CLIENT", "request:" + url);
return url;
}
//配置网络信息
public static void setHttpClient(AsyncHttpClient c) {
client = c;
client.addHeader("Accept-Language", Locale.getDefault().toString());
client.addHeader("Host", HOST);
client.addHeader("Connection", "Keep-Alive");
client.getHttpClient().getParams()
.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
setUserAgent(ApiClientHelper.getUserAgent(AppContext.getInstance()));
}
}
4、存储系统信息的全局类-AppContext
public class AppContext extends BaseApplication{
//BaseApplication继承于Application
private static AppContext instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
init();
}
private void init() {
// 初始化网络请求
AsyncHttpClient client = new AsyncHttpClient();
ApiHttpClient.setHttpClient(client);
}
}