构建Android中的数据业务应用,Android提供了几种网络访问方式: 移动IP网络(GPRS,基于移动网络的数据应用层 ),WiFi,蓝牙。这里讨论的是基于第一种方式的网络应用。Android主要提供了java.net和org.apache.httpclient两个包来处理相关的网络应用,另外还有android.net这个包,它只是对org.apache.httpclient进行了简单的封装,所以重点介绍apache包的应用,当然也会对java.net作简单介绍。
1:检查网络连接状态
Android提供各种后台Service以便我们可以获得系统共用对象的实例,ConectivityManager是用来检查网络连接的类,下面代码是它通用使用方法:
ConnectivityManager mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
2:Android中简单的Http访问
首先通过一个简单的例子使用标准的Java.net API 通过Http Get方法来从指定URL获得一个简单的Html流。Http Get请求只需要把查询参数放入请求的URL中,
private String getHttpResponse(String location) {
String result = null;
URL url = null;
try {
url = new URL(location); //构造一个URL对象
} catch (MalformedURLException e) {
Log.e(Constants.LOGTAG, “ERROR”, e);
}
if (url != null) {
try {
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); //使用HttpURLConnection打开连接
BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));//为输出创建BufferedReader
String inputLine;
int lineCount = 0; // limit the lines for the example
while ((lineCount < 10) && ((inputLine = in.readLine()) != null)) { //读Response中的数据
lineCount++;
result += "\n" + inputLine; #6
}
in.close();
urlConn.disconnect();
} catch (IOException e) {
Log.e(Constants.LOGTAG, “ERROR”, e);
}
} else {
Log.e(Constants.LOGTAG, " url NULL");
}
return result;
}
}
通过上面可以看到,通过Http访问数据在Anroid是很容易的,但是在实际应用中,通常都是复杂频繁的网络请求访问而不是如例子中简单的获取数据,如果这样的话,例子中的做法就会变得很笨重,为了对Java.net中的类可以被更好的使用,apache提供了HttpClient,它对Java.net中的类做了封装和更好的抽象,用来支持设计更复杂的Http应用,而且能在独立的线程上处理这些请求。
3:使用HttpClient
这个例子展示了怎样把网络访问请求运行的独立的线程之中,它使用了Apache的ResponseHandler和Android Handler。
private final Handler handler = new Handler() { //创建一个Android Handler
@Override
public void handleMessage(final Message msg) {
progressDialog.dismiss();
String bundleResult = msg.getData().getString("RESPONSE");//在Handler内部来处理刷新UI
ApacheHTTPSimple.this.output.setText(bundleResult);
}
};
private void performRequest() {
final ResponseHandler<String> responseHandler = new ResponseHandler<String>() { //使用ResponseHandler来创建一个异步的Http调用
public String handleResponse(HttpResponse response) {//实现OnResponse的回调函数
StatusLine status = response.getStatusLine();
HttpEntity entity = response.getEntity();//获得Response的Entity
String result = null;
try {
result = StringUtils.inputStreamToString(entity.getContent());
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("RESPONSE", result);
message.setData(bundle);
handler.sendMessage(message); //向UI handler发送消息,把Http请求的数据传递给UI进程
} catch (IOException e) {}
return result;
}
};
this.progressDialog = ProgressDialog.show(this, "working . . .", "performing HTTP request");
new Thread() {//使用一个独立线程进行Http请求
@Override
public void run() {
try {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpMethod = new HttpGet(ApacheHTTPSimple.this.urlChooser.getSelectedItem().toString());//根据URL创建一个HttpGet对象
client.execute(httpMethod, responseHandler); //通过HttpClient运行HttpGet
} catch (ClientProtocolException e) {
Log.e(Constants.LOGTAG, " " + ApacheHTTPSimple.CLASSTAG, e);
} catch (IOException e) {
Log.e(Constants.LOGTAG, " " + ApacheHTTPSimple.CLASSTAG, e);
}
}
}.start();
}
以下是结构示意图
现在我们已经了解了HttpClient的使用和基本的访问方法, 为了避免重复的创建代码,基于一个稳定的Http访问模型,下面通过分析WebKit的Http访问架构,来展现一个可以兼容Http Get ,Post,多任务而且容易管理结构模型。
4: WebKit中Http访问架构解析
下面是模型结构图:
把Http Request行为抽象到一个单例中,通过HttpClient进行Get或者Post访问。
Code
public class NetworkManager {
private static NetworkManager sInstance = null;
private Context mContext = null;
private DefaultHttpClient mHttpClient = null;
protected String mCookie=null;
private NetworkManager(Context context) {
mContext = context;
mHttpClient = new DefaultHttpClient();
}
public static synchronized NetworkManager getInstance(Context context) {
if (null == sInstance) {
sInstance = new NetworkManager(context);
}
return sInstance;
}
public boolean requestURL(String method, String url, Map<String, String> headers,
byte[] body, AbstractHttpHandler handler) {
//Check URL
if (!URLUtil.isValidUrl(url)) {
Log.e(TAG, "Invalid URL:" + url);
handler.error(-1, "Invalid URL:" + url);
return false;
}
Log.d(TAG, "requestURL:" + url);
//Http Request
HttpUriRequest request = null;
if (HttpGet.METHOD_NAME.equalsIgnoreCase(method)) {
//HttpGet
request = new HttpGet(url);
} else {
//HttpPost
if (null != body && body.length > 0) {
Log.d(TAG, "Request Entity:" + body.toString());
//post.setEntity(new InputStreamEntity(new ByteArrayInputStream(body), body.length));
post.setEntity(new ByteArrayEntity(body));
}
request = post;
}
//Http Headers
addHeaders(request, headers);
//Cookie
request.addHeader("cookie", this.mCookie);
handler.setNetworkManager(this);
//Cache it
handler.setCachedRequestParam(method, url, headers, body);
//Connection Timeout
HttpParams hp = mHttpClient.getParams();
if(null != hp) {
ConnManagerParams.setTimeout(hp, 5000);
}
//Execute Request
try {
HttpResponse response = mHttpClient.execute(request);
//Handle Response
handler.handleResponse(response);
} catch(Exception e) {
e.printStackTrace();
}
return true;
}
public void setCookie(String cookies){
this.mCookie=cookies;
}
}
每个Task负责开启一个访问线程,与UI线程的交互都由Task来完成
Code
public abstract class AbstractTask implements Runnable {
private final static String TAG = "AbstractTask";
public final static int TASK_FINISHED = 1000;
protected Context mContext = null;
protected Handler mCallback = null;
private boolean mIsCanceled = false;
private int mTaskType=0;
public final static int ERROR_NO_ERROR = 0;
public final static int ERROR_FAILED = 1;
public final static int ERROR_RESPONSE_XML = 1000;
public final static int ERROR_RESQUEST_XML = 1001;
public final static int RESPONSE_STATUS_SUCCESS = 0;
protected int mErrorCode = ERROR_NO_ERROR;
protected String mErrorMsg = "";
public AbstractTask(Context context, Handler callback) {
mContext = context;
mCallback = callback;
}
protected synchronized void finishedCallback() {
if (null != mCallback && !isCanceled()) {
Log.d(TAG, "finishedCallback");
Message msg = mCallback.obtainMessage(TASK_FINISHED, this);
mCallback.sendMessage(msg);
mCallback = null;
}
}
public synchronized void cancel() {
mIsCanceled = true;
}
public synchronized boolean isCanceled() {
return mIsCanceled;
}
protected void setError(int code, String msg) {
mErrorCode = code;
mErrorMsg = msg;
}
public int getErrorCode() {
return mErrorCode;
}
public String getErrorMsg() {
return mErrorMsg;
}
public String formatErrMsg() {
return "" + mErrorMsg + "(" + mErrorCode + ")";
}
public Handler getCallbackHandler() {
return mCallback;
}
public int getTaskType()
{
return mTaskType;
}
public void setTaskType(int type){
mTaskType=type;
}
public void run() {
}
}
//类似于ResponseHandler
Code
public abstract class AbstractTask implements Runnable {
private final static String TAG = "AbstractTask";
public final static int TASK_FINISHED = 1000;
protected Context mContext = null;
protected Handler mCallback = null;
private boolean mIsCanceled = false;
private int mTaskType=0;
public final static int ERROR_NO_ERROR = 0;
public final static int ERROR_FAILED = 1;
public final static int ERROR_RESPONSE_XML = 1000;
public final static int ERROR_RESQUEST_XML = 1001;
public final static int RESPONSE_STATUS_SUCCESS = 0;
protected int mErrorCode = ERROR_NO_ERROR;
protected String mErrorMsg = "";
public AbstractTask(Context context, Handler callback) {
mContext = context;
mCallback = callback;
}
protected synchronized void finishedCallback() {
if (null != mCallback && !isCanceled()) {
Log.d(TAG, "finishedCallback");
Message msg = mCallback.obtainMessage(TASK_FINISHED, this);
mCallback.sendMessage(msg);
mCallback = null;
}
}
public synchronized void cancel() {
mIsCanceled = true;
}
public synchronized boolean isCanceled() {
return mIsCanceled;
}
protected void setError(int code, String msg) {
mErrorCode = code;
mErrorMsg = msg;
}
public int getErrorCode() {
return mErrorCode;
}
public String getErrorMsg() {
return mErrorMsg;
}
public String formatErrMsg() {
return "" + mErrorMsg + "(" + mErrorCode + ")";
}
public Handler getCallbackHandler() {
return mCallback;
}
public int getTaskType()
{
return mTaskType;
}
public void setTaskType(int type){
mTaskType=type;
}
public void run() {
}
}
//Demo Task,继承AbstractTask
Code
public abstract class AbstractTask implements Runnable {
private final static String TAG = "AbstractTask";
public final static int TASK_FINISHED = 1000;
protected Context mContext = null;
protected Handler mCallback = null;
private boolean mIsCanceled = false;
private int mTaskType=0;
public final static int ERROR_NO_ERROR = 0;
public final static int ERROR_FAILED = 1;
public final static int ERROR_RESPONSE_XML = 1000;
public final static int ERROR_RESQUEST_XML = 1001;
public final static int RESPONSE_STATUS_SUCCESS = 0;
protected int mErrorCode = ERROR_NO_ERROR;
protected String mErrorMsg = "";
public AbstractTask(Context context, Handler callback) {
mContext = context;
mCallback = callback;
}
protected synchronized void finishedCallback() {
if (null != mCallback && !isCanceled()) {
Log.d(TAG, "finishedCallback");
Message msg = mCallback.obtainMessage(TASK_FINISHED, this);
mCallback.sendMessage(msg);
mCallback = null;
}
}
public synchronized void cancel() {
mIsCanceled = true;
}
public synchronized boolean isCanceled() {
return mIsCanceled;
}
protected void setError(int code, String msg) {
mErrorCode = code;
mErrorMsg = msg;
}
public int getErrorCode() {
return mErrorCode;
}
public String getErrorMsg() {
return mErrorMsg;
}
public String formatErrMsg() {
return "" + mErrorMsg + "(" + mErrorCode + ")";
}
public Handler getCallbackHandler() {
return mCallback;
}
public int getTaskType()
{
return mTaskType;
}
public void setTaskType(int type){
mTaskType=type;
}
public void run() {
}
}
//TaskManager负责创建Task,管理Task
Code
public abstract class AbstractTask implements Runnable {
private final static String TAG = "AbstractTask";
public final static int TASK_FINISHED = 1000;
protected Context mContext = null;
protected Handler mCallback = null;
private boolean mIsCanceled = false;
private int mTaskType=0;
public final static int ERROR_NO_ERROR = 0;
public final static int ERROR_FAILED = 1;
public final static int ERROR_RESPONSE_XML = 1000;
public final static int ERROR_RESQUEST_XML = 1001;
public final static int RESPONSE_STATUS_SUCCESS = 0;
protected int mErrorCode = ERROR_NO_ERROR;
protected String mErrorMsg = "";
public AbstractTask(Context context, Handler callback) {
mContext = context;
mCallback = callback;
}
protected synchronized void finishedCallback() {
if (null != mCallback && !isCanceled()) {
Log.d(TAG, "finishedCallback");
Message msg = mCallback.obtainMessage(TASK_FINISHED, this);
mCallback.sendMessage(msg);
mCallback = null;
}
}
public synchronized void cancel() {
mIsCanceled = true;
}
public synchronized boolean isCanceled() {
return mIsCanceled;
}
protected void setError(int code, String msg) {
mErrorCode = code;
mErrorMsg = msg;
}
public int getErrorCode() {
return mErrorCode;
}
public String getErrorMsg() {
return mErrorMsg;
}
public String formatErrMsg() {
return "" + mErrorMsg + "(" + mErrorCode + ")";
}
public Handler getCallbackHandler() {
return mCallback;
}
public int getTaskType()
{
return mTaskType;
}
public void setTaskType(int type){
mTaskType=type;
}
public void run() {
}
}
//在UI主线程里,启动一个请求Task,
Task mTask = new DemoTask(mContext, mHandler);
TaskManager.getInstance().startTask(mTask);
下面是负责在Task与UI主进程交互的Handler
private final Handler mHandler = new Handler() { //创建一个Android Handler
@Override
public void handleMessage(final Message msg) {
switch(msg.what) {
case AbstractTask.TASK_FINISHED:
DemoTask task = (DemoTask) msg.obj;//在Handler内部来处理刷新UI
}
};