Android网络编程2

网络编程2

--------此笔记根据黑马程序员的授课视频所记录
Activity
网络编程1
网络编程2
广播接收者
服务
内容提供者
多媒体

1.使用httpurlconnection方式把数据提交到服务器

基于http协议

​ 【1】get和post提交的区别

​ 路径不同

	get方式提交:组拼URL地址把数据组拼到URL上  大小限制1kb(浏览器规定)  4kb(http协议规定)

​ post方式提交:post比get方式提交安全 数据没有大小限制 通过请求体的方式把数据写给服务器(也是以流的形式)

在这里插入图片描述

​ 【2】get方式提交数据 [联网记住要加权限]

//【2.1】定义get方式要提交的路径
String path = "http://***.***.***.***:8080?username="+name+"&pwd="+pwd;
//【2.2】获取httpurlconnection
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
int code = conn.getResponseCode();
if (code == 200) {
    //请求成功后的逻辑
    //获取服务器返回的数据 以流的形式返回
    InputStream in = conn.getInputStream();
    //通过工具类将流转换成字符串  InputStream in ➡ String content;
    
    //把服务器返回的数据展示到Toast上  (因为是网络请求所以此处就是子线程)
    runOnUiThread(new Runable(){
        public void run(){
            Toast.makeText(getApplicationContext(),content,1).show();
        }
    });
    
}

​ 【3】post方式提交数据

//【3.1】定义post方式要提交的路径
String path = "http://***.***.***.***:8080";//此处与get不同**********
//获取请求体
String data = "username="+name+"&pwd="+pwd;
//2.2】获取httpurlconnection
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");//此处与get不同***


//比get多设置两个请求头信息******
conn.setRequestProperty("Content-Type","application/x-www-form=urlencoded");//里面参数是一个key:value的类型
conn.setRequestProperty("Content-Lenght",data.length()+"");

//把组拼好的数据提交给服务器 以流的形式*******
conn.setDoOutput(true);//设置一个标记允许输出
conn.getOutStream().write(data.getBytes());


int code = conn.getResponseCode();
if (code == 200) {
    //请求成功后的逻辑
    //获取服务器返回的数据 以流的形式返回
    InputStream in = conn.getInputStream();
    //通过工具类将流转换成字符串  InputStream in ➡ String content;
    
    //把服务器返回的数据展示到Toast上  (因为是网络请求所以此处就是子线程)
    runOnUiThread(new Runable(){
        public void run(){
            Toast.makeText(getApplicationContext(),content,1).show();
        }
    });
    
}

2.乱码问题解决

​ ——————实际开发时不需要考虑,会有架包搞定

​ 因为客户端与服务端之间传输数据时是通过二进制传输的,所以解决乱码问题就是让服务端和服务端的编码格式相同就好了,哪个不一样改哪个,tomcat的默认编码格式是iso-8859-1,然而发送时的默认编码格式是gbk,在安卓当中编码格式默认都是utf-8;

​ 【1】解决服务端发送到客户端的乱码问题

​ 【1.1】服务端解决乱码问题

/*例*/
response.getOutputStream().write("返回服务器的信息".getBytes("utf-8"));

​ 【1.2】客户端解决乱码问题

/*例*/
String content = new String (baos.toByteArray(),"gbk");//此处是将从服务端拿过来的流信息转换为字符串时用gbk方式解码

​ 【2】解决客户端发送到服务端的乱码问题

/*例*/
//原理就是数据接收到后先以iso-8859-1的编码格式进行解码,然后再以utf-8的形式进行转码
new String(name.getBytes("iso-8859-1"),"utf-8");//其中name就是从客户端获取到的数据

//但是如果只这样进行转码的话再客户端还为乱码,但是再网页访问可以,因为网页给数据进行了一个url编码所以在Android中如果要进行转码需要将数据进行url的编码。此时有一个java类可以直接实现
URLEncoder.encode("要编码的内容","utf-8");

3.以httpclient方式把数据提交到服务器

​ 开源项目,阿帕奇的开源项目,谷歌拿过来封装好了 就是对http请求的封装

​ 谷歌一般以 base defalut simple 进行命名

​ 【1】get方式提交数据

