Android多线程下实例


  • Android多线程下实例
  • 将要下载的图片拷贝到服务器的WebContent目录之下
  • 新建一个downLoadFilejava类
  • 新建一个downxml文件完成界面布局
  • 新建DownLoadActivityjava作为启动的Activity
  • 最终的效果
  • 注意事项


将要下载的图片拷贝到服务器的WebContent目录之下。

android 10条线程并发 android多线程并发实例_线程池

新建一个downLoadFile.java类

在downLoadFile中进行网络请求、创建线程池,分配线程下载任务,开启线程下载图片到SD卡,返回下载进程判断变量message.what,判断是否下载完成。

package com.example.tonydandelion.downloadfile;

import android.os.Environment;
import android.os.Handler;
import android.os.Message;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * Created by TonyDandelion on 2015/11/15.
 */
public class DownLoad {

     private Handler handler;
     //记得将handler传入到Runnable中,因为是在Runnable中更新UI。
     public DownLoad(Handler handler){
         this.handler=handler;
     }


     //建立线程池,一共三个。
     private Executor threadPool= Executors.newFixedThreadPool(3);
     //给线程池创建Runnable对象,Runnable可以理解为一个任务。
     //这个任务只是一个接口。具体的任务执行是在 run()方法执行。
     static class DownLoadRunnable implements Runnable{
         private  Handler handler;
         private  String url;
         private  String fileName;
         private  long start;
         private  long end;

         public DownLoadRunnable(String url,String fileName,long start,long end,Handler handler){
             this.url=url;
             this.fileName=fileName;
             this.start=start;
             this.end=end;
             this.handler=handler;
         }


         @Override
         public void run() {
             //网络访问请求的代码
             URL httpUrl = null;
             try {
                 httpUrl = new URL(url);
                 HttpURLConnection conn=(HttpURLConnection)httpUrl.openConnection();
                 conn.setRequestMethod("GET");
                 conn.setReadTimeout(5000);
                 //指定Runnable发送的数据的长度。
                 conn.setRequestProperty("Range","bytes="+start+"-"+end);
                 //通过RandomAccessFile往本地文件里面写,方式是可读可写"rwd"
                 RandomAccessFile access = new RandomAccessFile(new File(fileName),"rwd");
                 //从start处开始读写
                 access.seek(start);
                 //拿到读入流
                 InputStream in = conn.getInputStream();
                 //创建一个四字节缓冲区
                 byte[] b=new byte[1024*4];
                 int len=0;
                 //开始读取数据,先往缓冲区里面读数据,只要不为-1,就一直读下去。从0开始读到len的长度。
                 while((len=in.read(b))!=-1){
                     access.write(b,0,len);
                 }
                 //读取完之后,关掉这个流。
                 if(access!=null){
                     access.close();
                 }
                 //读完了就关掉读入流 in
                 if(in!=null){
                     in.close();
                 }
                 //所有文件下载之后想主线程发送一个消息
                 Message message = new Message();
                 // message.what设置消息的int值,你可以自己定义。handler里用来区分是哪个消息。
                 message.what=1;
                 handler.sendMessage(message);

             } catch (MalformedURLException e) {
                 e.printStackTrace();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }

     public void downLoadFile(String url){
         //网络访问请求的代码
         URL httpUrl = null;
         try {
             httpUrl = new URL(url);
             HttpURLConnection conn=(HttpURLConnection)httpUrl.openConnection();
             conn.setRequestMethod("GET");
             conn.setReadTimeout(5000);
             //拿到下载图片的整体长度
             int count = conn.getContentLength();
             //通过三个线程去下载,所以每个线程的长度是整个图片长度的1/3
             int block = count/3;
             //指定下载的文件的名字,利用getFileName方法,直接从服务器中获取。
             String fileName=getFileName(url);
             //指定下载的文件的位置,在SD卡中创建这样一个名为fileName的文件。
             File parenr= Environment.getExternalStorageDirectory();
             File fileDownLoad = new File(parenr,fileName);

             //往线程池提交下载任务,开始下载。
             /**假设一个文件有11个字节,11/3=3....2
              * 第一个线程下载0-2字节
              * 第二个线程下载3-5字节
              * 第三个线程下载6-10字节
              * 最后的两个字节溢出来了当i=2时,说明到了最后一个线程。
              * 这时设置 end=count,就能多存溢出的字节。
              * */
             //开启三个线程
              for(int i=0;i<3;i++){
                  //算出每个线程起始位置和终止位置取数据的区间
                  long start=i*block;
                  long end=i*block;
                  if(i==2){
                      end=count;
                  }
              //创建Runnable对象
              DownLoadRunnable runnable = new DownLoadRunnable(url,fileDownLoad.getAbsolutePath(),start,end,handler);
              //通过线程池来提交任务,也就是提交Runnable对象。
              threadPool.execute(runnable);
              }

         } catch (MalformedURLException e) {
             e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }

    /**拿到文件的名字,因为文件的名字在
     *url(http://localhost:8080/web/Sky.jpg)最后一个反斜杠的后面
     * 所以调用url.substring截取字符串,其中截取的位置是url.lastIndexOf("/")+1
     *lastIndexOf("/") 方法可返回指定的字符串("/")值最后出现的位置,
     * 再加1,就是把Sky.jpg截取了
     * */
    public String getFileName(String url){
        return url.substring(url.lastIndexOf("/")+1);
    }
}

android 10条线程并发 android多线程并发实例_线程池_02

新建一个down.xml文件完成界面布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">


    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="下载图片"
        android:textSize="30sp"
        android:id="@+id/downloadbutton"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="36sp"
        android:id="@+id/textView" />


</LinearLayout>

新建DownLoadActivity.java作为启动的Activity

package com.example.tonydandelion.downloadfile;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.os.Handler;

/**
 * Created by TonyDandelion on 2015/11/16.
 */
public class DownLoadActivity extends Activity {

    private Button button;
    private TextView textView;
    private int count = 0;

    private Handler handler=new Handler(){
        public void handleMessage(android.os.Message msg){
            int result=msg.what;
            count+=result;
            //当count等于3的时候,说明下载完成了,打印下载完成到TextView上。
            if(count==3){
                textView.setText("下载成功!");
            }
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.down);
        button= (Button) findViewById(R.id.downloadbutton);
        textView= (TextView) findViewById(R.id.textView);


        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //开新线程来运行DownLoad。Android4.4以上的系统就不允许在主线程里面直接进行网络操作了。
                new Thread(){
                    @Override
                    public void run() {
                        DownLoad load = new DownLoad(handler);
                        load.downLoadFile("http://192.168.1.103:8080/web/Sky.jpg");
                    }
                }.start();
            }
        });
    }
}

最终的效果

点击下载按钮,完成下载。

android 10条线程并发 android多线程并发实例_java_03


在文件管理器里面就有Sky.java这个文件了

android 10条线程并发 android多线程并发实例_android 10条线程并发_04

注意事项

1、Handler的包,要导import android.os.Handler;这个,不能导import java.util.logging.Handler;这个。

2、因为Android4.4以上的系统就不允许在主线程里面直接访问网络,所以我们要自己新开一个线程来运行DownLoad.java,记得调用这个新开线程的start方法。

android 10条线程并发 android多线程并发实例_android_05