一、通过Socket、ServerSocket进行网络编程
Socket、ServerSocket编程方式可以说是比较底层的网络编程方式,其他的高级协议(如HTTP)都是建立在此基础之上的,而且Socket编程是跨平台的编程,可以在异构语言之间进行通信,所以掌握Socket网络编程是掌握其他网络编程方式的基础。
1、Socket、ServerSocket编程模型
在Socket编程模式中,Socket类用来建立客户端程序,ServerSocket类用来建立服务器端程序。首先,要有服务器端程序。通过ServerSocket建立服务器端程序,一般指定一个监听端口,用来等待客户端的连接。客户端Socket要指定服务器端的IP地址和端口号。一旦连接建立,ServerSocket就可以获得一个Socket实例,通过Socket打开输入、输出流进行通信。
2、Socket编程实例
一般Socket在Android中的编程应用中,Android都作为客户端,因为无线上网IP地址的分配是由移动运营公司动态分配的,没有固定IP所以不能作为服务器端来使用。下面的实例是通过Android建立Socket客户端连接ServerSocket服务器端实现简单的通信。
/**
* Socket服务器,响应Android客户端连接
*/
public class MyServer {
public static void main(String[] args) {
try {
//实例化服务器套接字
ServerSocket server = new ServerSocket(8888);
//永真循环
while(true){
//获得客户端套接字
Socket client = server.accept();
//获得输出流
OutputStream out = client.getOutputStream();
//输出字符串
String msg = "Hello Android!";
//写字符串
out.write(msg.getBytes());
//关闭输出流
client.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
socket.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/msgTextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="等待接受服务器消息..." />
</LinearLayout>
/**
* 客户端接受服务器消息
*/
public class MainActivity extends Activity {
private TextView MyText;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.socket);
MyText = (TextView) findViewById(R.id.msgTextView01);
try {
Socket socket = new Socket("192.168.1.101",8888);
InputStream in = socket.getInputStream();
byte[] buffer = new byte[in.available()];
in.read(buffer);
String msg = new String(buffer);
MyText.setText(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
二、通过URL进行网络编程
下面我们可以使用URL、URLConnection和HttpURLConnection进行URL网络连接,下面的实例要展示的是同URL连接、读取服务器的一张图片,并使用ImageView组件显示出来。
test_url.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/ImageView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
public class MainActivity extends Activity {
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_url);
imageView = (ImageView) findViewById(R.id.ImageView01);
//要显示的图标路径
String urlStr = "http://localhost:8080/tomcat.gif";
try {
//实例化URL
URL url = new URL(urlStr);
//1、直接使用URL获得输入流
//InputStream in = url.openStream();
//2、获得URLConnection
URLConnection conn = url.openConnection();
InputStream in = conn.getInputStream();
//3、如果是HTTP协议可以使用HttpURLConnection
// HttpURLConnection httpConn = (HttpsURLConnection)conn;
// in = httpConn.getInputStream();
//通过BitmapFactory获得Bitmap实例
Bitmap bm = BitmapFactory.decodeStream(in);
//为ImageView设置图片
imageView.setImageBitmap(bm);
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、通过HTTP进行网络编程
在Android中针对HTTP进行网络通信有两种:一是HttpURLConnection;二是ApacheHTTP客户端。
1、使用HttpURLConnection
如果我们知道访问资源的URL,并且是基于HTTP的,那么我们就可以使用HttpURLConnection进行请求/响应。
下面通过一个用户登录实例,来比较学习使用HttpURLConnection和使用ApacheHTTP客户端的异同
http1.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TableLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow>
<TextView
android:text="用户名称:"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/usernameEditText"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</TableRow>
<TableRow>
<TextView
android:text="用户密码:"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/passwordEditText"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</TableRow>
<TableRow android:gravity="right">
<Button
android:text="取消"
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="登录"
android:id="@+id/loginButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</TableRow>
</TableLayout>
</LinearLayout>
LoginServlet
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
response.setContentType("text/html");
((ServletRequest) response).setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String msg = null;
if(username != null && username.equals("admin") && password != null && password.equals("1")){
msg = "登录成功";
}else{
msg = "登录失败";
}
out.print(msg);
out.flush();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
Activity
public class MainActivity extends Activity {
private Button cancelBtn,loginBtn;
private EditText userEditText,pwdEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.http1);
cancelBtn = (Button) findViewById(R.id.cancelButton);
loginBtn = (Button) findViewById(R.id.loginButton);
userEditText = (EditText) findViewById(R.id.usernameEditText);
pwdEditText = (EditText) findViewById(R.id.passwordEditText);
//设置登录监听器
loginBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
String username = userEditText.getText().toString();
String password = pwdEditText.getText().toString();
login(username, password);
}
});
cancelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
//定义一个显示提示信息的对话框
private void showDialog(String msg){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(msg)
.setCancelable(false)
.setPositiveButton("确定",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
}
});
AlertDialog alert = builder.create();
alert.show();
}
//通过用户和密码进行查询,发送Post请求,获得响应结果
private void login(String username,String password){
//请求URL
String urlStr = "访问LoginServlet的路径+?";//Servlet
//查询字符串
String queryString = "username=" + username + "&password=" + password;
urlStr += queryString;
try {
//实例化URL
URL url = new URL(urlStr);
//获得HttpURLConnection实例
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//如果请求成功
if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
//获得输入流
InputStream in = conn.getInputStream();
//数组缓存
byte[] b = new byte[in.available()];
//读数据到缓存
in.read(b);
//转换为字符串
String msg = new String(b);
//显示对话框
showDialog(msg);
//关闭输入流
in.close();
}
//断开连接
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 使用Apache HTTP客户端
* 只是把login方法改写成了Apache HTTP Client,其他的都没有变化
* 改写后的方法如下login2
*/
private void login2(String username,String password){
String urlStr = "....../LoginServlet";
HttpPost request = new HttpPost(urlStr);
//如果传递参数个数比较多的话,我们可以对传递的参数进行封装
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", username));
params.add(new BasicNameValuePair("password", password));
try {
//设置请求参数项
request.setEntity(new UrlEncodedFormEntity(params,HTTP.UTF_8));
//执行请求返回响应
HttpResponse response = new DefaultHttpClient().execute(request);
//判断是否请求成功
if(response.getStatusLine().getStatusCode() == 200){
//获得响应消息
String msg = EntityUtils.toString(response.getEntity());
showDialog(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2、使用ApacheHTTP客户端
HTTP是一种请求/响应机制,在Servlet编程中我们会使用HttpServletRequest和HttpServletResponse表示请求和响应,ApacheHTTP客户端也对请求和响应进行封装,根据请求方法的不同,我们会用到HttpGet和HttpPost两个对象,响应对象是HttpResponse,使用DefaultHttpClient执行请求获得响应。
本实例在上面的实例基础上只是把login方法改写成使用Apache HTTP Client,其他都没有变化。代码详见上实例中的Activity的login2()方法。
四、通过Web Service进行网络编程
Web Service是实现异构程序之间方法调用的一种机制。Web Service通过一种XML格式的特殊文件来描述方法、参数、调用和返回值,这样格式的XML文件被称为WEDL(Web Service Description Language),即Web服务描述语言。Web Service采用的通信协议是SOAP(Simple Object Access Protocol),即简单对象访问协议。
Java领域的Web Service实现有很多种方式,例如sun公司的XML-RPC、Apache的Axis以及Codehaus的Xfire,但是这些都不适合在资源有限的移动设备中使用。早起的Java ME开发当中使用到了KSOAP。
下面我们将通过KSOAP和Apache HTTP客户端来实现一个天气预报。
1)、到Google的网站下载支持Android的KSOAP.jar文件
2)、将jar文件添加到工程的classpath下
weather.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:text="天气预报"
android:id="@+id/titleTextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:text="请选择城市"
android:id="@+id/cityTextView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/citySpinner01"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<ScrollView
android:id="@+id/ScrollView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/displayTextView03"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</ScrollView>
</LinearLayout>
WebServiceUtil.java
public class WebServiceUtil {
//使用KSOAP,获得城市列表
public static List<String> getCityList(){
//命名空间
String serviceNamespace = "http://WebXml.com.cn/";
//请求URL
String serviceURL = "http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx";
//调用方法
String methodName = "getRegionProvince";
//实例化SoapObject对象
SoapObject request = new SoapObject(serviceNamespace, methodName);
//获得序列化的Envelope
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = request;
(new MarshalBase64()).register(envelope);
//Android传输对象
@SuppressWarnings("deprecation")
AndroidHttpTransport ht = new AndroidHttpTransport(serviceURL);
ht.debug = true;
try {
//调用
ht.call("http://WebXml.com.cn/getRegionProvince", envelope);
if(envelope.getResponse() != null){
return parse(envelope.bodyIn.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//对得到的城市XMl信息进行解析
private static List<String> parse(String str){
String temp;
List<String> list = new ArrayList<String>();
if(str != null && str.length() > 0){
int start = str.indexOf("string");
int end = str.lastIndexOf(";");
temp = str.substring(start, end - 3);
String[] test = temp.split(";");
for (int i = 0; i < test.length; i++) {
if(i == 0){
temp = test[i].substring(7);
}else{
temp = test[i].substring(8);
}
int index = temp.indexOf(",");
list.add(temp.substring(0, index));
}
}
return list;
}
//通过传递城市名称获得天气信息
public static String getWeatherMsgByCity(String cityName){
String url = "http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx/getWeather";
HttpPost request = new HttpPost(url);
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("theCityCode", cityName));
params.add(new BasicNameValuePair("theUserID", ""));
String result = null;
try {
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,HTTP.UTF_8);
request.setEntity(entity);
HttpResponse response = new DefaultHttpClient().execute(request);
if(response.getStatusLine().getStatusCode() == 200){
result = EntityUtils.toString(response.getEntity());
return parse2(result);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//对天气信息XML文件进行解析
private static String parse2(String str){
String temp;
String[] temps;
List list = new ArrayList();
StringBuilder sb = new StringBuilder("");
if(str != null && str.length() > 0){
temp = str.substring(str.indexOf("<string>"));
temps = temp.split("</string>");
for (int i = 0; i < temps.length; i++) {
sb.append(temps[i].substring(12));
sb.append("\n");
}
}
return sb.toString();
}
}
Activity
public class WeatherActivity extends Activity{
private TextView displayTextView;
private Spinner spinner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.weather);
displayTextView = (TextView) findViewById(R.id.displayTextView03);
spinner = (Spinner) findViewById(R.id.citySpinner01);
List<String> citys = WebServiceUtil.getCityList();
ArrayAdapter a = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item,citys);
System.out.println("citys" + citys);
spinner.setAdapter(a);
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3) {
String msg = WebServiceUtil.getWeatherMsgByCity(spinner.getSelectedItem().toString());
displayTextView.setText(msg);
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
}
}
五、直接使用WebView视图组件显示网页
Android提供了内置的浏览器,该浏览器使用了开源的WEbKit引擎。在Android中使用浏览器需要通过WebView组件来实现。WebView提供了一些浏览器方法,例如,使用loadUrl()可以直接打开一个Web地址页面;使用loadData可以显示HTML格式的网页内容。
1、使用WebView打开网页
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<WebView
android:id="@+id/myWebView"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
public class TestWebViewActivity extends Activity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView) findViewById(R.id.myWebView);
// String url = "http://www.google.com";
// webView.loadUrl(url);
//使用WebView加载HTML
String html = "";
html += "<html>";
html += "<body>";
html += "<a href=http://www.google.com>Google Home</a>";
html += "</body>";
html += "</html>";
webView.loadData(html, "text/html", "utf-8");
}
}
2、使用WebView加载HTML
见上面的实例
loadData(String data, String mimeType, String encoding);