今天开始android网络编程,平时做的android整机开发这块,基本上不大需要接触android网络变成这块知识,还是得熟悉熟悉。
本文要讲的是使用URLConnection对象和HttpClient组件访问网络以及获取 网页内容的方法。
Android对HTTP(超文本传输协议)提供了很好的支持,这里包括两种接口:
1、标准Java接口(java.net) ----HttpURLConnection,可以实现简单的基于URL请求、响应功能;
2、Apache接口(org.appache.http)----HttpClient,使用起来更方面更强大。一般来说,用这种接口。不过本文还是把第一种接口过一下。
任何一种接口,无外乎四个基本功能:访问网页、下载图片或文件、上传文件.本文示范的是访问网页和下载图片。HttpURLConnection继承自URLConnection类,用它可以发送和接口任何类型和长度的数据,且预先不用知道数据流的长度,可以设置请求方式get或post、超时时间。
先直接上代码吧:
package com.example.webdatashow;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import android.R.string;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener{
private String TAG = "webdatashow";
private Button urlConnection;
private Button httpClient;
private TextView webDataShow;
private String pediyUrl = "http://bbs.pediy.com/forumdisplay.php?f=161";
private static final int MSG_SUCCESS = 0;
private static final int MSG_FAILURE = 1;
private Handler mHandler = null;
private Thread mThread;
private Thread httpClientThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webdata);
urlConnection = (Button)findViewById(R.id.urlConnection);
httpClient = (Button)findViewById(R.id.httpClient);
webDataShow = (TextView)findViewById(R.id.webDataShow);
urlConnection.setOnClickListener(this);
httpClient.setOnClickListener(this);
mHandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SUCCESS:
Toast.makeText(getApplicationContext(), "URLConnection 连接成功", Toast.LENGTH_SHORT).show();
webDataShow.setText((String)msg.obj);
break;
case MSG_FAILURE:
Toast.makeText(getApplicationContext(), "URLConnection 连接失败", Toast.LENGTH_SHORT).show();
default:
break;
}
}
};
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.urlConnection:
if(mThread == null)
{
mThread = new Thread(urlConnRunnable);
mThread.start();
}
break;
case R.id.httpClient:
if(httpClientThread == null)
{
httpClientThread = new Thread(httpClientRunnable);
httpClientThread.start();
}
break;
default:
break;
}
}
Runnable httpClientRunnable = new Runnable() {
@Override
public void run() {
httpClientWebData();
}
};
Runnable urlConnRunnable = new Runnable() {
@Override
public void run() {
try {
urlConGetWebData();
} catch (IOException e) {
e.printStackTrace();
}
}
};
private void urlConGetWebData() throws IOException {
URL url = new URL(pediyUrl);
HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();
if(httpConn.getResponseCode() == HttpURLConnection.HTTP_OK)
{
Log.d("TAG", "---into-----urlConnection---success--");
InputStreamReader isr = new InputStreamReader(httpConn.getInputStream(), "utf-8");
int i;
String content = "";
while((i = isr.read()) != -1)
{
content = content + (char)i;
}
mHandler.obtainMessage(MSG_SUCCESS,content).sendToTarget();
isr.close();
httpConn.disconnect();
}else
{
Log.d("TAG", "---into-----urlConnection---fail--");
}
}
protected void httpClientWebData() {
DefaultHttpClient httpClinet = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(pediyUrl);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
try {
String content = httpClinet.execute(httpGet, responseHandler);
mHandler.obtainMessage(MSG_SUCCESS,content).sendToTarget();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/urlConnection"
android:layout_width="fill_parent"
android:layout_height="60dip"
android:text="urlConnection"
/>
<Button
android:id="@+id/httpClient"
android:layout_width="fill_parent"
android:layout_height="60dip"
android:text="httpClient"
/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/webDataShow"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</ScrollView>
</LinearLayout>
做这个需要注意几点:
1,访问网络,记得添加权限
<uses-permission android:name="android.permission.INTERNET" />
2,使用Http协议错误:java.net.MalformedURLException: no protocol:
错误原因就是这是http请求,需要在请求地址上加入 http://协议
3,android.os.NetworkOnMainThreadException
这个异常大概意思是在主线程访问网络时出的异常。 Android在4.0之前的版本 支持在主线程中访问网络,但是在4.0以后对这部分程序进行了优化,也就是说访问网络的代码不能写在主线程中了。
4,android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程(MainThread),主线程负责处理和ui相关的事件,因此主线程通常又叫UI线程。而由于Android采用UI单线程模型,所以只能在主线程中对UI元素进行操作。如果在非UI线程直接对UI进行了操作,则会报错:
CalledFromWrongThreadException:only the original thread that created a view hierarchy can touch its views
。
Android为我们提供了消息循环的机制,我们可以利用这个机制来实现线程间的通信。那么,我们就可以在非UI线程发送消息到UI线程,最终让Ui线程来进行ui的操作。
对于运算量较大的操作和IO操作,我们需要新开线程来处理这些繁重的工作,以免阻塞ui线程
备注:
这两种方法分别采用HttpClient和URLConnection,好像是HttpClient方式比较稳定,一般都能下载到,但是URLConnection在EDGE网络下经常下不到数据。
来源:oschina
链接:https://my.oschina.net/u/273541/blog/213355