//获取httpclient实例
DefaultHttpClient client = new DefaultHttpClient();
//准备一个get请求 定义一个Httpget实现
HttpGet get = new HttpGet(path);//path为服务器地址
//执行一个get请求
HttpResponse response = client.execute(get);
//获取服务器返回的状态码
int code = response.getStatusLine().getStatusCode();//返回getStatusLine()状态行,返回getStatusCode()状态码
if(code == 200){
    //获取服务器返回的数据 以流的形式返回
    InputStream inputStream = response.getEntity().getContent(); //getEntity()获取一个实体,getContent()获取一个流
    //把流通过工具类转换成一个字符串 InputStream inputStream ➡ String  content 
    //打印土司(记住因为现在是访问网络所以是在子线程中,打印土司用个runOnUiThread();)
    
    
}else{
    
}

​ 【2】post方式提交数据

String path = "http://***.***.***.***:8080";
//获取httpclient实例
DefaultHttpClient client = new DefaultHttpClient();
//准备post请求
HttpPost post = new HttpPost(path);


//准备parameters
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
//准备NameValuePair 实际上就是我们要提交的用户名密码  第一个参数key是服务器的key
BasicNameValuePair nameValuePair = new BasicNameValuePair("username",name);
BasicNameValuePair pwdValuePair = new BasicNameValuePair("password",pwd);
//将值加入到parameters集合中
parameters.add(nameValuePair);
parameters.add(pwdValuePair);
//准备entity
UrlEncodeFormEntity entity = new UrlEncodeFormEntity(parameters);
//以实体的形式准备post提交的正文信息(键值对的形式)
post.setEntity(entity);


//执行一个post请求
HttpResponse response = client.execute(post);
//获取服务器返回的状态码
int code = response.getStatusLine().getStatusCode();//返回getStatusLine()状态行,返回getStatusCode()状态码
if(code == 200){
    //获取服务器返回的数据 以流的形式返回
    InputStream inputStream = response.getEntity().getContent(); //getEntity()获取一个实体,getContent()获取一个流
    //把流通过工具类转换成一个字符串 InputStream inputStream ➡ String  content 
    //打印土司(记住因为现在是访问网络所以是在子线程中,打印土司用个runOnUiThread();}else{
    
}

4.开源项目方式把数据提交到服务器

5.javase多线程下载

​ 设置请求服务器文件的位置

conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);//此头信息是告诉服务器此线程访问的数据开始位置和结束位置

​ 【1】介绍

​ 【1.1】多线程加速下载,但是不是说线程越多下载越快,手机迅雷这款软件它建议是开3-4个线程

​ 【1.2】受服务器带宽的影响,受自己本身网络限制

​ 【1.3】多线程是拿了更多的cpu资源

​ 【2】步骤

​ 【2.1】获取文件大小

​ 【2.2】在客户端创建一个大小和服务器一摸一样的文件 提前申请好空间(此步可以省略)

​ 【2.3】计算好每一个下载的开始位置和结束位置

在这里插入图片描述
​ 【2.4】开多个线程取下载文件

​ 【2.5】知道每个线程什么时候下载完毕了

/*
*实例代码
*/
private static String path = "http://***.***.***.***:8080/xxx文件.exe";//定义下载路径
private static final int threadCount = 3; //假设开的线程数为3
private static final int runningThread;//表示正在运行的线程数量
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
int code = conn.getResponseCode();
if (code == 200) {
    //[1]获取服务器文件大小
    int length = conn.getContentLength();
    //把线程的数量赋值给正在运行的线程数
    runningThread = threadCount;
    //[2]创建出一个大小和服务器上的一摸一样的文件 目的是提前把空间申请出来
    RandomAccessFile rafAccessFile = new RandomAccessFile("文件名","rm");//第一个参数是生成的文件名,第二个参数是生成文件的模式。用此方法创建的文件是可以随机的访问读取和写入
    //设置生成文件的长度
    rafAccessFile.setLength(length);
    //[3]计算开始结束位置
    int blockSize = lenght/threadCount;
    for(int i=0;i<threadCount;i++){
        int startIndex = i*blockSize  //计算出每个线程下载的开始位置
        int endIndex = (i+1)*blockSize-1;//计算出每个线程下载的结束位置
        //特殊情况最后一个线程
        if(i == treadCount-1){
            endIndex = length-1;
        }
    }
    //[4]开启线程去下载文件
    DownLoadThread downLoadThread = new DownLoadThread(startIndex,endIndex,threadId);
    downLoadThread.start();
}else{
    
}


