Android 는 다 중 스 레 드 를 사용 하여 정지점 다운 로드 를 실현 합 니 다.

다 중 스 레 드 다운 로드 는 다운로드 속 도 를 빠르게 하 는 방식 이다.여러 스 레 드 를 켜 서 하나의 미 션 을 수행 합 니 다.미 션 의 실행 속 도 를 빠르게 할 수 있 습 니 다.다 중 스 레 드 의 미 션 다운 로드 는 항상 사용 할 수 있 습 니 다.예 를 들 어 우리 핸드폰 내부 응용 프로그램의 다운로드 체 제 는 다 중 스 레 드 를 사용 하여 만 든 다운로드 기 입 니 다.그리고 이 다운로드 기 는 정지점 다운 로드 를 실현 할 수 있 습 니 다.미 션 이 강제로 종 료 된 후에..다음 에 트리거 를 통 해 누 를 수 있 습 니 다.단 추 를 누 르 면 정지점 다운 로드 를 완성 합 니 다.그러면 정지점 다운 로드 를 어떻게 실현 하 느 냐 가 문제 입 니 다.
  우선 명확 한 것 은 다 중 스 레 드 다운로드 기 가 여러 스 레 드 를 사용 하여 같은 작업 을 다운로드 하 는 것 입 니 다.그러나 이 다 중 스 레 드 는 스 레 드 의 수량 이 많 을 수록 다운로드 속도 가 빨 라 지 는 것 이 아 닙 니 다.스 레 드 가 많이 증가 할 때...단일 스 레 드 의 실행 효율 도 느 려 집 니 다.따라서 스 레 드 의 수량 은 한계 가 있어 야 합 니 다.건물 주가 직접 테스트 를 거 쳐 야 합 니 다.다 중 스 레 드 가 같은 임 무 를 다운로드 할 때 스 레 드 의 수량 5-8 개 는 비교적 효율 적 인 편 입 니 다.스 레 드 의 수량 이 10 개 를 넘 으 면 다 중 스 레 드 의 효율 은 오히려 느 려 집 니 다(전제:네트워크 속도 가 대체적으로 같 을 때..)
  그러면 다 중 스 레 드 로 같은 미 션 을 다운로드 할 때 그 이 치 를 알 아야 합 니 다.다음은 추가 그림 을 보 겠 습 니 다.

  이 그림 은 사실 그 원 리 를 간단하게 설명 하고 있 습 니 다.우 리 는 하나의 미 션 을 여러 부분 으로 나 누 었 습 니 다.그리고 여러 스 레 드 를 열 어 해당 하 는 부분 을 다운로드 하면 됩 니 다.그러면 먼저 해결 해 야 할 문 제 는 각자 의 스 레 드 를 어떻게 각자 의 미 션 을 다운로드 하 느 냐 하 는 것 입 니 다.경 계 를 넘 을 수 없습니다...그러면 구체 적 인 실현 과정 을 살 펴 보 겠 습 니 다.우선 우 리 는 일반 자바 코드 를 사용 하여 실현 합 니 다.마지막 으로 자바 코드 를 Android 에 이식 하면 됩 니 다...

public class Download {

