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 인터페이스의 업 데 이 트 를 완성 해 야 한 다 는 것 을 알 수 있 습 니 다.따라서 이 부분 은 우리 가 주의해 야 합 니 다.이식 후 코드 는 큰 변화 가 없 었 습 니 다.그러면 안 드 로 이 드 에 있 는 다 중 스 레 드 정지점 다운로드 기 를 완성 할 수 있 습 니 다.
이상 은 본 고의 모든 내용 입 니 다.여러분 이 안 드 로 이 드 소프트웨어 프로 그래 밍 을 배 우 는 데 도움 이 되 기 를 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.