//定义一个线程去服务器下载文件
public static class DownLoadThread extends Thread{
    //通过构造方法把每个线程下载的开始位置和结束位置传进来
    private int startIndex;
    private int endIndex;
    private int threadId;
    public DownLoadThread(int startIndex,int endIndex,int threadId){
        this.startIndex = int startIndex;
        this.endIndex = int endIndex;
        this.threadId = int threadId;
    }
    public void run(){
        //实现去服务器下载文件的逻辑
        URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		conn.setRequestMethod("GET");
		conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);//此头信息是告诉服务器此线程访问的数据开始位置和结束位置        
		int code = conn.getResponseCode();//206代表请求部分资源成功  200是请求全部资源成功
		if (code == 206) {
            //创建随机读写对象
            RandomAccessFile raf = new RandomAccessFile("文件名","rm");
            //每个线程从自己的位置开始写
            raf.seek(startIndex);
			InputStream in = conn.getInputStream();//现在这个流就是下载返回的数据
            //把数据写到文件中
            int len = -1;
            byte[] buffer = new byte[1024];
            while((len == in.read(buffer))!=-1){
                raf.write(buffer,0,len);
            }
            raf.close();//关闭流释放资源
        }
}

6.断点续传实现

​ 原理:存一个文件记录上次下载到的位置,再次下载的时候检测此文件是否存在,若文件存在则提取里面记录的位置信息,将startIndex的位置变成此次记录的位置,然后再开始下载

​ 所以说要实现断点续传只需要更改去服务下载文件的这个类,下面代码为更改上一步的代码

//定义一个线程去服务器下载文件(添加了断点续传的功能版)
public static class DownLoadThread extends Thread{
    //通过构造方法把每个线程下载的开始位置和结束位置传进来
    private int startIndex;
    private int endIndex;
    private int threadId;
    public DownLoadThread(int startIndex,int endIndex,int threadId){
        this.startIndex = int startIndex;
        this.endIndex = int endIndex;
        this.threadId = int threadId;
    }
    public void run(){
        //实现去服务器下载文件的逻辑
        URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		conn.setRequestMethod("GET");
        
        //***********
        //如果中间断过 继续上次的位置下载 继续下载 从文件里读取上次下载的位置
        File file = new File(threadId+".txt");
        if (file.exists()&&file.length()>0){
            FileInputStream fis = new FileInputStream(file);
            BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
            String SlastPosition = bufr.readLine();//此处读取出来的就是上一次下载的内容
            int lastPosition = Integer.parseInt(SlastPosition);
            startIndex = lastPosition;
            fis.close();
        }
        //***********
        
        
		conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);//此头信息是告诉服务器此线程访问的数据开始位置和结束位置        
		int code = conn.getResponseCode();//206代表请求部分资源成功  200是请求全部资源成功
		if (code == 206) {
            //创建随机读写对象
            RandomAccessFile raf = new RandomAccessFile("文件名","rm");
            //每个线程从自己的位置开始写
            raf.seek(startIndex);
			InputStream in = conn.getInputStream();//现在这个流就是下载返回的数据
            //把数据写到文件中
            int len = -1;
            byte[] buffer = new byte[1024*1024];//1mb
            int total = 0;  //代表当前线程下载的大小**********
            while((len == in.read(buffer))!=-1){
                raf.write(buffer,0,len);
                //**********
                total+=len;
                //实现断点续传 就是把当前线程下载的位置给存起来下次再下载的时候 就是按照上次下载的位置继续下载就可以了
                int currentThreadPosition = startIndex+total//当前线程下载的大小加上起始位置就是当前下载的位置,然后存入一个txt文本中去
                //接下开始将当前位置信息存入到当前线程的文本中去
                RandomAccessFile raff = new RandomAccessFile(threadId+".txt","rwd");//存入的名称为当前线程的id.txt,模式为rwd
      			raff.write(String.valueOf(currentThreadPosition).getBytes());
        		raff.close();
                //**********
            }
            raf.close();//关闭流释放资源
            //**********
            //下载完成后删除记录位置的文件
             synchronized (DownLoadThread.class){//加一个线程锁避免冲突
            	runningThread--
                    if(runningThread == 0){//当runningThread等于0了,就代表所有的线程都下载完毕了,就可以开始删除文件了
                        for(int i=0;i<threadCount;i++){
                        File deleteFile = new File(i+".txt");
                        deleteFile.delete();
                    	}
                    }
                   
       		 } 
            //**********
            
        }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值