0
点赞
收藏
分享

微信扫一扫

Android网络请求 上传文件 和 下载文件 断点下载


Get  Post   (Http)

HttpUrlConnection

Get:

1.创建一个URL地址
    URL url=new URL("http://www.baidu....?username=xxxx");
2.打开一个Http链接
    HttpUrlConnection conn=(HttpUrlConnection)url.openConnection();  
3.设置Get请求
    conn.setRequestMethod("GET");
4.返回数据前要判断下响应码
    if(conn.getResponseCode()==200){
5.如果响应码是200 读取数据
    conn.getInputStream();
    }

 

Post:

1.创建一个URL地址
    URL url=new URL("http://www.baidu....?username=xxxx");
2.打开一个Http链接
    HttpUrlConnection conn=(HttpUrlConnection)url.openConnection();
3.设置Post请求
    conn.setRequestMethod("Post");
4.设置请求头(这里有2个请求头,1声明表单提交 2声明提交参数的长度)
    conn.setRequestProperty("xxxx","xxxx");
5.提交数据到服务器(向服务器提交的开关默认是关闭)
    conn.setDoOutput(true);
    conn.getOutputStream().write("xxxxxx");
6.返回数据前要判断下响应码
    if(conn.getResponseCode()==200){
     7.如果响应码是200 读取数据
    conn.getInputStream();
    }

HttpClient(安卓6.0以后就被抛弃了)面向接口的编程

 

Get:

1.创建一个浏览器
    HttpClient client=new DefaultHttpClient();  //AndroidDefaultHttpClient
2.声明一个Get请求
    HttpGet request=new HttpGet("url地址");
3.执行一个Get请求
    HttpResponse response=client.execute(request);
4.拿到响应码--->响应行
    StatusLine line=response.getStatusLine();
    int responseCode=line.getStatusCode();
5.读取数据  不管是请求的参数还是响应的参数 全部封装到HttpEntity
    HttpEntity entity=response.getEntity();
    InputStream is=entity.getContent();

Post:

1.创建一个浏览器
    HttpClient client=new DefaultHttpClient();  //AndroidDefaultHttpClient
2.声明一个Post请求
    HttpPost request=new HttpPost("url地址");
3.将参数添加到请求里面
    ArrayList<NameValuePaire> params=new ArrayList<NameValuePaire>();
        for(){
          params.add(new BasicNameValuePaire("key","value"));
        }
    HttpEntity entity=new UrlEncodedFormEntity(params);
    request.setEntity(entity);
4.执行一个Post请求
    HttpResponse response=client.execute(request);
4.拿到响应码--->响应行
    StatusLine line=response.getStatusLine();
    int responseCode=line.getStatusCode();
5.读取数据  不管是请求的参数还是响应的参数 全部封装到HttpEntity
    HttpEntity entity=response.getEntity();
    InputStream is=entity.getContent();


注意点:
1.网络权限
2.子线程
3.返回主线程修改UI

 

 

 

网络请求的方式

1.采用Get方式提交数据到服务器

        Get请求在网页发送过程中的抓包:

Android网络请求   上传文件   和   下载文件   断点下载_服务器

 

        在安卓代码中如何使用Get请求网络数据:

Android网络请求   上传文件   和   下载文件   断点下载_java_02



2.采用Post方式提交数据到服务器

    Post请求在网页发送过程中的抓包:

Android网络请求   上传文件   和   下载文件   断点下载_java_03

  在安卓代码中如何使用Post请求网络数据:

   

Android网络请求   上传文件   和   下载文件   断点下载_android_04

3.Get和Post请求数据的比较

        根据HTTP标准,HTTP请求可以使用多种请求方法。

        HTTP1.0定义了三种请求方法: GET,POST 和 HEAD方法。

        HTTP1.1新增了五种请求方法:OPTIONS,PUT, DELETE, TRACE 和 CONNECT 方法。

        在客户机和服务器之间进行请求-响应时,两种最常被用到的方法是:GET和 POST。

Android网络请求   上传文件   和   下载文件   断点下载_java_05

 

GET 方法

优点:代码简单 容易编写只需要在url后面组拼字符串

缺点:不可以提交太大的数据,规定组拼路径最大长度不超过4k, 不安全。

请注意,查询字符串(名称/值对)是在 GET 请求的URL 中发送的:

/test/demo_form.asp?name1=value1&name2=value2

POST 方法

优点:安全,用流的方式把数据写入到服务器提交数据没有最大长度的限制

缺点:代码编写不方便。

请注意,查询字符串(名称/值对)是在 POST 请求的HTTP 消息主体中发送的:

POST /test/demo_form.aspHTTP/1.1

Host: w3schools.com

name1=value1&name2=value2

网络请求的注意点:

1. 在安卓4.0版本以后请求网络的代码不能在主线程中运行。

