PS:看了9年的小说,自己开始动手写了一本,请各位猿们动动手指,点击下,有起点账号的可以收藏下!!《武意长存》
Android 为我们提供了两种访问网络的方式:
一、 HttpURLConnection
二、 HttpClient
当然,除了以上两种,还有其它一些封装好的框架,我们可以很方便的拿来使用,比如android-async-http,以及Google提供的Volley
现在,先来看看如何使用HttpURLConnection对网络资源进行访问
首先,我们先自己搭个简单的后台,用来验证用户登录
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String username = request.getParameter("username");
String password = request.getParameter("password");
if("zhangsan".equals(username) && "123".equals(password)){
out.println("login success!");
}else {
out.println("login fail!");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
接下来就开始编写Android客户端,使之可以访问网络
Android中要访问网络必须得有权限,所以我们得先在manifest文件中添加权限
<uses-permission android:name="android.permission.INTERNET"/>
<p><span style="background:silver;">
</span></p><p><span style="background:silver;">LoginService</span>.java : 用来提供访问网络的类</p><p><pre name="code" class="java">public class LoginService {
<span style="white-space:pre"> </span>private static final String BASE_PATH = "http://110.89.138.70:8080/server/LoginServlet";
/**
* GET方式登陆到服务器
* @param username 用户名
* @param password 密码
* @return 服务器返回的消息
*/
public static String loginByGet(String username, String password){
String path = BASE_PATH + "?username="+username+"&password="+password;
try {
URL url = new URL(path);
//打开连接, 获取HttpURLConnection 的对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000); //设置链接超时时间
conn.setRequestMethod("GET"); //设置请求方式
int code = conn.getResponseCode(); //获取返回码
if(code == 200){
InputStream is = conn.getInputStream();
return StreamTools.readInputStream(is);
}else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* POST方式登陆到服务器
* @param username 用户名
* @param password 密码
* @return 服务器返回的消息
*/
public static String loginByPost(String username, String password){
try {
String data = "username="+username+"&password="+password;
URL url = new URL(BASE_PATH);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//1.设置请求方式 为 post
conn.setRequestMethod("POST");
//2. 设置请求的头
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(data.length()));
conn.setConnectTimeout(5000);
//3.设置 允许向服务器写数据
conn.setDoOutput(true);
conn.getOutputStream().write(data.getBytes());
int code = conn.getResponseCode();
if(code == 200){
InputStream is = conn.getInputStream();
return StreamTools.readInputStream(is);
}else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public class StreamTools {
public static String readInputStream(InputStream is){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
try {
while((len=is.read(buffer)) != -1){
baos.write(buffer);
}
is.close();
baos.close();
byte[] result = baos.toByteArray();
return new String(result);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
下图是程序的界面:
当我们点击loginByGet按钮时,调用以下方法
public void loginByGet(View view){
final String username = etUsername.getText().toString().trim();
final String password = etPassword.getText().toString().trim();
if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){
Toast.makeText(this, "用户名或密码不能为空!", Toast.LENGTH_SHORT).show();
}else {
new Thread(){
public void run() {
final String result = LoginService.loginByGet(username, password);
if(null != result){ //请求成功
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
}
});
}else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});
}
};
}.start();
}
}
当我们输入的是zhangsan和123时,登录成功
当我们输入错误时,如密码输入321,则登录失败
当我们点击loginByPost按钮时,调用以下方法
public void loginByPost(View view){
final String username = etUsername.getText().toString().trim();
final String password = etPassword.getText().toString().trim();
if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)){
Toast.makeText(this, "用户名或密码不能为空!", Toast.LENGTH_SHORT).show();
}else {
new Thread(){
public void run() {
final String result = LoginService.loginByPost(username, password);
if(null != result){ //请求成功
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
}
});
}else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});
}
};
}.start();
}
}
(此处不再截图,参照上面两幅截图)
输入的zhangsan和123时,登录成功
输入错误时,如密码输入321,则登录失败
post请求方式和get不同的是,post的参数不是放在url字符串里,而是放在http请求数据中。
另外还有一点需要注意的是,HttpURLConnection的setRequestMethod(),传入的字符串必须是全大写的,GET或POST,其它的全小写或者首字母大写的形式都不行。
以上的代码并没有对中文乱码进行处理,当我们把服务端的代码改为
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String username = request.getParameter("username");
String password = request.getParameter("password");
<span style="white-space:pre"> </span>System.out.println("username----------"+username);
if("张三".equals(username) && "123".equals(password)){
out.println("登录成功!");
}else {
out.println("登录失败!");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
则会出现乱码问题
这是由于Java在网络传输中使用的默认编码是ISO-8859-1,因此服务端接收到的数据是乱码,要解决这问题,只需在Android程序中重新进行编码,再在服务端以相应的编码方式进行解码,如下
把loginByGet()里的路径替换成下面一行代码
String path = BASE_PATH +"?username="+URLEncoder.encode(username,"utf-8")+"&password="+URLEncoder.encode(password,"utf-8");
URLEncoder.encode(username,"utf-8")表示把字符串username以utf-8的编码方式重新进行编码
服务端解码如下
username = new String(username.getBytes("iso8859-1"), "utf-8");
System.out.println("username----------"+username);
if("张三".equals(username) && "123".equals(password)){
out.println("登录成功!");
}else {
out.println("登录失败!");
}
服务端控制台输出的username如下图
解决了从Android传参到服务端的乱码问题后,还有从就是从服务器返回数据到Android客户端,看到这里有人或许会有疑问,上面的例子不是可以正常的返回
中文字符串吗?
这是因为上面的例子,我们已经指定了返回数据时以utf-8的方式进行编码response.setCharacterEncoding("utf-8");
而Android的默认编码方式也是utf-8,所以中文能正常显示,但当我们把服务端的编码方式改为gbk,
这时就会出现乱码问题response.setCharacterEncoding("gbk");
byte[] result = baos.toByteArray();
return new String(result);
替换成
<span style="white-space:pre"> </span>byte[] result = baos.toByteArray();
String temp = new String(result, "gbk");
return temp;
归根结底,乱码问题就是客户端和服务端采用的编码不一致而导致的,只要想办 法让两边以同样的编码方式进行编码和解码就 OK 了。