005 Android HttpURLConnection的使用+Handler的原理及典型应用
1.介绍
总结:HttpURLConnection用来发送和接收数据。
2.ANR异常报错
(1)ANR(Application not response) 应用无响应, 主线程(UI线程)
(2)如果在主线程中进行耗时操作(比如连接网络、拷贝大量的数据),都会报ANR异常
(3)避免ANR报错,可以把耗时操作放到子线程中,自己再创建一个线程。
(4)android 4.0之后,Google公司要求连接网络不能在主线程中进行访问。
总结:主线程中不要执行耗时操作(比如连接网络、拷贝大量的数据、Thread.sleep()),应在子线程中操作。
UI的更新应该在主线程中执行。
3.handler原理
handler是更新UI界面的机制,也是消息处理的机制,我们可以发送消息,也可以处理消息
handler实现主线程与子线程之间的交互。
handler使用步骤:
(1)在主线程定义一个handler
(2)重写handler的handleMessage()方法
(3)在子线程中发送需要设置的消息内容
(4)handler中进行接收消息,并设置ui
注意:
<1>hander的作用是发送并处理消息
<2>子线程最好不要更新ui组件
<3>Looper的作用是监视消息队列,若消息队列中有消息,则取出消息并将消息交给hander处理。
Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { //在主线程里更新ui String strTemp= (String) msg.obj; tv_websiteShow.setText(strTemp); } };
4.网址测试时,网址最好复制网上的直接网址,不要自己手动输入。
5.使用技巧(避免出错):
<1>无论哪个版本的手机,只要涉及耗时操作(比如连接网络,拷贝大量的数据等),则需要开辟一个子线程
<2>获取数据后想要更新ui,就使用Handler就可以了
6.利用手机的缓存功能
//缓存图片(节省流量)
FileOutputStream fos=new FileOutputStream(file); //创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
int len=-1;
byte[] buffer=new byte[1024]; //1kb
while ((len=in.read(buffer))!=-1){ //从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
fos.write(buffer,0,len);
}
fos.close();
in.close();
7.java代码
<1>MainActivity.class
注意:更新ui组件有两种方法:(1)利用handler发送消息,修改ui组件(必须掌握,万能) (2)调用runOnUiThread()方法,实现在子线程中更新ui的效果。(有的情况下不能使用)
package com.example.lucky.test54wanzhichakan; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class MainActivity extends AppCompatActivity { protected static final int REQUESTSUCCESS=0; protected static final int REQUESTNOTFOUND=1; protected static final int REQUESTEXCEPTION=2; protected static final int REQUESTIMAGESUCCESS=3; Button bt_showText; Button bt_showImage; TextView tv_websiteShow; EditText et_website; ImageView iv_pic1; @SuppressLint("HandlerLeak") Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case REQUESTSUCCESS: //请求成功 //在主线程里更新ui String strTemp= (String) msg.obj; tv_websiteShow.setText(strTemp); break; case REQUESTNOTFOUND: Toast.makeText(MainActivity.this,"请求未响应",Toast.LENGTH_LONG).show(); break; case REQUESTEXCEPTION: Toast.makeText(MainActivity.this,"服务器正忙,稍后再试",Toast.LENGTH_LONG).show(); break; case REQUESTIMAGESUCCESS: Bitmap bitmap= (Bitmap) msg.obj; iv_pic1.setImageBitmap(bitmap); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_showText=findViewById(R.id.bt_showText); bt_showImage=findViewById(R.id.bt_showImage); tv_websiteShow=findViewById(R.id.tv_websiteShow); et_website=findViewById(R.id.et_website); iv_pic1=findViewById(R.id.iv_pic1); bt_showText.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {
//开启一个子线程 new Thread(){ @Override public void run() { String website=et_website.getText().toString().trim(); //trim()方法用于去除字符串开头和结尾的空白 try { //1.创建URL,指定我们要访问的网址 URL url=new URL(website); //2.获取HttpURLConnection对象,用于发送或接收数据 HttpURLConnection conn= (HttpURLConnection) url.openConnection(); System.out.println("-------------------flaglucky"); //3.设置请求格式为get conn.setRequestMethod("GET"); //注意get要求大写,默认为get请求 //4.设置请求的超时时间 conn.setConnectTimeout(5000); //5.获取服务器返回的状态码 int code=conn.getResponseCode(); System.out.println("--------------"+code); //如果code==200说明请求成功 if(code==200){ System.out.println("-------------------flagif"); //6.获取服务器返回的数据(以流的形式返回) InputStream in=conn.getInputStream(); //7.用定义的工具类将InputStream类型的数据转换为String String contentStr=StreamTools.readStream(in); //8.1创建message对象 Message msg=new Message(); msg.obj=contentStr; //设置消息内容 msg.what=REQUESTSUCCESS; //设置消息代号 handler.sendMessage(msg); //利用handler告诉系统需要更新ui组件,则handlermessage方法就会执行 }else { Message msg=new Message(); msg.what=REQUESTNOTFOUND; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); Message msg=new Message(); msg.what=REQUESTEXCEPTION; handler.sendMessage(msg); } } }.start(); } }); bt_showImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //开启一个子线程 new Thread(){ @Override public void run() { try { File file=new File(getCacheDir(),"test.png"); //判断图片是否已经缓存 if(file.exists()&&file.length()>0){ System.out.println("使用缓存图片"); //7.利用BitmapFactory将InputStream类型的数据转换为Bitmap Bitmap bitmap=BitmapFactory.decodeFile(file.getAbsolutePath()); //8.1创建message对象 Message msg=new Message(); msg.obj=bitmap; //设置消息内容 msg.what=REQUESTIMAGESUCCESS; //设置消息代号 handler.sendMessage(msg); //利用handler告诉系统需要更新ui组件,则handlermessage方法就会执行 }else { System.out.println("第一次连接网络"); String picPath=et_website.getText().toString().trim(); //1.创建URL,指定我们要访问的网址 URL url=new URL(picPath); //2.获取HttpURLConnection对象,用于发送或接收数据 HttpURLConnection conn= (HttpURLConnection) url.openConnection(); System.out.println("-------------------flaglucky"); //3.设置请求格式为get conn.setRequestMethod("GET"); //注意get要求大写,默认为get请求 //4.设置请求的超时时间 conn.setConnectTimeout(5000); //5.获取服务器返回的状态码 int code=conn.getResponseCode(); System.out.println("--------------"+code); //如果code==200说明请求成功 if(code==200){ System.out.println("-------------------flagif"); //6.获取服务器返回的数据(以流的形式返回) InputStream in=conn.getInputStream(); //缓存图片(节省流量) FileOutputStream fos=new FileOutputStream(file); //创建一个向指定 File 对象表示的文件中写入数据的文件输出流。 int len=-1; byte[] buffer=new byte[1024]; //1kb while ((len=in.read(buffer))!=-1){ //从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。 fos.write(buffer,0,len); } fos.close(); in.close(); //7.利用BitmapFactory将InputStream类型的数据转换为Bitmap final Bitmap bitmap=BitmapFactory.decodeFile(file.getAbsolutePath()); // //8.1创建message对象 // Message msg=new Message(); // msg.obj=bitmap; //设置消息内容 // msg.what=REQUESTIMAGESUCCESS; //设置消息代号 // handler.sendMessage(msg); //利用handler告诉系统需要更新ui组件,则handlermessage方法就会执行 //使用runOnUiThread()方法相当于在主线程中执行run()方法 runOnUiThread(new Runnable() { @Override public void run() { iv_pic1.setImageBitmap(bitmap); } }); }else { Message msg=new Message(); msg.what=REQUESTNOTFOUND; handler.sendMessage(msg); } } } catch (Exception e) { e.printStackTrace(); Message msg=new Message(); msg.what=REQUESTEXCEPTION; handler.sendMessage(msg); } } }.start(); } }); } }
<2>工具类
package com.example.lucky.test54wanzhichakan; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; //流操作的工具类 public class StreamTools { //把一个inputStream转换为String public static String readStream(InputStream in) throws Exception { //定义一个内存输出流 ByteArrayOutputStream baos=new ByteArrayOutputStream(); int len=-1; byte[] buffer=new byte[1024];//大小为1kb while ((len=in.read(buffer))!=-1){ //read()方法:从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中,若到文件结尾返回-1 baos.write(buffer,0,len); } in.close(); //关闭流 String content=new String(baos.toByteArray()); return content; } }
7.效果图
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)