先說聲 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; } }
今天的代碼 有些多撒 正常下載是沒有問題的 這篇的代碼 存在一個問題 那就是會跳行,嘿嘿 留給大家這個問題了,
明天說說怎麼處理撒。