android 多線程同時下載多個較大文件

先說聲 sorry 不好意思 拖了 兩三天了。。。。


ok 正文:

額 開始做程序前 先把要測試的服務器和文件準備好撒~


1、配置AndroidManifest.xml,既然是要向本地sdcard 寫內容,訪問URL 權限是必須滴

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>

2、設置layout了,

 1)在activity_main.xml中加入一個listView,加入listView的要注意啊


android:layout_height="match_parent"這個參數一定得是match_parent的


 2)新建一個單行佈局

   弄個這樣的就好了

注意 沒開始下載時 那個進度條 應該隱藏的

在progressBar中加這樣一句話就好了

android:visibility="invisible"


隱藏後效果:


3、寫代碼:

package com.example.bolg_download_file;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.ClipData.Item;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener
{
    private ListView mListView;
    private DownLoadAdapter mAdapter;
    private Map<Integer, DownLoadThread> mItemLoadThreads;// 用於存放已啓動的進度條 ,
                                                          // 在點擊啓動線程的時候設置值
    private Map<Integer, DownLoadHandler> mItemLoadHandlers;
    private Map<Integer, BarInfo> mItemProgressInfo;// 用於存放所有進度條的信息,在創建bar的時候就要設置值了
    class ViewHolder
    {
        ImageView mImageView;
        TextView mTitle;
        TextView mSubtitle;
        Button mButton;
        ProgressBar mBar;
    }
    class BarInfo
    { // 用來分裝 Bar(進度條)的信息
        boolean isDownLoad;// 是否已經下載,這個參數
                           // 我暫時沒有使用,但是想要將下載系統做的更完善,應該是需要它的,大家可以完善下~嘿嘿
        boolean visible;// bar是否顯示
        int currentProgress;// 進度條當前的值
        int maxProgress;// 進度條的最大值
    }
    class DownLoadHandler extends Handler
    {
        private ProgressBar bar;
        public void setBar(ProgressBar bar)
        {
            this.bar = bar;
        }
        @Override
        public void handleMessage(Message msg)
        {
            BarInfo bi = (BarInfo) msg.obj;
            bar.setVisibility(View.VISIBLE);
            bar.setMax(bi.maxProgress);
            bar.setProgress(bi.currentProgress);
        }
    }
    class DownLoadAdapter extends BaseAdapter
    {
        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            /*
             * 前面做 ListView優化時 有說過現在再說一下撒 主要參數: position:代表ListView的當前行號,
             * convertView:代表ListView的緩存layout
             */
            View layout = null;
            ViewHolder holder = null;
            if (convertView == null)
            {
                layout = getLayoutInflater().inflate(R.layout.list_item, null);
                holder = new ViewHolder();
                holder.mBar = (ProgressBar) layout
                        .findViewById(R.id.progressBar1);
                holder.mImageView = (ImageView) layout
                        .findViewById(R.id.p_w_picpathView1);
                holder.mTitle = (TextView) layout.findViewById(R.id.textView1);
                holder.mSubtitle = (TextView) layout
                        .findViewById(R.id.textView2);
                holder.mButton = (Button) layout.findViewById(R.id.button1);
                holder.mButton.setTag(position);// 將當前行號 給button
                holder.mButton.setOnClickListener(MainActivity.this);// 設置點擊事件
                layout.setTag(holder);
            }
            else
            {
                layout = convertView;
                holder = (ViewHolder) layout.getTag();
            }
            // 設置控件內容
            DownLoadHandler dlh = null;
            if (!mItemLoadHandlers.containsKey(position))
            {// 給每一行分配一個handler
                dlh = new DownLoadHandler();
                mItemLoadHandlers.put(position, dlh);
                dlh.setBar(holder.mBar);
            }
            else
            {
                dlh = mItemLoadHandlers.get(position);
                dlh.setBar(holder.mBar);
            }
            if (!mItemProgressInfo.containsKey(position))
            {// 設置 BarInfo 如果當前行已經存在就不用設置了
                BarInfo value = new BarInfo();
                value.currentProgress = 0;
                value.isDownLoad = false;
                value.maxProgress = 0;
                value.visible = false;
                mItemProgressInfo.put(position, value);
            }
            holder.mTitle.setText("title:" + position);
            BarInfo bi = mItemProgressInfo.get(position);
            if (bi.visible)
            {
                holder.mBar.setVisibility(View.VISIBLE);
            }
            else
            {
                holder.mBar.setVisibility(View.INVISIBLE);
            }
            holder.mBar.setMax(bi.maxProgress);
            holder.mBar.setProgress(bi.currentProgress);
            return layout;
        }
        @Override
        public int getCount()
        {
            // 目前先把他寫死了,我服務器提供了 15個下載文件了
            return 9;
        }
        @Override
        public Object getItem(int position)
        {
            return null;
        }
        @Override
        public long getItemId(int position)
        {
            return 0;
        }
    }
    @Override
    public void onClick(View v)// 這裏的view 是觸發事件的空間
    {
        int position = (Integer) v.getTag();
        BarInfo bi = mItemProgressInfo.get(position);
        if (!mItemLoadThreads.containsKey(position))
        {// 判斷當前行是否已啓動了線程,如果沒啓動就啓動一個線程執行下載功能
            // 因爲前面 在做list_item的時候將progressbar的顯示調成隱藏的了,這裏得把他弄出來撒
            DownLoadThread dt = new DownLoadThread(position);
            dt.start();
            mItemLoadThreads.put(position, dt);
        }
        else
        // 如果已經啓動了就 通知用戶 該軟件正在下載
        {
            Toast.makeText(MainActivity.this, "該文件正在下載。。。請稍後撒~~~",
                    Toast.LENGTH_SHORT).show();
            // toast的最後一個參數代表Toast的顯示時間:
            // 主要有兩個值:LENGTH_SHOT表示 較短時間
            // LENGTH_LONG表示 較長時間
        }
    }
    private final static String NET_WORK_PATH = "http://10.0.2.2:8080/download/";// 前面有說過這裏爲什麼是10.0.2.2
    class DownLoadThread extends Thread
    {
        int position;
        public DownLoadThread(int position)
        {
            this.position = position;
        }
        @Override
        public void run()
        {
            InputStream is = null;
            OutputStream os = null;
            try
            {
                BarInfo bi = mItemProgressInfo.get(position);
                String fileName = "abc" + position + ".zip";
                File file = Environment.getExternalStorageDirectory();
                os = new FileOutputStream(file.getAbsoluteFile() + "/"
                        + fileName);
                URL u = new URL(NET_WORK_PATH + fileName);// 這裏寫這麼長只是構造文件名而已不用過多糾結撒
                URLConnection urlConn = u.openConnection();
                bi.maxProgress = urlConn.getContentLength();// 獲取文件大小;要注意這裏的文件大小單位是字節,所以文件過大的話
                                                            // 最好用long類型的了
                is = urlConn.getInputStream();
                byte[] buffer = new byte[1024];
                int len = 0;
                int sum = 0;
                bi.visible = true;
                while (-1 != (len = is.read(buffer)))
                {
                    sum += len;
                    Message msg = new Message();
                    bi.currentProgress = sum;
                    os.write(buffer);
                    msg.arg1 = position;
                    msg.obj = bi;
                    mItemLoadHandlers.get(position).sendMessage(msg);
                }
                os.flush();// 嘿嘿 下載完後 java 的io要flush一下輸出流的緩存的,上回我沒寫哦,不知道大家
                           // 有沒有發現這個錯誤撒 嘿嘿~
                // 下載完後 做一些 數據的更改撒
                bi.visible = false;
            }
            catch (MalformedURLException e)
            {
                e.printStackTrace();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initUi();
        initData();
    }
    private void initData()
    {
        mItemLoadThreads = new HashMap<Integer, MainActivity.DownLoadThread>();
        mItemProgressInfo = new HashMap<Integer, MainActivity.BarInfo>();
        mItemLoadHandlers = new HashMap<Integer, MainActivity.DownLoadHandler>();
    }
    private void initUi()
    {
        mListView = (ListView) findViewById(R.id.listView1);
        mAdapter = new DownLoadAdapter();
        mListView.setAdapter(mAdapter);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}


今天的代碼 有些多撒 正常下載是沒有問題的 這篇的代碼 存在一個問題 那就是會跳行,嘿嘿 留給大家這個問題了,

明天說說怎麼處理撒。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章