Android使用HttpURLConnection实现网络访问流程
作者:一只敲代码的嗷呜 发布时间:2023-09-04 10:40:31
一、管理网络状态
使用网络进行数据通信前,需要先获取网络状态。
使用ConnectivityManager获取网络状态步骤:
1.获取ConnectivityManager对象
2.获取当前活动的网络NetworkInfo对象
3.判断当前网络状态是否为连接状态
4.在AndroidMainfest.xml中添加访问当前网络状态权限
//使用ConnectivityManager检查网络状态步骤
private boolean checkNetworkState() {
ConnectivityManager connectivityManager = (ConnectivityManager) this.getSystemService(CONNECTIVITY_SERVICE);//1.通过系统服务获取ConnectivityManager类的对象
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();//2.调用getActiveNetworkInfo()获取当前活动的网络NetworkInfo对象
if (networkInfo==null || networkInfo.isConnected()==false) {//3.判断当前网络状态是否为连接状态,如果当前没有网络是活动的,则返回null
return false;
}else {
return true;
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.httpurlexestud">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><!--检查网络状态步骤4.添加访问当前网络状态权限-->
<uses-permission android:name="android.permission.INTERNET"/><!--增加访问网络授权声明-->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".WelcomeActivity"></activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
二、HTTP协议
1.HTTP(Hyper Text Transfer Protocol) 即超文本传输协议,是一种详细规定了客户端和万维网(www,World Wide Web)服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。
2.HTTP协议是一种请求/响应式的协议。当客户端与服务器端建立连接后,向服务器端发送的请求,称作HTTP请求;当服务器端接收到请求后会做出响应,称为HTTP响应。
三、HttpURLConnection
HttpURLConnection类位于java.net内,提供了基于HTTP的网络访问方法。
使用HttpURLConnection访问HTTP资源的主要操作步骤:
1.利用URL地址实例化URL类
2.由URL类创建HttpURLConnection对象
3.以GET/POST方式向服务器发送请求
4.接收服务器响应
5.关闭连接
HTTP协议使用注意事项:
1.使用“ .setRequestMethod(" "); ”设置请求方式
2.使用“ .connect(); ”连接网络。请求行、请求头的设置必须放在网络连接前
3.“ .getInputStream() ”只是得到一个流对象,并不是数据。我们需要从流中读取数据,从流中读取数据的操作必须放在子线程
4.“ .getInputStream() ”得到一个流对象,从这个流对象中只能读取一次数据,第二次读取时将会得到空数据
四、GET和POST请求方式
1.GET方式是以实体的方式得到由请求URL所指向的资源信息,它向服务器提交的参数跟在请求URL后面。使用GET方式访问网络URL的长度一般要小于1K
2.POST方式向服务器发送请求时需要在请求后附加实体,它向服务器提交的参数在请求后的实体中。POST方式对URL的长度没有限制
3.采用POST方式提交数据时,用户在浏览器中看不到向服务器提交的请求参数,因此POST方式要比GET方式相对安全。
4.GET重点在从服务器上获取资源,POST重点在向服务器发送数据。
5.GET传输的数据量小,因为受URL长度限制,但效率较高;POST没有此限制,可以传输大量数据,所以上传文件时只能用POST方式。
6.GET方式只能支持ASCII字符,向服务器传的中文字符可能会乱码;POST支持标准字符集,可以正确传递中文字符。
注意事项:
1.所有内容都需要访问网络才能进行发送或者获取,因此需要配置文件AndroidMainfest.xml文件中添加访问网络的权限(第一部分里已给出代码)。
2.实际开发中,手机端与服务器端进行交互的过程中,避免不了要提交中文到服务器,这时就会出现中文乱码的情况。因此,无论是GET方式还是POST方式提交参数时都要对参数进行编码。需要注意的是,编码方式必须与服务器解码方式一致。同样,在获取服务器返回的中文字符时,也需要用指定格式进行解码。
(1)以GET方式提交数据
/*一、GET方式步骤:
1.把用户名和密码拼接成以get方式向服务器发送请求的URL字符串
2.使用url的openConnection()方法获得HttpURLConnection对象
3.设置HttpURLConnection对象的请求方式、超时等,并调用connect()建立连接
4.得到响应码并判断连接正常后,通过getInputStream()方法获得携带服务器返回信息的输入流,从流中读取出服务器返回值,并向handler发送消息
5.断开连接*/
String urlStr = "http://192.192.192.192:8080/TestServer/servlet/Login?name="+
URLEncoder.encode(name)+
"&pass="+URLEncoder.encode(pwd);//将用户名和密码拼在指定资源路径后面,并对用户名和密码进行编码
try {//使用try-catch-finally捕获异常
url = new URL(urlStr);//在URL的构造方法中传入要访问资源的路径
uc = (HttpURLConnection) url.openConnection();//返回一个HttpURLConnection对象
uc.setRequestMethod("GET");//设置GET请求方式
uc.setConnectTimeout(5000);//设置超时时间
uc.connect();//连接
int code = uc.getResponseCode();//得到响应码(获取HTTP状态码)
if (code == HttpURLConnection.HTTP_OK) {//4.得到响应码并判断连接正常后,通过getInputStream()方法获得携带服务器返回信息的输入流,从流中读取出服务器返回值,并向handler发送消息
System.out.println(uc.getResponseCode());//控制台输出
InputStream inputStream = uc.getInputStream();//得到响应流(通过getInputStream()方法获取携带服务器返回信息的输入流)
int i = inputStream.read();
System.out.println(i);//控制台显示是0还是1,以ASCII码形式显示
//通过Message和handler.sendMessage()将返回结果传递给UI线程
Message message = Message.obtain();//从服务器返回的数据,1.获取可用的Message对象
message.arg1 =i;//2.通过message的arg1传递参数
handler.sendMessage(message);//发送至主界面显示
}else {
System.out.println(uc.getResponseCode());//控制台输出
Message message = Message.obtain();
message.arg1 =2;
handler.sendMessage(message);
}
}catch (Exception e) {
e.printStackTrace();
}finally {
if (uc != null) {
uc.disconnect();//关闭HTTP连接
}
}
(2)以POST方式提交数据
/*二、POST方式步骤:
1.通过URL字符串创建URL对象
2.使用url的openConnection()方法获得HttpURLConnection对象
3.设置HttpURLConnection对象的请求方式、超时、请求头数据提交方式等,并调用connect()建立连接
4.通过getOutputStream()获得输出流往服务器写数据
5.得到响应码并判断连接正常后,通过getInputStream()方法获得携带服务器返回信息的输入流,从流中读取出服务器返回值,并向handler发送消息
6.断开连接*/
String urlStr = "http://192.192.192.192:8080/TestServer/servlet/Login";
try {//使用try-catch-finally捕获异常
url = new URL(urlStr);//在URL的构造方法中传入要访问资源的路径
uc = (HttpURLConnection) url.openConnection();//返回一个HttpURLConnection对象
uc.setRequestMethod("POST");//设置POST请求方式
uc.setConnectTimeout(5000);//设置超时时间
String data = "name="+ URLEncoder.encode(name) +
"&pass="+URLEncoder.encode(pwd);
uc.setRequestProperty("Content-Type","application/x-www-form-urlencoded");//设置请求头数据提交方式,这里以form表单形式提交
uc.setRequestProperty("Content-Length", data.length()+"");//设置请求头,设置提交数据的长度
//POST方式,实际是浏览器把数据写给了服务器
uc.setDoOutput(true);//设置允许向外写数据
uc.connect();//连接
//4.通过getOutputStream()获得输出流往服务器写数据
OutputStream outputStream = uc.getOutputStream();//通过getOutputStream()获得输出流
outputStream.write(data.getBytes());
int code = uc.getResponseCode();//获取HTTP状态码
if (code == HttpURLConnection.HTTP_OK) {//5.得到响应码并判断连接正常后,通过getInputStream()方法获得携带服务器返回信息的输入流,从流中读取出服务器返回值,并向handler发送消息
System.out.println(uc.getResponseCode());//控制台输出
InputStream inputStream = uc.getInputStream();//得到响应流(通过getInputStream()方法获取携带服务器返回信息的输入流)
int i = inputStream.read();
System.out.println(i);//控制台显示是0还是1,以ASCII码形式显示
//通过Message和handler.sendMessage()将返回结果传递给UI线程
Message message = Message.obtain();//从服务器返回的数据,1.获取可用的Message对象
message.arg1 =i;//2.通过message的arg1传递参数
handler.sendMessage(message);//发送至主界面显示
}else {
System.out.println(uc.getResponseCode());//控制台输出
Message message = Message.obtain();//从服务器返回的数据,1.获取可用的Message对象
message.arg1 =2;//2.通过message的arg1传递参数
handler.sendMessage(message);//发送至主界面显示
}
}catch (Exception e) {
e.printStackTrace();
}finally {
if (uc != null) {
uc.disconnect();//关闭HTTP连接
}
}
五、做个实验
(一)实验效果如图所示
(二)实验步骤
MainActivity.java文件
1.在MainActivity.java中使用ConnectivityManager获取网络状态,完成网络状态判断方法checkNetworkState()的实现,具体步骤和代码在第一部分中已经给出
2.在 “登录”按钮的事件监听方法btnLogin.setOnClickListener()中,新建线程并使用HttpURLConnection访问服务器进行用户名和密码的验证,并将结果发送给Handler对象
重写run()方法中采用GET或POST方法提交数据,代码在第四部分已经给出
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final String name=edName.getText().toString();
final String pwd=edPwd.getText().toString();
if(checkNetworkState()!=true){//判断是否联网
Toast.makeText(MainActivity.this,"网络没有打开,请打开网络后再试。",Toast.LENGTH_LONG).show();
}else {
if (name.equals("")) {
Toast toast = Toast.makeText(MainActivity.this, "输入用户名", Toast.LENGTH_LONG);
toast.show();
}else if (pwd.equals("")) {
Toast toast = Toast.makeText(MainActivity.this, "输入密码", Toast.LENGTH_LONG);
toast.show();
}else {
//新建线程,并通过GET或post方式把用户名和密码向服务器发送请求并将结果发送给Handler对象
new Thread(new Runnable() {
@Override
public void run() {//重写run()方法
}
}).start();
}
}
}
});
3.在onCreate()方法外部,实现Handler的handleMessage()方法,根据服务器返回结果判断是否登录成功
final Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
//通过msg中传递数据判断是否登录成功,若成功则实现界面跳转到WelcomeActivity
int i = msg.arg1;
if (i==49) {//界面跳转
Intent intent = new Intent(MainActivity.this, WelcomeActivity.class);
startActivity(intent);
}else if (i==48) {//Toast提示用户名或密码错误
Toast.makeText(MainActivity.this, "用户名或密码错误!", Toast.LENGTH_LONG).show();
}else {//Toast提示连接失败
Toast.makeText(MainActivity.this, "网络连接失败!", Toast.LENGTH_LONG).show();
}
}
};
WelcomeActivity.java文件
4.完成DownloadTask类中各个方法的实现。doInBackground()方法中使用HttpURLConnection访问服务器并下载图片,下载过程中实时发布下载进度,下载完成后返回Bitmap对象
class DownloadTask extends AsyncTask<String, Integer, Bitmap> {//分别代表:执行后台任务传递的参数、更新的进度值的类型(都是整形) 、返回结果类型
@Override
protected void onPreExecute() {//UI组件初始化设置
super.onPreExecute();
textView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.VISIBLE);
progressBar.setProgress(0);//设置进度条初始值为0
}
@Override
protected Bitmap doInBackground(String... strings) {
URL url;
HttpURLConnection urlConnection = null;
Bitmap bitmap = null;
pbValue=0;//初始值为0
try {
/*url = new URL(strings[0]);//在URL构造方法中传入要访问资源的路径*/
url = new URL(urlStr);
urlConnection = (HttpURLConnection) url.openConnection();//根据url发送一个http的请求
urlConnection.setRequestMethod("GET");//设置GET请求方式
urlConnection.setConnectTimeout(5000);//设置超时时间
urlConnection.connect();//连接
if(urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK /*urlConnection.getResponseCode() == 200*/ ) {//得到响应码,判断连接是否正常
System.out.println(urlConnection.getResponseCode());//控制台输出
InputStream inputStream = urlConnection.getInputStream();//通过getInputStream()方法获得携带服务器返回信息的输入流
System.out.println(inputStream);//控制台显示是0还是1,以ASCII码形式显示
int maxSize = urlConnection.getContentLength();//通过urlConnection的getContentLength()获取下载图片的总大小
byte[] buffer = new byte[1024*8];
int len = -1;
int process =0;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while((len = inputStream.read(buffer)) != -1) {//通过inputStream.read(buffer)和while循环读取数据,并通过ByteArrayOutputStream将数据写入
process += len;
byteArrayOutputStream.write(buffer, 0, len);
Thread.sleep(50);//每隔50ms通过publishProgress()发布进度值
pbValue = (int) ((((double)process)/maxSize)*progressBar.getMax());//计算数据下载的完成百分比
publishProgress(pbValue);//发布进度
}
/*byteArrayOutputStream.flush();*/
//数据读取完成后通过BitmapFactory.decodeByteArray()将ByteArrayOutputStream对象out中数据转换成Bitmap对象并返回
byte[] result = byteArrayOutputStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(result, 0, maxSize);
/*bitmap = BitmapFactory.decodeByteArray(byteArrayOutputStream.toByteArray(), 0, maxSize);*/
}
}catch (Exception e) {
e.printStackTrace();
}finally {
if (urlConnection != null) {
urlConnection.disconnect();//关闭HTTP连接
}
return bitmap;
}
}
@Override
protected void onProgressUpdate(Integer... values) {//下载过程中更新TextView和进度条的进度值
super.onProgressUpdate(values);
textView.setText("已下载"+ values[0]+"%");
progressBar.setProgress(values[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap) {//下载完成后更新TextView和进度条
super.onPostExecute(bitmap);
Toast.makeText(WelcomeActivity.this, "加载完毕", Toast.LENGTH_SHORT).show();
textView.setText("恭喜!下载完成!");
progressBar.setVisibility(View.INVISIBLE);//下载完成后进度条消失
imageView.setImageBitmap(bitmap);
}
}
5.在“下载图片”按钮的事件监听方法btnGetPic.setOnClickListener ()中,新建DownloadTask类的异步任务并调用execute(urlStr)方法执行网络图片的下载任务
btnGetPic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new DownloadTask().execute(urlStr);//创建DownloadTask实例对象,并调用其execute()方法
}
});
完整代码请从这里下载
注意事项:
1.我上传的压缩包中包含两个文件,TestServer要导入myeclipse中,HttpUrlExeStud导入Android Studio中
2.TestServer下存在一个Login文件,其中
if(name!=null && pass!=null && name.equals("JMX") && pass.equals("666"))
包含了我的用户名和密码,你可以进行更换,建议用户名设置为英文
3.TestServer必须运行起来,右击TestServer项目,点击Run As – 3 MyEclipse Server Application,弹出如下界面则表示成功
4.HttpUrlExeStud下MainActivity.java的GET、POST方法和WelcomeActivity.java分别包含这几行代码
String urlStr = "http://192.192.192.192:8080/TestServer/servlet/Login?name="+URLEncoder.encode(name)+"&pass="+URLEncoder.encode(pwd);
String urlStr = "http://192.192.192.192:8080/TestServer/servlet/Login";
final String urlStr="http://192.192.192.192:8080/TestServer/pic/bamboo1.jpg";
其中192.192.192.192是我的ip地址,实际运行时需要替换成你自己的ip地址。可以通过win+R,键入cmd,输入ipconfig的方式获取到计算机ip信息
来源:https://blog.csdn.net/m0_66309026/article/details/123750938
猜你喜欢
- 今天碰到个很恶心的东西。。就是明明导入了相应的依赖文件(css,html,js等文件),路径也正确。。就是访问不了。。。。弄了一个多小时。。
- 文件上传在web应用中非常普遍,要在jsp环境中实现文件上传功能是非常容易的,因为网上有许多用java开发的文件上传组件,本文以common
- 本文实例讲述了Java文本文件操作方法。分享给大家供大家参考。具体分析如下:最初Java是不支持对文本文件的处理的,为了弥补这个缺憾而引入了
- 目录前言应用定义基本Enum特性Enum的静态导入Enum中添加新方法Switch语句中的EnumEnum的继承EnumSet的使用Enum
- 算法文章,总是带给我们无穷的思考和兴趣,一个问题,多种解决方法,看你如何去思考它,对于标题所引出的问题,我觉得,使用递归是比较有效的方法,当
- 一.内部类的介绍 内部类: 一个类定义在 另一个类 的 内部。 &
- HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。HashMap 实现了 Map 接口,根据键的 HashCod
- 注:由于工作需要, 也是第一次接触到打印机的相关内容, 凑巧, 通过找了很多资料和帮助后, 也顺利的解决了打印标签的问题(标签的表面信息[二
- 关于约瑟夫环的基本知识:罗马人攻占了乔塔帕特,41人藏在一个山洞中躲过了这场浩劫。这41个人中,包括历史学家josephus和他的一个朋友。
- 这个功能没什么可介绍的,大家都懂,直接上代码了。。实现功能选择多个文件压缩成ZIP文件和解压ZIP文件开发环境开发工具: Visual St
- 这篇文章主要介绍了Javaweb实现在线人数统计代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 一、内部类的概念在 Java 中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。p
- 在C#当中,利用WebClient这个核心类,可以轻易的打造一个下载器。但是这里想要强调的是,我们用的是异步操作。所谓异步,是相对于同步的概
- java控制台输出图书馆管理系统(只用java代码不用数据库和GUI,java入门的新手秒懂)在个项目中,我只用数组保存数据,和只用for循
- 1.配置自定义共享线程池(Spring线程池)@Configuration@EnableAsyncpublic class ThreadPo
- 相同:1、LinkedBlockingQueue和ArrayBlockingQueue都实现了BlockingQueue接口;2、Linke
- AssertJ是我目前见过的最强大的断言api,没有之一。官网传送门为什么使用assertJ?1、流式断言,代码即用例,直观易懂。举个例子:
- 中文乱码问题真的是一个很棘手的问题,特别是从前台传到后台之后,都不知道问题出在哪里了。现在分享解决javaWEB中前后台中文乱码问题的3种方
- Object是类层次结构的根,每个类都可以将Object作为超类。所有类都直接或者间接的继承自该类构造方法:public Object()回
- 前言在上篇文章《初识GraphQL》中我们大致的了解了GraphQL作用,并通过简单示例初步体验了GraphQL的使用。下面我们从Hello