編輯:關於Android編程
1、在客戶端創建出來一個文件,該文件大小與服務器上的文件大小完全性相同。
①、首先要知道服務器上文件的大小,通過相應頭裡 的content-length得到文件大小。
②、使用RandomAccessFile類隨機創建一個文件 ,通過setLength方法設置文件大小。
2、開辟三個線程,進行下載,計算出每一個線程下載的數據塊大小。
3、當三個線程都運行完畢後,所有的數據都已經下載好了。
public classTestMutileDownload {
//服務器上要下載的資源的地址
public static final String path="http://192.168.1.247:8080/youdao.exe";
public static int threadcount;
public static void main(String[] args) throws Exception{
URL url = new URL(path);
HttpURLConnection conn =(HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
//設置請求頭,User-Agent:表示資源來自哪裡
conn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
conn.setConnectTimeout(5000);//得到服務器響應狀態碼的時間
int len =conn.getContentLength();
System.out.println("文件大小為"+len);
// 在本地創建出來一個大小跟服務器文件一樣大的資源
File file = newFile("youdao.exe");
//創建下載的文件對象
RandomAccessFilerandomfile = new RandomAccessFile(file,"rwd");
randomfile.setLength(len);
int blocksize = len/3;
for(int i =1;i<=3;i++){
threadcount = 0;
int startsize = (i-1)*blocksize;
int endsize = (i)*blocksize - 1;
if(i==3){
// if(endsize<=len)
endsize = len;
}
new Thread(new DownLoadTask(i, startsize, endsize)).start();
// 怎麼才能知道3個子線程都執行完畢了呢?
}
}
}
class DownLoadTaskimplements Runnable{
//線程的id
private int id;
//要下載的文件的開始位置
private int startsize;
// 要下載的文件的結束位置
private int endsize;
//HttpURLConnection.setRequestProperty("Range","bytes=2097152-4194303");
public DownLoadTask(int id, int startsize, int endsize) {
this.id = id;
this.startsize =startsize;
this.endsize = endsize;
}
@Override
public void run() {
try {
// 每一個線程創建執行的時候 都創建一個id.txt的文件,這個文件用來記錄當前線程下載的進度
File idfile = new File(id+".txt");
// 判斷是否記錄的有下載的位置信息
if(idfile.exists()){
FileInputStream fis =new FileInputStream(idfile);
byte[] result =StreamTools.getBytes(fis);
String numberstr = newString(result);
if(numberstr!=null&&(!"".equals(numberstr))){
int startposition = Integer.parseInt( numberstr);
if(startposition>startsize){
startsize =startposition; // 重新指定下載的開始位置
}
}
}
URL url = new URL(TestMutileDownload.path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent", "Mozilla/4.0(compatible; MSIE 6.0; Windows NT 5.1; SV1)");
conn.setConnectTimeout(5000); //得到服務器響應狀態碼的時間
// 指定當前線程從服務器上的哪個位置下載文件y
if(startsize>endsize){
startsize=endsize-1;
}
conn.setRequestProperty("Range","bytes="+startsize+"-"+endsize);
System.out.println("線程id="+id+"開始位置"+startsize+"結束位置"+endsize);
InputStream is = conn.getInputStream();
File file = new File("youdao.exe");
RandomAccessFile randomfile = new RandomAccessFile(file, "rwd");
randomfile.seek(startsize);
//randomfile.write(arg0, arg1, arg2);
byte[] buffer = new byte[1024];
int len = 0;
int total = 0;
while( (len = is.read(buffer))!=-1){
randomfile.write(buffer,0, len);
// 記錄當前 線程下載的數據量 和對應的位置給記錄
total +=len;
FileOutputStream idfos =new FileOutputStream(idfile);
idfos.write((startsize+total+"").getBytes());// 記錄當前線程下載的位置信息
idfos.flush();
idfos.close();
}
randomfile.close();
is.close();
System.out.println("線程"+id+"下載完畢");
// //線程下載完畢後 擦屁股的操作
// if(idfile.exists()){
// idfile.delete();
// }
synchronized (TestMutileDownload.class) {
TestMutileDownload.threadcount++;
if(TestMutileDownload.threadcount>=3){
System.out.println("所有的線程都執行完畢了");
// 擦屁股的操作
for(int i=1;i<=3;i++){
File deletefile = newFile(i+".txt");
System.out.println(i+"刪除"+ deletefile.delete());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
1、設置布局:
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="多線程斷點下載器" />
android:id="@+id/et_path"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="http://192.168.1.247:8080/youdao.exe"
android:hint="請輸入下載文件的路徑" />
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal" //水平居中
android:orientation="horizontal" >
android:id="@+id/bt_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下載" />
android:id="@+id/bt_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暫停" />
android:id="@+id/pb"
style="?android:attr/progressBarStyleHorizontal"//進度條的樣式.
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
android:id="@+id/tv_progress"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="進度" />
2、業務代碼:
public class DemoActivityextends Activity implements OnClickListener {
protected static final int ERROR = 404;
public static final int DOWNLOAD_FINISH = 200;
private EditText et_path;
private Button bt_download;
private Button bt_stop;
private ProgressBar pb;
private TextView tv_progress;
public static int threadcount ;
public int total; // 當前下載的進度
public int totallen ; // 總的文件大小
private Handler handler = new Handler(){
@Override
public voidhandleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.what==ERROR){
Toast.makeText(getApplicationContext(),"獲取文件長度失敗", 0).show();
bt_download.setClickable(true);
bt_download.setEnabled(true);
return;
}
if(msg.what==DOWNLOAD_FINISH){
bt_download.setClickable(true);
bt_download.setEnabled(true);
return;
}
int process = total*100/totallen;
String strprocess = "當前進度"+process+"%";
tv_progress.setText(strprocess);
}
};
public boolean flag;
@Override
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
et_path = (EditText)this.findViewById(R.id.et_path);
bt_download = (Button)this.findViewById(R.id.bt_download);
bt_stop = (Button)this.findViewById(R.id.bt_stop);
pb = (ProgressBar)this.findViewById(R.id.pb);
tv_progress = (TextView)this.findViewById(R.id.tv_progress);
//注冊按鈕的點擊事件
bt_download.setOnClickListener(this);
bt_stop.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_stop:
flag = false;
bt_download.setClickable(true);
bt_download.setEnabled(true);
break;
case R.id.bt_download:
final String path = et_path.getText().toString().trim();
if("".equals(path)){
Toast.makeText(this,"路徑不能為空", 1).show();
return ;
}else{
// 開啟子線程 連接服務器 獲取文件的大小
bt_download.setClickable(false);
bt_download.setEnabled(false);
new Thread(){
public void run() {
try {
total = 0;
flag = true;
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent", "Mozilla/4.0(compatible; MSIE 6.0; Windows NT 5.1; SV1)");
conn.setConnectTimeout(5000); //得到服務器響應狀態碼的時間
// 獲取服務器文件的大小
totallen = conn.getContentLength();
//設置進度條的最大值
pb.setMax(totallen);
System.out.println("文件大小為"+totallen);
// 在本地創建出來一個大小跟服務器文件一樣大的資源
File file = newFile(Environment.getExternalStorageDirectory(),getFileName(path));
RandomAccessFile randomfile = new RandomAccessFile(file, "rwd");
randomfile.setLength(totallen);
// 假設只開啟3個子線程
int blocksize = totallen/3;
for(int i = 1;i<=3;i++){
threadcount = 0;
int startsize =(i-1)*blocksize;
int endsize =(i)*blocksize - 1;
if(i==3){
endsize = totallen;
}
new Thread(newDownLoadTask(i, startsize, endsize,path)).start();
// 怎麼才能知道3個子線程都執行完畢了呢?
}
} catch (Exception e) {
e.printStackTrace();
// Toast.makeText(this, "下載出錯", 0).show();
Message msg = new Message();
msg.what = ERROR;
handler.sendMessage(msg);
}
};
}.start();
}
break;
}
}
class DownLoadTask implements Runnable{
//線程的id
private int id;
//要下載的文件的開始位置
private int startsize;
// 要下載的文件的結束位置
private int endsize;
//HttpURLConnection.setRequestProperty("Range","bytes=2097152-4194303");
private String path;
public DownLoadTask(intid, int startsize, int endsize,String path) {
this.id = id;
this.startsize = startsize;
this.endsize = endsize;
this.path = path;
}
@Override
public void run() {
try {
// 每一個線程創建執行的時候 都創建一個id.txt的文件,這個文件用來記錄當前線程下載的進度
File idfile = newFile("/mnt/sdcard/"+id+".txt");
// 判斷是否記錄的有下載的位置信息
if(idfile.exists()){
FileInputStream fis = new FileInputStream(idfile);
byte[] result = StreamTools.getBytes(fis);
String numberstr = new String(result);
if(numberstr!=null&&(!"".equals(numberstr))){
int startposition =Integer.parseInt( numberstr); // 從文件裡面獲取到的位置信息
if(startposition>startsize){
int currentposition = startposition - startsize; // 當前線程已經下載的數據的大小
setProgreebarProgress(currentposition);
handler.sendEmptyMessage(0);
// handler.post(r);
startsize = startposition; // 重新指定下載的開始位置
}
}
}
URL url = new URL(path);
HttpURLConnection conn =(HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
conn.setConnectTimeout(5000);//得到服務器響應狀態碼的時間
// 指定當前線程從服務器上的哪個位置下載文件y
if(startsize>endsize){
startsize=endsize-1;
}
conn.setRequestProperty("Range","bytes="+startsize+"-"+endsize);
System.out.println("線程id="+id+"開始位置"+startsize+"結束位置"+endsize);
InputStream is =conn.getInputStream();
File file = newFile(Environment.getExternalStorageDirectory(),getFileName(path));
RandomAccessFilerandomfile = new RandomAccessFile(file,"rwd");
randomfile.seek(startsize);
//randomfile.write(arg0,arg1, arg2);
byte[] buffer = newbyte[1024];
int len = 0;
int total = 0;
while( (len =is.read(buffer))!=-1){
randomfile.write(buffer, 0, len);
// 記錄當前 線程下載的數據量 和對應的位置給記錄
total +=len;
setProgreebarProgress(len);
handler.sendEmptyMessage(0);
FileOutputStream idfos = new FileOutputStream(idfile);
idfos.write((startsize+total+"").getBytes()); // 記錄當前線程下載的位置信息
idfos.flush();
idfos.close();
if(!flag){
return ;
}
}
randomfile.close();
is.close();
System.out.println("線程"+id+"下載完畢");
// //線程下載完畢後 擦屁股的操作
// if(idfile.exists()){
// idfile.delete();
// }
synchronized (DemoActivity.this){
threadcount ++;
if(threadcount>=3){
System.out.println("所有的線程都執行完畢了");
// 擦屁股的操作
for(inti=1;i<=3;i++){
File deletefile = newFile("/mnt/sdcard/"+i+".txt");
System.out.println(i+"刪除"+ deletefile.delete());
}
//通知主線程 bt_download.setClickable(true);
//bt_download.setEnabled(true);
Message msg = newMessage();
msg.what =DOWNLOAD_FINISH;
handler.sendMessage(msg);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private synchronized void setProgreebarProgress(int len){
total += len;
pb.setProgress(total);
// 第二種做法 就是每次得到下載的進度後 把數據存到文件裡面
}
public String getFileName(String path){
int start =path.lastIndexOf("/")+1;
returnpath.substring(start);
}
}
只有創建View對象的線程,才可以更新view對象裡的內容,
其實所有的view對象都是在主線程裡面創建的 ,線程的名字叫main。
所用的與ui相關的界面都是在主線程裡面創建的。
更新view顯示基本原理:
當子線程要更新view裡的內容時,就讓子線程發送一個消息給主線程,主線程再根據消息的內容進行操作。
主線程裡面有消息隊列(message queue),可以存放一組消息。並且還有一個輪詢器,定期的輪詢消息隊列,查看是否有消息。如果發現有消息,;輪詢器會把消息取出來。
在主線程中創建消息的處理者handler對象,用於處理在消息隊列中取出的消息。
字體管家是手機安卓手機上面的一個更改手機字體的軟體,應該算是手機美化類別的。字體管家在手機在線字體的收集方面還算是比較全面的,雖不能算是百變字體,但分類足以
前言開發做得久了,總免不了會遇到各種坑。而在Android開發的路上,『軟鍵盤擋住了輸入框』這個坑,可謂是一個曠日持久的巨坑——來來來,我們慢慢看
Context:我自己寫下Google關於Android性能優化的視頻課程的翻譯,希望轉載者不要刪除我的博客地址http://blog.csdn.net/zhjali12
什麼是Android UDP?UDP是User Datagram Protocol的簡稱,中文名是用戶數據包協議,是OSI參考模型中一種無連接的傳輸層協議,提供面向事務的