2. 使用网络请求必须在AndroidMenifest.xml文件中申明使用权限。

 在<manifest />标签内添加<uses-permissionandroid:name="android.permission.INTERNET" />

 

 

 

HttpClient的应用

 

1.HttpClient的Get和Post请求

前面我们讲解了使用HttpUrlConnection来处理Http的两种常用请求,接下来我们使用一套名叫HttpClient的面向对象的API处理Http请求,至于工作中如何对请求选型,同学们可以根据对代码熟悉程度来决定。

1.HttpClient的Get请求:

Android网络请求   上传文件   和   下载文件   断点下载_android_06

 

2.HttpClient的Post请求:

Android网络请求   上传文件   和   下载文件   断点下载_java_07

 

 

 

3.开源HttpClient的Pos请求


除了上面两种安卓官方指定的请求方式,当面还有一些第三方的开源项目可以使用,这里介绍另外一个工具android-async-http-master,其可以在github

上下载。以下简单介绍其开发步骤:

1. 导包:

资料\第三方资料\android-async-http-master\library\src\main\java

2. 在AndroidMenifest.xml文件中申明使用权限 :

在<manifest />标签内添加<uses-permissionandroid:name="android.permission.INTERNET" />

3. 找到主要的类:

该类支持的方法有delete  get  header post put...

Android网络请求   上传文件   和   下载文件   断点下载_服务器_08

 

4. 实现代码:

如下post方法有三个参数 1. 网络地址 2.请求参数 3.返回值的监听器

Android网络请求   上传文件   和   下载文件   断点下载_服务器_09

 

5.开源HttpClient文件上传

android-async-http-master除了可以在请求过程中发送请求参数还可以做上传文件的功能。

上传文件一般需要使用到两个参数  一个是文件名(比如key=”fName” value=”aa.jpg”) 一个是要上传的文件 (key=”file” value=”上传的文件流”)

Android网络请求   上传文件   和   下载文件   断点下载_android_10

 

开发步骤:

1. 服务器准备好 upload项目  客户端将所需要上传的文件添加到sd卡里面

2. 添加权限

Android网络请求   上传文件   和   下载文件   断点下载_服务器_11

 

3. 写代码:

Android网络请求   上传文件   和   下载文件   断点下载_java_12

 

多线程断点下载

 

1.多线程下载原理01

Android网络请求   上传文件   和   下载文件   断点下载_服务器_13

2.多线程下载原理02

 

网络下载文件制定位置的请求头

Range,"bytes=100-200"

RandomAccessFile类的构造方法中如下模式

"r"    以只读方式打开。

"rw"    打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。   

"rws"    打开以便读取和写入,实时将内存数据写入到文件里面去的,不单修改文件里面的内容  修改了这个描述这个文件里面的元数据

"rwd"    打开以便读取和写入,实时将内存数据写入到文件里面去的,主要只修改文件里面的内容

"rws" 和"rwd" 模式的工作方式极其类似 :

如果该文件位于本地存储设备上,那么当返回此类的一个方法的调用时,可以保证由该调用对此文件所做的所有更改均被实时写入该设备。这对确保在系统崩溃时不会丢失重要信息特别有用。

 

