文件下载
文件下载:
实现文件下载管理,实现单线程断点续传,界面显示多个下载记录,
但只能点击单独一个可以继续下载,如果点击多个出现相应提示,在下载
列表里将所有Sdcard下的PDF文件全部显示出来,点击调用PDF浏览器,
如果没有浏览器提示无法显示。
完成已经下载完成的文件查看,删除:
MVC
V层Adapter实现
C层Activity实现
V和C层实现 订购/通知
M层使用单例,工厂,模板
C层中将需求提出:
1, 查询目录下的文件返回List
2, 删除指定文件(参数文件名)
3, 查看指定文件(参数文件名,context上下文)
由DownloadedInterface接口声明以上的3个方法,
由于1,2需求是不会改变的,但是在3中如果文件是PDF,DOC,TXT那么在打开的时候具体的逻辑是不同的。
那么就可以用模板方式将前2个需求实现,将第三个需求定义成抽象,子类继承模板类单独实现抽象的3需求,好处是如果需求更改,需要加入其他文件类型的时候只需要继承模板类实现需求3就可以了,因为需求1,2是不变的。
如果需求更改,需要在Activity中添加多个DownloadedInterface的获取指定文件的类,或者添加多个判断:
判断是pdf,判断是doc,判断是txt。
这样C层中的代码复用可能性也不大,有没有什么好的方式去解耦呢?
可以使用工厂模式,
DownloadedObjectFactory类(单例),私有构造中声明List里面加上map,key是文件类型(其实就相当于文件夹的路径),value是Obj的(需要将符合Key的类装入到list中进行缓存,这样的好处是在初始化的时候耗时,但是以后就不需要再创建,并且是全局的随时可以使用)。在构造中添加所有的文件类比如doc,txt,pdf等等,DownloadedObjectFactory定义成单例,在下面有getDownloadObjForName方法(参数是文件名/文件夹名)返回DownloadedInterface这样在使用的时候只需要将文件名或文件夹名传入,返回的自然就是你需要的类了,如果需要扩展只需要,继承模板类实现需求3,并在list中加入key和value,在使用的时候直接
DownloadedInterface downloadedInterface =DownloadedObjectFactory.getInstance().getDownloadObjForName(文件名/文件夹名);就可以了
其实简单看好像没有什么必要实现工厂,但是这样可以实现解耦,并且C层是不需要知道用户需要的格式是什么格式,这样也保证了复用性。
以上是M层。
下面是C和V层之间的订购/通知实现,
interface DownloadedDelegat声明方法DownloadedDelegate(文件名,点击类型)
在V层定义DownloadedDelegat,并实现set方法,在长按(暂定删除)调用DownloadedDelegate(文件名,长按类型),在点击查看时调用方法传入文件名和点击类型。
在c层Activity中实现DownloadedDelegat接口中的方法,adapter调用set代理,就可以实现订购/通知,而在实现的接口方法中可以判断点击的类型,并调用相应的删除/查看方法通知到M层去实现,C层必须知道V层传入的事件类型,但是没有必要知道具体操作的是什么文件,所以只要调用删除和查看,但是具体删除什么文件,查看什么文件C层是不需要知道的,这是需要M层做的事情。
不需要担心文件的类型出错只要传入的没有错,调用的就没有错,当创建的时候就是传入文件的类型,所以返回的接口肯定也是这个类型的。并且使用了单例和缓存中的list不会出现问题。
整个工程结构:
把源码传上来以备以后查阅(按包名类名):
package com.hsm.Activity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends Activity { private Button b1; private Button b2; private Button b3; private Intent intent; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); this.setContentView(R.layout.first); b1 = (Button)findViewById(R.id.button1); b2 = (Button)findViewById(R.id.button2); b3 = (Button)findViewById(R.id.button3); intent = new Intent(); b1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub intent.setClass(MainActivity.this,ResumeBrokenDownloadsActivity.class); intent.putExtra("url", "http://192.168.10.113:8080/a.pdf"); startActivity(intent); } }); b2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub intent.setClass(MainActivity.this,ResumeBrokenDownloadsActivity.class); intent.putExtra("url", "http://192.168.10.113:8080/b.pdf"); startActivity(intent); } }); b3.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub intent.setClass(MainActivity.this,ResumeBrokenDownloadsActivity.class); intent.putExtra("url", "http://192.168.10.113:8080/c.pdf"); startActivity(intent); } }); } }
上面的是进入的首界面activity
下面是进入后显示已经下载完成的list的activity
package com.hsm.Activity; import java.util.List; import com.hsm.downloadedfile.DownloadedPDF; import com.hsm.factory.DownloadedObjectFactory; import com.hsm.modelinterface.DownloadedDelegat; import com.hsm.modelinterface.DownloadedInterface; import com.hsm.view.DownloadedAdapter; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.widget.ListView; public class ResumeBrokenDownloadsActivity extends Activity implements DownloadedDelegat{ /** Called when the activity is first created. */ private List<String> list ; private ListView downloadedListView; private DownloadedAdapter downloadedAdapter; private DownloadedInterface downloadedInterface; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //显示已经下载完成的文件 downloadedInterface = DownloadedObjectFactory.getInstance().getDownloadObjForName("pdf"); list = downloadedInterface.queryDownloadedFiles(); downloadedAdapter = new DownloadedAdapter(this, list); downloadedAdapter.setDelegate(this); downloadedListView = (ListView)findViewById(R.id.downloaded_list); downloadedListView.setAdapter(downloadedAdapter); //显示正在下载的文件 Intent intent = getIntent(); String nameString = intent.getStringExtra("url"); //TODO 如果nameString是空就表示从其他入口进来不是从下载入口进来 } @Override public void DownloadedDelegate(String name, int event) { if (event==1)//删除 { downloadedInterface.removeFileForName(name); Message msg = new Message(); msg.obj = "flush"; flushHandler.sendMessage(msg); }else if(event==2){//查看 downloadedInterface.openDownloadedFile(name,this); } } //刷新已下载完成的Adapter private Handler flushHandler = new Handler() { public void handleMessage(Message msg) { if ("flush".equals(msg.obj)) { downloadedAdapter.notifyDataSetChanged(); } } }; }
下面是具体实现查询下载完成Fild逻辑的类:
package com.hsm.downloadedfile; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.widget.Toast; import com.hsm.modelinterface.DownloadedInterface; public abstract class DownloadedFild implements DownloadedInterface { protected List<String> pdfList; protected File sdDir; protected String sdPath = Environment.getExternalStorageDirectory().toString();// 获取跟目录 public DownloadedFild(String folderPath) { String status = Environment.getExternalStorageState(); if (status.equals(Environment.MEDIA_MOUNTED)) { pdfList = new ArrayList<String>(); sdDir = new File(sdPath+"/"+folderPath); File[] allFile = sdDir.listFiles(); for (int i = 0; i < allFile.length; i++) { pdfList.add(allFile[i].getName()); } }else { //TODO 否则表示无sdcard } } @Override public List<String> queryDownloadedFiles() { return pdfList; } @Override public void removeFileForName(String fileName) { pdfList.remove(fileName); File file = new File(sdDir+"/"+fileName); if (!file.exists()) { return; } // 如果file的路径是文件夹 // if (!file.isDirectory()) // { // return; // } file.delete(); } @Override public abstract void openDownloadedFile(String fileName , Context context); }
下面的是实现删除具体文件的类继承了上面的查询类DownloadedFild只实现了public abstract void openDownloadedFile(String fileName , Context context);
package com.hsm.downloadedfile; import java.io.File; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.widget.Toast; public class DownloadedPDF extends DownloadedFild { public DownloadedPDF(String folderPath) { super(folderPath); } @Override public void openDownloadedFile(String fileName, Context context) { Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri localUri = Uri.fromFile(new File(sdDir+"/"+fileName)); intent.setDataAndType(localUri, "application/pdf"); try { context.startActivity(intent); } catch (Exception e) { // TODO Auto-generated catch block Toast.makeText(context, "无可用程序打开此文件!", 0).show(); } } }