在基于Android的APP开发中,不只是单一的在手机上操作,而是通常我们会和网络进行连接,把数据通过网络传输到服务器上,或者从服务器上拿到数据在APP上显示,也就是与服务器进行交互,前提是通过网络。我在做项目的时候完成了一些简单的与服务器之间的交互,在此给大家写出,互相学习。
所有的数据传输都是基于HTTP协议的,不是通过TCP协议。
Android中有两种自带的访问网络的API 1 URLConnection方法 2 HttpClient方法;在向服务器传输数据时,又有两种方式get方式和post方式。每一种方法每一种方式,我都采用函数的方法写出。
1 URLConnection 方法采用 get方式
<span ><span >public static String getmethod(String username,String password) throws IOException
{
//提交数据到服务器,采用get方式
//拼装路径
//String path = "http://192.168.0.105:8080/StructsDemo/hello?hhh=";
//对于网络请求,最好弄成线程
String path ="http://192.168.0.105:8080/StructsDemo/hello?username="+URLEncoder.encode(username,"gbk")+"&password="+URLEncoder.encode(password,"gbk");
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000); //读取的时间
conn.setRequestMethod("GET");
int code = conn.getResponseCode(); //获得服务器的响应
if(code == 200)
{
InputStream is = conn.getInputStream();
String text;
text = StreamTools.readInputStream1(is);
return text;
}
else
return null;
}</span></span>
get方式需要采用拼装字符串的方法,获得网址,在网址后添加要传输的值(username,password),通过android自带的API,采用URLConnection方法与Web进行连接,然后向服务器发送数据。获得服务器的响应,如果code = 200 就说明连接成功,这时候我们定义IuputStream来获取从服务器上的数据(只要服务器发送了消息,我们就能用InputStream获得服务器的消息),不同设备之间的数据交互,通常都是已字节流的形式传输,这个时候InputStream里面就有服务器发送的数据了,只不过是以流的形式存在,所有我们需要转化形式。用如下函数:
<span ><span > public static String readInputStream1(InputStream is)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //可以捕获内存缓冲区中的数据,然后转化成字节数组
int len = 0;
byte[] buffer = new byte[1024];
try {
while ((len = is.read(buffer))!=-1)
{
baos.write(buffer, 0, len);//把buffer中的内容从0写到len
}
is.close();
baos.close();
byte[] result = baos.toByteArray();
return new String(result);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
</span></span>
这个函数是把字节流转化为字符串,这样就能看到服务器发送的数据了。
2 URLConnection 方法采用 post方式
<span ><span >public static String postmethod(String username,String password) throws IOException
{
//提交数据到服务器,采用post方式
//拼装路径
//String path = "http://192.168.0.105:8080/StructsDemo/hello?hhh=";
//对于网络请求,最好弄成线程
String path ="http://192.168.0.105:8080/StructsDemo/hello";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("POST");
//准备 数据
String data= "username="+username+"password="+password;
// 设置请求的头
// conn.setRequestProperty("Connection", "keep-alive");
// 设置请求的头
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
// 设置请求的头
conn.setRequestProperty("Content-Length",
String.valueOf(data.length()+""));
// 设置请求的头
// conn.setRequestProperty("User-Agent",
// "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0");
//post的方式其实是浏览器把数据写给服务器
conn.setDoOutput(true); //允许向外写数据
conn.setDoInput(true); //允许向内读数据
OutputStream os = conn.getOutputStream(); //获得输出流,可以用输出流向服务器写内荣
os.write(data.getBytes()); //把内容写到服务器
int code = conn.getResponseCode(); //获得服务器的响应
if(code == 200)
{
InputStream is = conn.getInputStream();
String text;
text = StreamTools.readInputStream1(is);
return text;
}
else
return null;
}</span></span>
具体细节可以看代码。
3 HttpClient 方法采用 get 方式 (HttpClient API 在 SDK 5.0 以后就被弃用了,也就是代码上画横线)
<span ><span >/**
* 采用httpclient 的get方式访问服务器
* @param username
* @param password
* @return
* @throws IOException
* @throws
*/
public static String LoginByClientget(String username,String password) throws IOException
{
//打开一个浏览器
HttpClient client = new DefaultHttpClient(); //一个接口 (每个接口都有实现类)
//输入地址
String path ="http://192.168.0.105:8080/StructsDemo/hello?username="+username+"&password="+password;
HttpGet httpget = new HttpGet(path);
//敲回车
HttpResponse response = client.execute(httpget); //获得服务器返回的信息
int code ;
code = response.getStatusLine().getStatusCode(); //得到状态行状态码
if(code == 200)
{
InputStream is = response.getEntity().getContent(); //获得服务器返回来的流
String text;
text = StreamTools.readInputStream1(is);
return text;
}
else
return null;
}</span></span>
代码上都有注释,在此就不讲了。
4 HttpClient方法采用post方式(HttpClient API 在 SDK 5.0 以后就被弃用了,也就是代码上画横线)
<span ><span >public static String LoginByClientpost(String username,String password) throws IOException
{
//打开一个浏览器
HttpClient client = new DefaultHttpClient(); //一个接口 (每个接口都有实现类)
//输入地址
String path ="http://192.168.0.105:8080/StructsDemo/hello";
HttpPost httppost = new HttpPost(path);
//指定要提交的数据实体(以表单的形式) NameValuePair 键指対 是一个借口,要使用接口类型可以使用类
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("username", username));
parameters.add(new BasicNameValuePair("password", password));
httppost.setEntity(new UrlEncodedFormEntity(parameters, "gbk") );
//敲回车
HttpResponse response = client.execute(httppost);
int code ;
code = response.getStatusLine().getStatusCode(); //得到状态行状态码
if(code == 200)
{
InputStream is = response.getEntity().getContent(); //获得服务器返回来的流
String text;
text = StreamTools.readInputStream1(is);
return text;
}
else
return null;
}</span></span>
以上方法为Android系统自带的API,可以实现与服务器的交互。为了方便起见,我们还可以使用开源的代码包来实现这些功能,非常方便,高手已经封装好了,你直接用就行。
5 异步框架AsyncHttpClient,加入别人写好的包,直接调用包中的AsyncHttpClient框架,采用post方式
<span ><span > //传输json字符串采用AsyncHttpClient异步框架
AsyncHttpClient client1 = new AsyncHttpClient();
String path1 = "http://219.244.48.159:8080/WeChat/registerSmartDogAction.action";
RequestParams params = new RequestParams();
params.add("register", msg);
client1.post(path1, params, new AsyncHttpResponseHandler(){
@Override
public void onSuccess(int statusCode, Header[] headers,
byte[] responseBody) {
// TODO Auto-generated method stub
//String returninfo = responseBody.toString();
// String jiequinfo = returninfo.substring(0,3);
Toast.makeText(register.this,new String(responseBody).substring(8, 12) , 0).show();
}
//responsBody 是服务器返回的内容
@Override
public void onFailure(int statusCode, Header[] headers,
byte[] responseBody, Throwable error) {
// TODO Auto-generated method stub
Toast.makeText(register.this, new String(responseBody), 0).show();
}
}) ;</span></span>
由以上代码可以看出,在进行网络数据交互的时候非常方便, 1 new 一个 AsyncHttpClient 对象,2 写一个地址,3 new 一个 RequestParams 对象 4 用RequestParams 装载数据,以键值对的方式 5 用AsyncHttpClient的对象,post数据(路径,装载的数据, new AsyncHttpResponseHandler(){
作用是处理服务器返回的数据
public void onSuccess(){
服务器连接成功,返回的数据
}
public void onFailure(){
服务器连接失败,返回的数据
}
});
AsyncHttpClient框架代码地址:
下载好之后解压缩,把com文件整个放到工程的src文件夹下,当一个包引入,最简便方法粘贴复制。
6 上述方法都是向服务器请求数据(只是字符串),如果想要通过http协议向服务器请求图片,或者视频,音频的话(通常都使用的是POST方式),其它的操作都一样,只要改变一下请求资源的地址,然后使用post方式就行了,举例:
String path = "http://192.168.0.135:8080/jsonweb/WebRoot/pitcures/bb.jpg";
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(path);
HttpResponse response =client.execute(get);
int code ;
code = response.getStatusLine().getStatusCode();
if(code == 200)
{
InputStream is = response.getEntity().getContent();
Bitmap bitmap = BitmapFactory.decodeStream(is);
return bitmap;
}
上述代码就是用HttpClient的方法的post方式向服务器请求图片,如果code==200,服务器就会返回图片的字节流,通常这时候处理字节流有上述代码使用的方法,采用BitmapFactory.decodeStream函数,这个相当于在线看,没有下载下来;还有最普遍的方法写文件方法这个相当于下载下来(不管是音频文件,视频文件,图片文件,只要是文件转化的字节流都可以使用这种方法):
File file = new File("自己客户端想要存储的位置");
FileOutputStream output = new FileOutputStream(file);
byte [] byte1 = new byte[1024];
int length = 0 ;
while( (length = (is.read(byte1))!= -1){
output.write(byte1,0,length);
}
output.close();
这样就把这个向服务器请求的图片下载到了你想要保存的地方。
7 如果想要通过客户端向服务器端上传文件应该怎么办,在这里我只使用AsyncHttpClient开源库举例子:代码很简单
String path = address.getText().toString().trim(); //要上传文件的位置
String address1 = "http://192.168.0.105:8080/StructsDemo/upload";
final File file = new File(path);
if(file.exists()&& file.length()>0)
{
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
try {
params.put("profile-picture", file);
client.post(address1, params, new AsyncHttpResponseHandler() { //上传文件到服务器端
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,"请求成功",0).show();
}
@Override
public void onFailure(int statusCode, Header[] headers,
byte[] responseBody, Throwable error) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this,"请求失败",0).show();
}
}) ;
服务器端的upload.jsp网页上的代码:
<form action="up" method="post" enctype="multipart/form-data">
选择的文件:<input name="uploadFile" type="file">
</br>
<input name="submit" type="submit" value="上传">
</form>
enctype必须写成“mutipart/form-data”, params中的属性必须写成“profile-picture”
服务器端后台代码为:
public class upload extends ActionSupport{
private File uploadFile; // 得到上传的文件,此属性对应于表单中文件字段的名称
//下面的这两个属性的命名必须遵守上定的规则,即为"表单中文件字段的名称" + "相应的后缀"
private String uploadFileContentType; // 得到上传的文件的数据类型,
private String uploadFileFileName; // 得到上传的文件的名称
public File getUploadFile() {
return uploadFile;
}
public void setUploadFile(File uploadFile) {
this.uploadFile = uploadFile;
}
public String getUploadFileContentType() {
return uploadFileContentType;
}
public void setUploadFileContentType(String uploadFileContentType) {
this.uploadFileContentType = uploadFileContentType;
}
public String getUploadFileFileName() {
return uploadFileFileName;
}
public void setUploadFileFileName(String uploadFileFileName) {
this.uploadFileFileName = uploadFileFileName;
}
public String execute() throws Exception {
String realPath = ServletActionContext.getServletContext().getRealPath("/images");
System.out.println(realPath);
if(uploadFile !=null ){
File destFile = new File(new File(realPath), uploadFileFileName);//根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
if(!destFile.getParentFile().exists())//判断路径"/images"是否存在
destFile.getParentFile().mkdirs();//如果不存在,则创建此路径
//将文件保存到硬盘上,因为action运行结束后,临时文件就会自动被删除
FileUtils.copyFile(uploadFile, destFile);
ActionContext.getContext().put("message", "文件上传成功!");
}
return "success";
}
}
注:服务器端的后台代码能够继承ActionSupport类因为采用的是Structs框架