package com.li.ThreadUnload;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {
	private static final int MAX_THREAD_COUNT=3;//表示最大线程
	private static  int mReadCount;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
	}
	
	
	
	public void clickUnLoad(View v){
		new Thread(){
			public void run() {
				try {
					//1.获取下服务器里面文件的大小并且在手机创建一个一模一样的大小的空文件
						URL url = new URL(getUrlPath());
						HttpURLConnection conn=(HttpURLConnection)url.openConnection();//打开网页
						if (conn.getResponseCode()==200) {
							//获取文件的大小
							int contentLength=conn.getContentLength();
							//如果要创建一个空文件在file对象里面是没有的要到
							File file = new File(getFilesDir(),getFileName(getUrlPath()));
							RandomAccessFile random = new RandomAccessFile(file, "rw");
							random.setLength(contentLength);
						//2.创建n条线程并且把文件分割成n等分(最后那条线程应该吧剩下的内容读完)
							
							//知道了文件的长度还有线程数就可以等到每个线程应该读取的大小内容
							int perSize=contentLength/MAX_THREAD_COUNT;
							mReadCount=0;
							for(int i=0;i<MAX_THREAD_COUNT;i++){
								//startPosition 每一个线程应该下载的起始位置
								int startPosition = i*perSize;
								//endPosition  每一个线程应该下载的结束位置
								int endPosition=(i+1)*perSize-1;
								if(i==MAX_THREAD_COUNT-1){//最后一个线程下载剩下的资源
									endPosition=contentLength-1;
								}
								//创建三个子线程下载
								new DownLoadThread(i,startPosition, endPosition).start();
								
								
							}	
						}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			};
		}.start();
		
	}
	
	
	
	//创建子线程
	class DownLoadThread extends Thread{
		int mStartPosition;
		int mEndPosition;
		int mThreadIndex;
		public DownLoadThread(int i,int startPosition,int endPosition){
			this.mStartPosition=startPosition;
			this.mEndPosition=endPosition;
			this.mThreadIndex=i;
		}
		
		
		@Override
		public void run() {
			try {
				//1.跟服务器谈一谈 我想下载某个文件一部分
				URL url = new URL(getUrlPath());
				HttpURLConnection conn=(HttpURLConnection)url.openConnection();
				//通过请求头告诉服务器
					//Range,"bytes=100-200"  就是告诉服务器想下载文件从100~200字节的位置
				conn.setRequestProperty("Range", "bytes="+mStartPosition+"-"+mEndPosition);
				//如果只是获取文件的某部分  此时响应码不是200 而应该是206
				if(conn.getResponseCode()==206){
					InputStream is=conn.getInputStream();
				//2.告诉手机系统我想写某个文件的某一部分
				//RandomAccessFile 可以跳到文件某个位置之后开始写文件
				File file = new File(getFilesDir(),getFileName(getUrlPath()));
			
				RandomAccessFile random = new RandomAccessFile(file, "rw");
				random.skipBytes(mStartPosition);//skipBytes 跳过了多少个字节 就是每一个线程的起点
				//3.开始写文件  数据的来源从InputStream来
				byte[] buff=new byte[1024];
				int readCount;
				while((readCount=is.read(buff))>0){
					random.write(buff, 0, readCount);
				}
				
				random.close();
				}
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally {
				mReadCount++;
				if(mReadCount==MAX_THREAD_COUNT){
					Log.v("wang", "下载成功");
				}
			}
		}
	}
	/**
	 * 获取网络地址
	 * @return  返回网络地址
	 */
	public String getUrlPath(){
		return "http://10.140.0.186:8080/resource.rar";
	}
	/**
	 * 根据网络地址切割返回需要下载的文件名
	 * @param name 网络资源地址
	 * @return	
	 */
	public String getFileName(String name){
		return name.substring(name.lastIndexOf("/")+1);
	}
}

<strong>布局代码</strong>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="clickUnLoad"
        android:text="点击多线程下载" />

</LinearLayout>

 

 

3.多线程断点下载原理

 

 

Android网络请求   上传文件   和   下载文件   断点下载_android_14

 

开发步骤:

1.  创建一个变量mLastPosition  记录上次保存的位置。默认赋值为mStartPosition.当发现有保存进度的文件,则从保存进度的文件中获取。

开发代码

package com.li.ThreadUnload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;

public class MainActivity extends Activity {
	private static final int MAX_THREAD_COUNT=3;//表示最大线程
	private static  int mReadCount;
	private LinearLayout mLinear;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mLinear=(LinearLayout)findViewById(R.id.linearLayout);
	}
	
	
	
	public void clickUnLoad(View v){
		//ProgressBar多少个取决线程的数量
		mLinear.removeAllViews();
		for(int i=0;i<MAX_THREAD_COUNT;i++){
			View view=LayoutInflater.from(this).inflate(R.layout.pb_layout, null);
			mLinear.addView(view);
		}
		new Thread(){
			public void run() {
				try {
					//1.获取下服务器里面文件的大小并且在手机创建一个一模一样的大小的空文件
						URL url = new URL(getUrlPath());
						HttpURLConnection conn=(HttpURLConnection)url.openConnection();//打开网页
						if (conn.getResponseCode()==200) {
							//获取文件的大小
							int contentLength=conn.getContentLength();
							//如果要创建一个空文件在file对象里面是没有的要到
							File file = new File(getFilesDir(),getFileName(getUrlPath()));
							RandomAccessFile random = new RandomAccessFile(file, "rw");
							random.setLength(contentLength);
						//2.创建n条线程并且把文件分割成n等分(最后那条线程应该吧剩下的内容读完)
							
							//知道了文件的长度还有线程数就可以等到每个线程应该读取的大小内容
							int perSize=contentLength/MAX_THREAD_COUNT;
							mReadCount=0;
							for(int i=0;i<MAX_THREAD_COUNT;i++){
								//startPosition 每一个线程应该下载的起始位置
								int startPosition = i*perSize;
								//endPosition  每一个线程应该下载的结束位置
								int endPosition=(i+1)*perSize-1;
								if(i==MAX_THREAD_COUNT-1){//最后一个线程下载剩下的资源
									endPosition=contentLength-1;
								}
								//创建三个子线程下载
								new DownLoadThread(i,startPosition, endPosition).start();
							}	
							
							
						}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			};
		}.start();
		
	}
	
	
	
	//创建子线程
	class DownLoadThread extends Thread{
		int mStartPosition;
		int mEndPosition;
		int mThreadIndex;
		int mLastPosition;
		public DownLoadThread(int i,int startPosition,int endPosition){
			this.mStartPosition=startPosition;
			this.mEndPosition=endPosition;
			this.mThreadIndex=i;
			this.mLastPosition=startPosition;
		}
		
		
		@Override
		public void run() {
			//mLinear 有都少个ProgressBar
			//getChildAt 找到容器里面的子控件
			View view=mLinear.getChildAt(mThreadIndex);
			final ProgressBar pd=(ProgressBar)view.findViewById(R.id.seekBar1);
			runOnUiThread(new Runnable() {
				@Override
				public void run() {
					pd.setMax(mEndPosition-mStartPosition);
				}
			});
			try {
				//判断
				//判断有没有当前线程的记录进行的文件  如果有 那么最新的下载位置应该从记录文件的位置中来找
				File lastRecordFile=getRecordFile(mThreadIndex, getFileName(getUrlPath()));
				if(lastRecordFile.exists()&&lastRecordFile.length()>0){
					InputStream is = new FileInputStream(lastRecordFile);
					BufferedReader br = new BufferedReader(new InputStreamReader(is));
					mLastPosition=Integer.parseInt(br.readLine());
				}
				//1.跟服务器谈一谈 我想下载某个文件一部分
				URL url = new URL(getUrlPath());
				HttpURLConnection conn=(HttpURLConnection)url.openConnection();
				//通过请求头告诉服务器
					//Range,"bytes=100-200"  就是告诉服务器想下载文件从100~200字节的位置
				conn.setRequestProperty("Range", "bytes="+mLastPosition+"-"+mEndPosition);
				//如果只是获取文件的某部分  此时响应码不是200 而应该是206
				if(conn.getResponseCode()==206){
					InputStream is=conn.getInputStream();
				//2.告诉手机系统我想写某个文件的某一部分
				//RandomAccessFile 可以跳到文件某个位置之后开始写文件
				File file = new File(getFilesDir(),getFileName(getUrlPath()));
			
				RandomAccessFile random = new RandomAccessFile(file, "rw");
				random.skipBytes(mLastPosition);//skipBytes 跳过了多少个字节 就是每一个线程的起点
				//3.开始写文件  数据的来源从InputStream来
				byte[] buff=new byte[1024];
				int readCount;
				while((readCount=is.read(buff))>0){
					random.write(buff, 0, readCount);
					mLastPosition+=readCount;
					//保存一下mListPosition的大小    如果软件关闭就可以到文件中读取该文件的索引
					File recordFile=getRecordFile(mThreadIndex, getFileName(getUrlPath()));
					//需要保存当前进度使用RandomAeecssFile
					//RandomAeecssFile 可以实时的写数据到硬盘中
					RandomAccessFile recordRandom = new RandomAccessFile(recordFile, "rwd");
					recordRandom.write((mLastPosition+"").getBytes());//写入文件
				
					runOnUiThread(new Runnable() {
						@Override
						public void run() {
							pd.setProgress(mLastPosition-mStartPosition);
						}
					});
				
				}
				
				random.close();
				}
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally {
				mReadCount++;
				if(mReadCount==MAX_THREAD_COUNT){
					Log.v("wang", "下载成功");
					for(int i=0;i<MAX_THREAD_COUNT;i++){
						Log.v("wang","");
						File file=new File(getFilesDir(),getRecordFile(i,getFileName(getUrlPath())).getName());
						file.delete();
					}
				}
			}
		}
	}
	/**
	 * 获取网络地址
	 * @return  返回网络地址
	 */
	public String getUrlPath(){
		return "http://10.140.0.186:8080/resource.rar";
	}
	/**
	 * 根据网络地址切割返回需要下载的文件名
	 * @param name 网络资源地址
	 * @return	
	 */
	public String getFileName(String name){
		return name.substring(name.lastIndexOf("/")+1);
	}
	/**
	 * 为每一条线程创建一个记录当前进度文件
	 */
	private File getRecordFile(int threadPosition,String fileName){
		//fileName传一个值过来 resource.rar
		fileName=fileName.substring(0, fileName.lastIndexOf("."));
		return new File(getFilesDir(),fileName+"#"+threadPosition+".txt");
	}
}

 

布局代码

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="clickUnLoad"
        android:text="点击多线程下载" />
    <!-- 创建一个容器垓容器是用包含进度条的动态创建进度条 -->
	<LinearLayout
	  android:id="@+id/linearLayout"
	  android:layout_width="match_parent"
   	  android:layout_height="match_parent"
      android:orientation="vertical">
	    
	    
	</LinearLayout>
</LinearLayout>

 

pb_layout.xml

<?xml version="1.0" encoding="utf-8"?>
    <SeekBar
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/seekBar1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

 

举报

相关推荐

0 条评论