  public static int threadCount = 5;  //       ..
  public static void main(String[] args) {
    // TODO Auto-generated method stub

    String path = "http://192.168.199.172:8080/jdk.exe";
    try {
      URL url = new URL(path);
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      conn.setRequestMethod("GET");
      conn.setConnectTimeout(5000);
      int status = conn.getResponseCode();
      
      if(status == 200){
        int length = conn.getContentLength();
      
        System.out.println(length);
        
        int blocksize = length/threadCount; //         ..
        
        for(int threadID=1; threadID<=threadCount;threadID++){
          
          int startIndex = (threadID-1)*blocksize; //       ..
          int endIndex = threadID*blocksize -1;   //       ..
           
          /**
           *                 ..
           *                        ..
           * */
          if(threadID == threadCount){        
            endIndex = length;           
          }
          
          System.out.println("      :"+startIndex+"---"+endIndex);
        }
      }
      
      
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

  이렇게 하면 서버 연결 을 통 해 파일 의 길 이 를 얻 을 수 있 습 니 다.그리고 모든 스 레 드 다운로드 의 시작 위치 와 끝 위 치 를 설정 합 니 다.여 기 는 이러한 절차 만 완 료 했 습 니 다.다운로드 의 시작 위치 와 끝 위치 가 있 습 니 다.우 리 는 스 레 드 를 열 어 하 재 를 완성 해 야 합 니 다.그래서 우 리 는 스스로 다운로드 과정 을 정의 해 야 합 니 다.
  우선 우 리 는 명확 한 사고방식 을 가 져 야 한다.인 터 럽 트 다운로드 인 이상...인 터 럽 트 상황 이 발생 하면...우 리 는 다음 에 다운 로드 를 할 때 원래 끊 어 진 위치 에서 다운 로드 를 해 야 한다..이미 다운 로드 된 위치 에서 다운 로드 를 할 필요 가 없다..따라서 우 리 는 매번 의 다운로드 기록 을 기록 해 야 한다.그러면 기록 이 있 으 면...파일 다운로드 가 완료 되면..이 기록 들 은 지 워 져 야 하기 때문에 이 두 곳 의 생각 을 명 확 히 하면 쉽게 쓸 수 있다.

//       ..  
public static class DownLoadThread implements Runnable{

    private int threadID;
    private int startIndex;
    private int endIndex;
    private String path;
    
    public DownLoadThread(int threadID,int startIndex,int endIndex,String path){
      
      this.threadID = threadID;
      this.startIndex = startIndex;
      this.endIndex = endIndex;
      this.path = path;
      
    }
    
    @Override
    public void run() {
      // TODO Auto-generated method stub
      
      try {
        
        //           ..                ..               ..
        File tempfile =new File(threadID+".txt");
        if(tempfile.exists() && tempfile.length()>0){
          
          FileInputStream fis = new FileInputStream(tempfile);
          byte buffer[] = new byte[1024];
          int leng = fis.read(buffer);
          int downlength = Integer.parseInt(new String(buffer,0,leng));//             ..           ..
          startIndex = downlength;
          fis.close();
        }
        
        URL url = new URL(path);
        HttpURLConnection conn =(HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setConnectTimeout(5000);
        conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
        
        int status = conn.getResponseCode();
        //206          ..
        if(status == 206){
          
          //        I/O ..           ..
          InputStream in = conn.getInputStream();
          
          //      ..             ..
          RandomAccessFile raf = new RandomAccessFile("jdk.exe", "rwd");
          raf.seek(startIndex);
          
          
          int len = 0;
          byte buf[] =new byte[1024];
          
          //         ..
          int total = 0;
          
          while((len = in.read(buf))!=-1){
            
            //           ..
            RandomAccessFile file =new RandomAccessFile(threadID+".txt", "rwd");
            total += len;
            file.write((total+startIndex+"").getBytes());
            file.close();
            //         ..
            raf.write(buf, 0, len);
            
          }
          in.close();
          raf.close();
          
          
        }  
        
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }finally{
        //              ..       ..            ..
        runningThread -- ;
        if(runningThread==0){
          for(int i=1;i<threadCount;i++){
            File file = new File(i+".txt");
            file.delete();
          }
        }
      }
    }
  }

  이렇게 해서 파일 의 데이터 정보 다운 로드 를 완 료 했 습 니 다그렇다면?그래서 건물 주 는 90M 의 파일 이 5 개의 스 레 드 와 동시에 작용 하 는 시간 차 가 1 분 20 초 정도 차이 가 나 지 않 는 다 는 것 을 직접 측정 했다.한 스 레 드 를 사용 하여 다운로드 하 는 것 은 2 분 정도 차이 가 나 지 않 는 다.여 기 는 많은 시간 을 단축 시 켰 다.
 그래서 비교 해 보면역시 여러 개의 스 레 드 를 사용 하여 다운 로드 를 하 는 것 이 좋 습 니 다.안 드 로 이 드 의 일반적인 응용 프로그램 은 50m 정 도 를 넘 지 않 지만...게임 의 경우 100-200 M 정도 차이 가 나 지 않 습 니 다.따라서 다 중 스 레 드 를 사용 하면 다운로드 의 진도 와 효율 을 높 일 수 있 습 니 다.마찬가지 로 우 리 는 스 레 드 풀 을 사용 하 는 방식 으로 스 레 드 를 열 수 있 습 니 다.마지막 으로 이 스 레 드 풀 에 맡 겨 관리 하면 됩 니 다.이 젠..
 정상 적 인 자바 프로젝트 에서 다운로드 코드 를 적 었 습 니 다............................................................................

package com.example.mutithread;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

  private EditText et;
  private ProgressBar pb;
  public static int threadCount = 5;
  public static int runningThread=5;
  public int currentProgress=0; //     ..
  private TextView tv;
  
  
  private Handler handler = new Handler(){
    
    @Override
    public void handleMessage(Message msg){
      switch (msg.what) {
      case 1:
        Toast.makeText(getApplicationContext(), msg.obj.toString(), 0).show();
        break;
      case 2:
        break;
      case 3:
        tv.setText("    :"+(pb.getProgress()*100)/pb.getMax());
      default:
        break;
      }
    }
  };
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    et = (EditText) findViewById(R.id.et);
    pb =(ProgressBar) findViewById(R.id.pg);
    tv= (TextView) findViewById(R.id.tv);
  }

  public void downLoad(View v){
    final String path = et.getText().toString().trim();
    if(TextUtils.isEmpty(path)){
      Toast.makeText(this, "      ", Toast.LENGTH_LONG).show();
      return ;
    }
    
    new Thread(){
//      String path = "http://192.168.199.172:8080/jdk.exe";
      public void run(){
        try {
          URL url = new URL(path);
          HttpURLConnection conn = (HttpURLConnection) url.openConnection();
          conn.setRequestMethod("GET");
          conn.setConnectTimeout(5000);
          int status = conn.getResponseCode();
          
          if(status == 200){
            int length = conn.getContentLength();
            System.out.println("     "+length);
            pb.setMax(length);
            
            
            RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe","rwd");
            raf.setLength(length);
            raf.close();
            
            
            //  5          ..
            int blockSize = length/threadCount ;
            
            for(int threadID=1;threadID<=threadCount;threadID++){
              
              int startIndex = (threadID-1)*blockSize;
              int endIndex = threadID*blockSize -1;
              
              if(threadID == threadCount){
                endIndex = length; 
              }
              System.out.println("  "+threadID+"  :---"+startIndex+"--->"+endIndex);
              new Thread(new DownLoadThread(threadID, startIndex, endIndex, path)).start() ;
            }
          }
          
          
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      };
      
    }.start();
  }
  /** 
   *     ..
   * */
  public class DownLoadThread implements Runnable{

    private int ThreadID;
    private int startIndex;
    private int endIndex;
    private String path;
    
    public DownLoadThread(int ThreadID,int startIndex,int endIndex,String path){
      this.ThreadID = ThreadID;
      this.startIndex = startIndex;
      this.endIndex = endIndex;
      this.path = path;
    }
    @Override
    public void run() {
      // TODO Auto-generated method stub
      URL url;
      try {    
        //               ...
        File tempfile = new File("/sdcard/"+ThreadID+".txt");
        if(tempfile.exists() && tempfile.length()>0){
          FileInputStream fis = new FileInputStream(tempfile);
          byte temp[] =new byte[1024];
          int leng = fis.read(temp);
          int downlength = Integer.parseInt(new String(temp,0,leng));
          
          int alreadydown = downlength -startIndex;
          
          currentProgress += alreadydown;//               ..
          
          startIndex = downlength;
          fis.close();
        }
        
        
        url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
        conn.setConnectTimeout(5000);
        
        //     ..
        int status =conn.getResponseCode();
        
        if(status == 206){
          InputStream in = conn.getInputStream();
          RandomAccessFile raf =new RandomAccessFile("/sdcard/jdk.exe", "rwd");
          
          //      ..
          raf.seek(startIndex);
          
          int len =0;
          byte[] buffer =new byte[1024];
          
          //         ..
          int total = 0;
          
          
          while((len = in.read(buffer))!=-1){
            //           ...
            RandomAccessFile file = new RandomAccessFile("/sdcard/"+ThreadID+".txt", "rwd");
            
            raf.write(buffer, 0, len);
            total += len;
            System.out.println("  "+ThreadID+"total:"+total);
            file.write((total+startIndex+"").getBytes());
            file.close();
            
            synchronized (MainActivity.this) {
              currentProgress += len; //       ...
               //progressBar progressDialog            UI..              ..
               pb.setProgress(currentProgress); //           ..
               Message msg =Message.obtain(); //       ..    new...
               msg.what = 3;
               handler.sendMessage(msg);
               
            }
          }
          raf.close();
          in.close();
          System.out.println("  :"+ThreadID+"    ");
        }else{
          System.out.println("  :"+ThreadID+"    ");
        }
        
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        Message msg = new Message();
        msg.what = 1;
        msg.obj = e;
        handler.sendMessage(msg);
      }finally{
        synchronized (MainActivity.this) {
          runningThread--;
          
          if(runningThread == 0){
            for(int i=1;i<=threadCount;i++){
              File file = new File("/sdcard/"+i+".txt");
              file.delete();
            }
            Message msg =new Message();
            msg.what = 2;
            msg.obj ="    ";
            handler.sendMessage(msg);
          }
        }  
        
      }
  
    }
    
  }
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

}

  소스 코드 는 위 와 같 습 니 다..최 적 화 된 일 은 하지 않 겠 습 니 다..편 의 를 위해 바로 붙 였 습 니 다..여기 서 ProgressBar 진도 바 를 정 의 했 습 니 다..TextView 하나 로 진도 바 의 다운로드 진 도 를 동기 화 합 니 다..Android 에서 우 리 는 자 연 스 럽 게 메 인 스 레 드 에서 시간 을 소모 하 는 작업 을 호출 할 수 없습니다.이 때문에 우 리 는 하위 스 레 드 를 여 는 방식 으로 사용 합 니 다.그러나 하위 스 레 드 는 그렇지 않 습 니 다.UI 인 터 페 이 스 를 업데이트 할 수 있 는...따라서 메 인 인터페이스 UI 업 데 이 트 를 위해 Handler Message 메커니즘 을 사용 해 야 합 니 다.
  하지만 위의 코드 에서 우 리 는 문 제 를 발견 할 수 있 습 니 다.하위 스 레 드 내부 에서 ProgressBar 작업 을 업 데 이 트 했 습 니 다.사실 ProgressBar 와 ProgressDialog 는 두 가지 특례 입 니 다.우 리 는 하위 스 레 드 내부 에서 그들의 속성 을 업데이트 할 수 있 습 니 다.소스 코드 의 실현 과정 을 살 펴 보 겠 습 니 다.

 private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
    if (mUiThreadId == Thread.currentThread().getId()) { //               ..       ..
      doRefreshProgress(id, progress, fromUser, true);
    } else { //           ..
      if (mRefreshProgressRunnable == null) {
        mRefreshProgressRunnable = new RefreshProgressRunnable();//         ..         ..
      }

      final RefreshData rd = RefreshData.obtain(id, progress, fromUser); //          ..
      mRefreshData.add(rd);
      if (mAttached && !mRefreshIsPosted) {
        post(mRefreshProgressRunnable); //       ..   post  ..                 ..          UI    ..          ..
        mRefreshIsPosted = true;
      }
    }
  }

  바로 소스 코드 내부 에서 post 방법 을 호출 했 기 때 문 입 니 다.현재 스 레 드 를 메시지 큐 에 넣 습 니 다.그러면 UI 의 Looper 스 레 드 는 이 스 레 드 를 처리 합 니 다.그러면 이 스 레 드 는 UI 에서 실 행 될 수 있다 는 뜻 입 니 다.바로 이 요소 로 인해 우 리 는 하위 스 레 드 내부 에서 Progressbar 를 업데이트 할 수 있 습 니 다.그러나 우리 가 TextView 를 업데이트 하려 면 Handler Message 체 제 를 사용 하여 UI 인터페이스의 업 데 이 트 를 완성 해 야 한 다 는 것 을 알 수 있 습 니 다.따라서 이 부분 은 우리 가 주의해 야 합 니 다.
  이식 후 코드 는 큰 변화 가 없 었 습 니 다.그러면 안 드 로 이 드 에 있 는 다 중 스 레 드 정지점 다운로드 기 를 완성 할 수 있 습 니 다.
이상 은 본 고의 모든 내용 입 니 다.여러분 이 안 드 로 이 드 소프트웨어 프로 그래 밍 을 배 우 는 데 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기