一、远程服务器存储
1、说明
(1对于联网的APP来说, 可能需要通过请求向服务器提交请求数据, 也可能需要从服务器端获取数据显示
(2如何编码实现客户端与服务器端的交互呢?
JDK内置的原生API :HttpUrlConnection
Android内置的包装API:HttpClient 浏览器
异步网络请求框架:Volley,Xutils
(3注意:
访问网络, 需要声明权限: android.permission.INTERNET
访问网络的程序必须在分线程执行
2、HTTP协议(复习)
• 一次HTTP请求的过程
– 建立连接-à发送请求-à处理请求-à返回数据-à发送请求2-à………关闭连接
• HTTP请求的常用方式
– GET
– POST
• HTTP请求的格式
– 请求行
– 请求头
– 请求体
• HTTP响应的格式
– 响应行
– 响应头
– 响应体
二、使用HttpConnection
1.URL : 包含请求地址的类
URL(path) : 包含请求路径的构造方法
openConnection() : 得到连接对象
2.HttpURLConnection : 代表与服务器连接的类
setMethod(“GET/POST”) : 设置请求方式
setConnectTimeout(time) : 设置连接超时时间, 单位为ms
setReadTimeout(time): 设置读取服务器返回数据的时间
connect() : 连接服务器
int getResponseCode(): 得到服务器返回的结果码
Int getContentLength() : 得到服务器返回数据的长度(字节)
getOutputStream() : 返回一个指向服务器端的数据输出流
getInputStream() : 返回一个从服务器端返回的数据输入流
disconnect() : 断开连接
权限:
<!-- 联网 --> <uses-permission android:name="android.permission.INTERNET"/>
public class MainActivity extends Activity {
private EditText et_main_message;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_main_message=findViewById(R.id.et_main_message);
}
/*
* 使用httpUrlConnection提交get请求
*/
/*
1. 显示ProgressDialog
2. 启动分线程
3. 在分线程, 发送请求, 得到响应数据
1). 得到path, 并带上参数name=Tom1&age=11
2). 创建URL对象
3). 打开连接, 得到HttpURLConnection对象
4). 设置请求方式,连接超时, 读取数据超时
5). 连接服务器
6). 发请求, 得到响应数据
得到响应码, 必须是200才读取
得到InputStream, 并读取成String
7). 断开连接
4. 在主线程, 显示得到的结果, 移除dialog
*/
public void get(View v){
//1. 显示ProgressDialog
final ProgressDialog progressDiag= ProgressDialog.show(this,null,"正在请求中");
//2. 启动分线程
new Thread(){
//3. 在分线程, 发送请求, 得到响应数据
public void run(){
try {
//1). 得到path, 并带上参数
String path="http://192.168.0.118/test.php?id=2";
//2). 创建URL对象
URL url=new URL(path);
//3). 打开连接, 得到HttpURLConnection对象
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//4). 设置请求方式,连接超时, 读取数据超时
connection.setRequestMethod("GET");
connection.setConnectTimeout(200);
connection.setReadTimeout(200);
//5). 连接服务器
connection.connect();
//6). 发请求, 得到响应数据
//得到响应码, 必须是200才读取
int code=connection.getResponseCode();
if(code==200){
//得到InputStream, 并读取成String
InputStream is=connection.getInputStream();
ByteArrayOutputStream bao=new ByteArrayOutputStream();
byte[] flush=new byte[1024];
int len=1;
while((len=is.read(flush))!=-1){
bao.write(flush,0,len);
}
final String result=bao.toString();
bao.close();
is.close();
//4. 在主线程, 显示得到的结果, 移除dialogs
runOnUiThread(new Runnable() {
@Override
public void run() {
et_main_message.setText(result);
progressDiag.dismiss();
}
});
}
//7). 断开连接
connection.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
//如果出了异常要移除dialog
progressDiag.dismiss();
} catch (IOException e) {
e.printStackTrace();
//如果出了异常要移除dialog
progressDiag.dismiss();
}
}
}.start();
}
/*
* 使用httpUrlConnection提交post请求
*/
/*
1. 显示ProgressDialog
2. 启动分线程
3. 在分线程, 发送请求, 得到响应数据
1). 得到path
2). 创建URL对象
3). 打开连接, 得到HttpURLConnection对象
4). 设置请求方式,连接超时, 读取数据超时
5). 连接服务器
6). 发请求, 得到响应数据
得到输出流, 写请求体:name=Tom1&age=11
得到响应码, 必须是200才读取
得到InputStream, 并读取成String
7). 断开连接
4. 在主线程, 显示得到的结果, 移除dialog
*/
public void post(View v){
//1. 显示ProgressDialog
final ProgressDialog progressDialog=ProgressDialog.show(this,null,"正在加载数据");
//2. 启动分线程
new Thread(new Runnable() {
//3. 在分线程, 发送请求, 得到响应数据
@Override
public void run() {
try {
//1). 得到path
String path="http://192.168.0.118/test.php";
//2). 创建URL对象
URL url=new URL(path);
//3). 打开连接, 得到HttpURLConnection对象
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
//4). 设置请求方式,连接超时, 读取数据超时
connection.setRequestMethod("POST");
connection.setConnectTimeout(2000);
connection.setReadTimeout(5000);
//5). 连接服务器
connection.connect();
//6). 发请求, 得到响应数据
//得到输出流, 写请求体:name=Tom1&age=11
OutputStream os=connection.getOutputStream();
String data="id=2&name=haitao";
os.write(data.getBytes("utf-8"));
//得到响应码, 必须是200才读取
int code=connection.getResponseCode();
if(code==200){
//得到InputStream, 并读取成String
InputStream is=connection.getInputStream();
ByteArrayOutputStream bao=new ByteArrayOutputStream();
byte[] flush=new byte[1024];
int len=-1;
while( (len=is.read(flush))!=-1 ){
bao.write(flush,0,len);
}
final String result=bao.toString();
bao.close();
is.close();
//4. 在主线程, 显示得到的结果, 移除dialog
runOnUiThread(new Runnable() {
@Override
public void run() {
et_main_message.setText(result);
progressDialog.dismiss();
}
});
}
//7). 断开连接
connection.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
下载图片
public class MainActivity extends AppCompatActivity {
private ImageView iv;
private String imageurl = "http://img06.tooopen.com/images/20161106/tooopen_sl_185050524199.jpg";
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView) findViewById(R.id.iv_show);
findViewById(R.id.load).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(loadrunable).start();
}
});
}
private Runnable loadrunable = new Runnable() {
private InputStream is;
@Override
public void run() {
try {
URL imgUrl = new URL(imageurl);
// 使用HttpURLConnection打开连接
HttpURLConnection urlConn = (HttpURLConnection) imgUrl
.openConnection();
urlConn.setDoInput(true);
urlConn.setDoOutput(false);
urlConn.setRequestMethod("GET");
urlConn.setConnectTimeout(3000);
urlConn.setUseCaches(true);
urlConn.connect();
int code = urlConn.getResponseCode();
Log.e("tag", "run: "+code );
// 将得到的数据转化成InputStream
InputStream is = urlConn.getInputStream();
// 将InputStream转换成Bitmap
// bitmap = getBitmapInputStream(is);
byte[] bytesInputStream = getBytesInputStream(is);
bitmap = BitmapFactory.decodeByteArray(bytesInputStream,0,bytesInputStream.length);
Message msgone = new Message();
msgone.what = 1;
handler.sendMessage(msgone);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (null != is){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// super.handleMessage(msg);
Log.e("tag", "handleMessage: "+msg.what );
if (null != bitmap && null != iv){
iv.setImageBitmap(bitmap);
}
}
};
public Bitmap getBitmapInputStream(InputStream is){
Bitmap bp;
bp = BitmapFactory.decodeStream(is);
return bp;
}
public byte[] getBytesInputStream( InputStream is) throws IOException {
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
byte[] buff = new byte[512];
int len;
while ((len = is.read(buff))!= -1){
arrayOutputStream.write(buff,0,len);
}
is.close();
arrayOutputStream.close();
return arrayOutputStream.toByteArray();
}
}
重点:不要设置setDoOutput(true),post请求上传参数得设置为true;
它默认为false: urlConn.setDoOutput(false);
三、使用HttpClient
1.HttpClient/DefaultHttpClient : 能提交请求的客户端对象
HttpResponse execute (HttpUriRequest request)
执行包含请求数据的请求对象, 返回包含响应数据的响应对象
HttpParams getParams()
得到包含请求参数的对象
1.: HttpConnectionParams : 设置请求参数的工具类
static setConnectionTimeout(params, time) : 设置获取连接的超时时间
static setSoTimeout(params, time): 设置读取数据的超时时间
2.HttpGet : Get请求
HttpGet(String path) : 包含请求路径的构造方法
3.HttpPost : Post请求
HttpPost(String path) : 包含请求路径的构造方法
setEntity(HttpEntity entity) : 设置请求体
6、使用HttpClient(2)
1.NameValuePair/BasicNameValuePair : 包含参数键值对
BasicNameValuePair (String name, String value)
2.HttpResponse : 服务器返回的响应
getStatusLine() : 得到响应状态行, 从而得到状态码
getEntity() : 得到响应体数据对象
3.EntityUtils : 解析HttpEntity的工具类
toString(httpEntity): 解析响应体, 得其内容字符串
4. 关闭连接, 释放资源:
client.getConnectionManager().shutdown();
权限:
<!-- 联网 --><uses-permission android:name="android.permission.INTERNET"/>
public class MainActivity extends Activity {
private EditText et_main_message;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_main_message=findViewById(R.id.et_main_message);
}
public void get(View v) throws IOException {
//1. 显示ProgressDialog
final ProgressDialog dialog= ProgressDialog.show(this,null,"正在加载中");
//2. 启动分线程
new Thread(new Runnable() {
//3. 在分线程, 发送请求, 得到响应数据
@Override
public void run() {
try {
//1). 得到path, 并带上参数
String path="http://192.168.0.118/test.php?id=2";
//2). 创建HttpClient对象
HttpClient httpClient=new DefaultHttpClient();
//3). 设置超时
HttpParams params=httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params,2000);
HttpConnectionParams.setSoTimeout(params,3000);
//4). 创建请求对象
HttpGet request=new HttpGet(path);
//5). 执行请求对象, 得到响应对象
HttpResponse response= httpClient.execute(request);
int code=response.getStatusLine().getStatusCode();
if(code==200){
//6). 得到响应体文本
HttpEntity entity=response.getEntity();
final String result=EntityUtils.toString(entity);
//4. 要主线程, 显示数据, 移除dialog
runOnUiThread(new Runnable() {
@Override
public void run() {
et_main_message.setText(result);
dialog.dismiss();
}
});
}
//7). 断开连接
httpClient.getConnectionManager().shutdown();
} catch (IOException e) {
e.printStackTrace();
//如果出了异常要移除dialog
dialog.dismiss();
}
}
}).start();
}
public void post(View v){
//1. 显示ProgressDialog
final ProgressDialog dialog= ProgressDialog.show(this,null,"正在加载中");
//2. 启动分线程
new Thread(new Runnable() {
@Override
public void run() {
try {
//1). 得到path, 并带上参数
String path="http://192.168.0.118/test.php";
//2). 创建HttpClient对象
HttpClient httpClient=new DefaultHttpClient();
//3). 设置超时
HttpParams params=httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params,2000);
HttpConnectionParams.setSoTimeout(params,3000);
//4). 创建请求对象
HttpPost request=new HttpPost(path);
//设置请求体
List<BasicNameValuePair> parameters=new ArrayList<BasicNameValuePair>();
parameters.add(new BasicNameValuePair("id","123"));
parameters.add(new BasicNameValuePair("name","haitao"));
HttpEntity entity=new UrlEncodedFormEntity(parameters);
request.setEntity(entity);
//5). 执行请求对象, 得到响应对象
HttpResponse response=httpClient.execute(request);
int code=response.getStatusLine().getStatusCode();
if(code ==200){
//6). 得到响应体文本
entity=response.getEntity();
final String result=EntityUtils.toString(entity);
//4. 要主线程, 显示数据, 移除dialog
runOnUiThread(new Runnable() {
@Override
public void run() {
et_main_message.setText(result);
dialog.dismiss();
}
});
}
//7). 断开连接
httpClient.getConnectionManager().shutdown();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
dialog.dismiss();
} catch (ClientProtocolException e) {
e.printStackTrace();
dialog.dismiss();
} catch (IOException e) {
e.printStackTrace();
dialog.dismiss();
}
}
}).start();
}
}
四、Android Studio中添加对HttpClient的支持包
sdk6.0以后取消了HttpClient,设置android SDK的编译版本为23时,且使用了httpClient相关类的库项目,会出现有一些类找不到的错误。
解决方法有两种:
1.在相应的module下的build.gradle中加入:
useLibrary 'org.apache.http.legacy'
这条语句一定要加在 android{ } 当中。
如:
android {
useLibrary 'org.apache.http.legacy'
}
2.将在相应的module下的build.gradle中修改compileSdkVersion的值,设置为更小的sdk版本
一、Volley
Volley是Google 2013年的 I/O大会 上,发布了的一个框架
Volley是Android上的网络通信库,能使网络通信更快,更简单,更健壮
Volley特别适合数据量不大但是通信频繁的场景: 带图片的列表
http://www.cnblogs.com/cpacm/p/4193011.html
Volley框架的使用
http://blog.csdn.net/guolin_blog/article/details/17482095
所谓Volley,它是2013年Google I/O上发布的一款网络框架,基于Android平台,能使网络通信更快,更简单,更健全。
它的优点:
(1)默认Android2.3及以上基于HttpURLConnection,2.3以下使用基于HttpClient;
(2)符合Http 缓存语义 的缓存机制(提供了默认的磁盘和内存等缓存);
(3)请求队列的优先级排序;
(4)提供多样的取消机制;
(5)提供简便的图片加载工具(其实图片的加载才是我们最为看重的功能);
(6)一个优秀的框架。
不足之处也有:
(1)它只适合数据量小,通信频繁的网络操作,
(2)如果是数据量大的,像音频,视频等的传输,还是不要使用Volley的为好。
2、Volley相关API
1.RequestQueue : 请求队列, 会自动执行队列中的请求
Volley. newRequestQueue(context) : 创建一个请求队列
addReqeust(Request reqeust) : 将请求添加到请求队列
2.Request<T>: 代表请求的接口
StringRequest : 获取字符串结果的请求
JsonRequest : 获取Json数据结果的请求
ImageRequest : 获取图片结果的请求
权限:<!-- 联网 --> <uses-permission android:name="android.permission.INTERNET"/>
public class MainActivity extends Activity {
private EditText et_main_message;
private RequestQueue queue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_main_message=findViewById(R.id.et_main_message);
queue= Volley.newRequestQueue(this);
}
/*
* 使用Volley提交get请求
*/
/*
1. 创建请求队列对象(一次)
2. 创建请求对象StringRequest
3. 将请求添加到队列中
*/
public void get(View v){
final ProgressDialog dialog = ProgressDialog.show(this, null, "正在请求中...");
//创建请求对象StringRequest
String path ="http://192.168.0.118/test.php?id=2";
//创建请求对象StringRequest
StringRequest request=new StringRequest(path, new Response.Listener<String>() {
@Override
public void onResponse(String response) {//在主线程执行
et_main_message.setText(response);
dialog.dismiss();
}
}, null);
queue.add(request);
}
/*
* 使用Volley提交post请求
*/
public void post(View v){
final ProgressDialog dialog = ProgressDialog.show(this, null, "正在请求中...");
String path="http://192.168.0.118/test.php";
//创建请求对象StringRequest
StringRequest request=new StringRequest(Request.Method.POST, path, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
et_main_message.setText(response);
dialog.dismiss();
}
},null){
//重写此方法返回参数的map作为请求体
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> map=new HashMap<String,String>();
map.put("id","1");
map.put("name","haitao");
return map;
}
};
queue.add(request);
}
}