0
回答
android多线程下载网站上资源
华为云4核8G,高性能云服务器,免费试用   

大家好,今天自己写了一个安卓下多线程下载网站上资源的一个demo,遇到了一个奇怪的问题,下面是源代码,就2个文件,布局文件activity_main.xml和MainActivity.java,代码见下

实现流程:将服务器资源分成3部分,每个部分使用一个线程下载,为了实现能断点续传,将每个线程下载到的资源索引位置记录到文件中(sdcard/*.txt  如第一个线程的文件就是1.txt,第二个就是2.txt),下次再下载的时候加载线程时先去读取文件中的索引位置,然后从索引开始接着下载,为了使下载完成后能自动删除这个索引文件,设置了一个属性为3,在每次一个线程执行下载完后去减去1,当等于0的时候,一次性删除所有的文件。

具体问题描述如下:

1.先运行一遍程序,文件下载成功,sdcard文件夹中线程索引文件也被自动清除,只剩下载好的文件。(运行正常)
2.不结束这个程序进程,删除下载的文件,然后重新点击下载按钮再下载一次文件,当三个线程都提示下载完成时,但是最后的删除3个进程的缓存文件的那段代码,却没有执行,也就是说,线程类中的最后那个finally代码块中的代码并,没有执行。
3.再次删除索引文件和exe文件,再次执行,依然出现2中的情况。

运行环境 eclipse ADT      android SDK 4.3    虚拟机android 4.3    

第一次日志:

第二次之后运行日志:

请求大家帮助

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.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends Activity {
	private EditText et_path;
	private ProgressBar pg;
	public static int runningThread = 3;
	public static int threadCount = 3;
	private Handler handler = new Handler();
	
	public int currentProcess = 0;  //当前进度条的进度

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		et_path = (EditText) findViewById(R.id.et_path);
		pg = (ProgressBar) findViewById(R.id.pg);
	}

	public void download(View v) {
		final String path = et_path.getText().toString().trim();

		if (TextUtils.isEmpty(path)) {
			Toast.makeText(this, "路径不能为空", Toast.LENGTH_SHORT).show();
			return;
		}
		
		

		new Thread() {
			public void run() {
				// 1.连接服务器获取一个文件,获取文件的长度,在本地创建一个大小跟服务器文件一样大的临时文件
				try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setRequestMethod("GET");
					conn.setConnectTimeout(5000);
					int code = conn.getResponseCode();
					if (code == 200) {
						int length = conn.getContentLength();
						pg.setMax(length); //设置进度条最大值
						System.out.println("文件总长度:" + length);
						// 在客户端本地创建一个大小跟服务器端文件一样大小的临时文件
						RandomAccessFile raf = new RandomAccessFile("/sdcard/qq.exe",
								"rwd");
						// 设置临时文件的长度
						raf.setLength(length);
						raf.close();

						// 假设3个线程去下载资源
						// 平均每一个线程下载的文件大小
						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 - 1;
							}
							System.out.println("线程" + threadId + ":----" + startIndex
									+ "---->" + endIndex);
							new Thread(new DownloadThread(path, threadId, startIndex, endIndex)).start();
						}

					} else {
						runOnUiThread(new Runnable() {
							@Override
							public void run() {
								Toast.makeText(MainActivity.this, "服务器错误,下载失败", Toast.LENGTH_SHORT).show();
							}
						});
					}
				} catch (Exception e) {
					e.printStackTrace();
					runOnUiThread(new Runnable() {
						@Override
						public void run() {
							Toast.makeText(MainActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
						}
					});
				}
			};
		}.start();

	}

	public class DownloadThread implements Runnable {
		private int threadId;
		private int startIndex;
		private int endIndex;
		private String path;

		/**
		 * @param path
		 *           下载文件的路径(URL)
		 * @param threadId
		 *           线程ID
		 * @param startIndex
		 *           线程下载的开始位置
		 * @param endIndex
		 *           线程现在的结束位置
		 */
		public DownloadThread(String path, int threadId, int startIndex,
				int endIndex) {
			super();
			this.path = path;
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
		}

		@Override
		public void run() {
			try {
				File tempFile = new File("/sdcard/" + threadId + ".txt");
				if (tempFile.exists() && tempFile.length() > 0) {
					FileInputStream fis = new FileInputStream(tempFile);
					byte[] tmp = new byte[1024];
					int leng = fis.read(tmp);
					int downloadintlen = Integer.parseInt(new String(tmp, 0, leng));
					int alreadylen = downloadintlen - startIndex;
					currentProcess += alreadylen;
					startIndex = downloadintlen;
					fis.close();
				}

				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(5000);
				conn.setRequestMethod("GET");
				// 请求服务器下载部分文件 指定文件的起止位置
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
						+ endIndex);
				System.out.println("真实线程" + threadId + ":----" + startIndex
						+ "---->" + endIndex);
				int code = conn.getResponseCode(); // 冲服务器请求全部资源200 ok 从服务器请求部分资源206
																// ok
				System.out.println("code:" + code);

				InputStream is = conn.getInputStream();
				RandomAccessFile raf = new RandomAccessFile("/sdcard/qq.exe", "rwd");
				// 随机写文件的时候从哪个位置开始写
				raf.seek(startIndex); // 定位文件

				int len = 0;
				byte[] buffer = new byte[4096];
				int total = 0; // 已下载数据的长度

				while ((len = is.read(buffer)) != -1) {
					RandomAccessFile info = new RandomAccessFile("/sdcard/"
							+ threadId + ".txt", "rwd"); // 记录当前线程已下载数据总长度
					raf.write(buffer, 0, len);
					total += len;
					// System.out.println("线程" + threadId + "newStartIndex:" + (total
					// + startIndex));
					info.write((total + startIndex + "").getBytes());
					info.close();
					
					synchronized (MainActivity.this) {
						currentProcess += len; //获取当前总进度
						pg.setProgress(currentProcess); //更改界面上进度条进度
						//特殊情况 progressbar   progressdialog 可以直接在子线程里面更新ui 内部代码已处理handler
					}
					
				}
				is.close();
				raf.close();
				System.out.println("线程" + threadId + "下载完毕");

			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				//当文件下载完毕后清除下载记录
				threadFilish(MainActivity.DownloadThread.this);
			}
		}

		private synchronized void threadFilish(Runnable r) {
			runningThread--;
			if (runningThread == 0) {
				for (int i = 1; i <= threadCount; i++) { // 所有的线程都执行完毕了
					File file = new File("/sdcard/" + i + ".txt");
					file.delete();
				}
				System.out.println("文件下载完毕删除所有现在记录");
				runOnUiThread(new Runnable() {
					@Override
					public void run() {
						Toast.makeText(MainActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
					}
				});
				handler.removeCallbacks(r);
			}
		}
		
	}

}
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/et_path"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="http://192.168.0.101/qq.exe" >

        <requestFocus />
    </EditText>

    <ProgressBar
        android:id="@+id/pg"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="download"
        android:text="download" />

</LinearLayout>



举报
binzo
发帖于5年前 0回/632阅
顶部