();// 首先定义静态的标志位:
public static int isDowning = 0;
//0 未下载, 1正在下载 ,2 暂停 ,3 下载完成
private Handler handler = new Handler() { @Override
public void handleMessage(Message msg) {
if (!Thread.currentThread().isInterrupted()) { switch (msg.what) { case 1:
int size = msg.getData().getInt(\"size\"); String fileloadpath = msg.getData().getString(\"stringbuilder\");
progressBar.setProgress(size); int result = (int) (((float) progressBar.getProgress() / (float) progressBar .getMax()) * 100);
resultView.setText(result + \"%\"); if (progressBar.getMax() == progressBar.getProgress()) {
setTitle(\"下载成功\");
showToastString(\"下载成功\"); isDowning = 3; fileService = new FileService(DownLoaderActivity.this);
InternetFile internetFile = new InternetFile();
internetFile.setName(FileDownloader.filename);
internetFile.setSavepath(fileloadpath); try {
fileService.save(internetFile);
} };
} catch (Exception e) { e.printStackTrace(); } }
break; case -1:
String error = msg.getData().getString(\"error\"); showToastString(error); break; } }
super.handleMessage(msg);
说明
String fileloadpath =
msg.getData().getString(\"stringbuilder\");
在主页面中得打下载的路径,
fileService = new FileService(DownLoaderActivity.this);
得到fileService对象,调用下载文件的业务方法。
InternetFile internetFile = new InternetFile();
下载文件的实体
internetFile.setName(FileDownloader.filename);
得到下载文件的名字,并给实体赋值
internetFile.setSavepath(fileloadpath);
得到下载文件的目录,并给实体赋值
fileService.save(internetFile);
调用数据库的save保存方法,将文件实体保存到数据库中。
@Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.downloader); Intent intent =this.getIntent(); final String path =
intent.getExtras().getString(\"url\").trim();
pathEditText = (EditText) this.findViewById(R.id.path); pathEditText.setText(path);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
resultView = (TextView) findViewById(R.id.result); /**
* 下载操作
*/
button_download = (Button)
findViewById(R.id.button_download);
button_download.setOnClickListener(new View.OnClickListener() { /**
* 0未下载, 1正在下载 ,2 暂停 ,3 下载完成 * 下载文件,并保存到SDCard */
@Override
public void onClick(View v) {
setTitle(\"正在下载中\"); if(isDowning ==1){
showToastString(\"正在下载中!\"); }
if(isDowning == 0 || isDowning ==2)
if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { try {
flags.put(path, true);
download(path, Environment
.getExternalStorageDirectory());// 1 isDowning = 1;
showToastString(\"开始下载!\"); } catch (Exception e) {
showToastString(\"网络连接失败!\"); Log.e(TAG, e.toString()); }
} else {
showToastString(\"SD卡出现错误!\"); } } });
说明
public static int isDowning = 0;
定义下载文件的状态,0未下载, 1正在下载 ,2 暂停 ,3 下载完成 if(isDowning ==1){
showToastString(\"正在下载中!\"); }
如果正在下载中Toast显示出“正在下载中!”; if(isDowning == 0 || isDowning ==2) 如果尚未下载或是下载暂停就开始下载工作 flags.put(path, true);
flags作为标志位,在下载时将其Value设定为true,在下载的
DownloadThread.java中进行判断当前falg的值,并将其作为下载的条件。
/**
* 暂停操作 */
button_pause = (Button) this.findViewById(R.id.button_pause); button_pause.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setTitle(\"暂停下载\"); try {
//0 未下载, 1正在下载 ,2 暂停 ,3 下载完成 switch (isDowning) { case 0:
showToastString(\"尚未开始下载!\"); break; case 1:
flags.put(path, false); isDowning = 2;
showToastString(\"暂停\"); break; case 2:
showToastString(\"已经暂停!\"); break; case 3:
showToastString(\"已经下载完了!\"); break; }
} catch (Exception e) {
showToastString(\"暂停失败!\"); }
} });
说明:
当点击【暂停】按钮时,触发其点击事件,用switch分别判断四种状态,并作出相应的业务处理。
flags.put(path, false);
传给标志位为false,用于暂停线程的下载,在后面会详细介绍。
/**
* 删除操作
*/
button_delete = (Button)
this.findViewById(R.id.button_delete);
button_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setTitle(\"删除下载文件\"); try {
if(isDowning==0){
Toast.makeText(DownLoaderActivity.this, \"还没有
1).show();
开始下载!\
}
//0 未下载, 1正在下载 ,2 暂停 ,3 下载完成
if(isDowning==1||isDowning ==2 ||isDowning == 3 ){ flags.put(path, false);
String filename = FileDownloader.filename; new FileService(DownLoaderActivity.this).delete(path); DelFile.delFile(filename); progressBar.setProgress(0); resultView.setText(0 + \"%\"); isDowning = 0;
showToastString(\"删除成功!\"); }
} catch (Exception e) {
showToastString(\"删除失败!\"); } } });
说明:
String filename = FileDownloader.filename;
得到文件的名字,在FileDownloader类中,filename为公共的静态变量。 new FileService(DownLoaderActivity.this).delete(path); 删除数据库中的下载记录。
DelFile.delFile(filename);
调用DelFile对象的delFile方法,删除下载在SD卡中的指定的文件。 progressBar.setProgress(0); resultView.setText(0 + \"%\");
设定progressBar和resultView中的值为0。
/**
* 跳转到已经下载列表
*/
button_already = (Button)
findViewById(R.id.button_alreadylist);
button_already.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { Intent intent =new
Intent(DownLoaderActivity.this,SaveFileActivity.class); startActivity(intent); } });
说明
Intent intent =new
Intent(DownLoaderActivity.this,SaveFileActivity.class);
新建一个显式意图,第一个参数为当前Activity类对象,第二个参数要打开的Activity类。SaveFileActivity将在后面重点介绍。 startActivity(intent);
发送该意图。
/**
* 返回到首页 */
button_back = (Button) this.findViewById(R.id.button_back); button_back.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { Intent intent = new
Intent(DownLoaderActivity.this,BrowserActivity.class); startActivity(intent); } });
} /**
* 运行在主线程(UI线程负责显示控件的显示更新[重绘界面]) * */
private void download(final String path, final File saveDir) throws
Exception{
new Thread(new Runnable() { @Override
public void run() { try {
if (downloader==null) { downloader = new
FileDownloader(DownLoaderActivity.this, path, saveDir, 3); }
downloader.init();
progressBar.setMax(downloader.getFileSize());
downloader.download(new DownloadProgressListener(){
@Override
public void onDownloadSize(int size) { Message msg = new Message(); msg.what = 1;
StringBuilder stringBuilder = new StringBuilder();
String string = String.valueOf(
stringBuilder.append(Environment.getExternalStorageDirectory())
.append(\"/\") string);
.append(FileDownloader.filename)); msg.getData().putString(\"stringbuilder\
msg.getData().putInt(\"size\ Log.i(TAG, \"\"+size);
handler.sendMessage(msg); } });
} catch (Exception e) {
Message msg = new Message(); msg.what = -1;
msg.getData().putString(\"error\下载失败\"); handler.sendMessage(msg); Log.e(TAG, e.toString()); } }
}).start(); }
说明:
if (downloader==null) {
downloader = new FileDownloader(DownLoaderActivity.this, path, saveDir, 3); }
判断当前是否已经创建了FileDownloader对象,如果为null,则创建,如果不为null,直接执行。
downloader.init();
调用downloader对象的初始化方法,目的:
1. 当再次点击下载的时候,要求只完成一次构造函数。 2. 初始化下载器时首先将下载文件大小设定为0,在再次在数据库中获取已经下载文
件的大小,玩完成下载器的构造。
StringBuilder stringBuilder = new StringBuilder(); String string = String.valueOf(
stringBuilder.append(Environment.getExternalStorageDirectory()
.append(\"/\")
.append(FileDownloader.filename)); msg.getData().putString(\"stringbuilder\
)
得到下载目录拼接成字符串,并将利用消息机制将内容传递给这页面的hander。实现下载文件数据库的信息保存。
FileDownloader.java中关键代码:
package com.sharpandroid_video.download.net.download;
/**
* 文件下载器 */
public class FileDownloader { private Context context;
public static String filename =\"\";
............................ ............................
// 构造下载器
public FileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum) { try {
this.context = context;
this.downloadUrl = downloadUrl;
fileService = new FileService(this.context); this.fileSaveDir = fileSaveDir; this.url = new URL(downloadUrl);
}
this.threads = new DownloadThread[threadNum]; }catch (Exception e) {
e.printStackTrace();
说明: 将原来的整体的构造下载器分为两部分:FileDownloader类的构造函数和
FileDownloader对象的初始化。
public void init(){ try{
downloadSize= 0;
if(!fileSaveDir.exists()) fileSaveDir.mkdirs(); HttpURLConnection conn = (HttpURLConnection) print(e.toString());
............................
throw new RuntimeException(\"连接不到下载路径not connect internet \"); } }
说明:
downloadSize= 0;
当再次点击下载按钮时会再次调用此方法,则设置已经下载的大小为0,在下面省略的代码中在前面已经做了很详细的介绍,会查询数据库得到已经下载文件的位置。
/**
* 获取文件名 */
public String getFileName(HttpURLConnection conn) {
............................
return filename;
}
//实现下载功能,并同时可以得到此时各个线程的下载数量
public int download(DownloadProgressListener listener) throws Exception{
............................ }
//0 未下载, 1正在下载 ,2 暂停 ,3 下载完成
if(listener!=null && DownLoaderActivity.isDowning == 1) listener.onDownloadSize(this.downloadSize);
说明: if(listener!=null && DownLoaderActivity.isDowning == 1)
listener.onDownloadSize(this.downloadSize);
判断如果listen不为null而且处于下载状态就实时更新页面的操作。如果
DownLoaderActivity.isDowning == 1的作用是:只有当正在下载的时候才会给给主页面发送已经下载文件大小的消息,如果不加上的后果是在机器内部会不停的给主页面发送消息,一直在消耗机器本身的物理内存。 ............................
............................
private static void print(String msg){ Log.i(TAG, msg); } }
DownloadThread.java中更新的代码:
package com.sharpandroid_video.download.net.download;
public class DownloadThread extends Thread {
.................................... print(\"线程 \" + this.threadId + \"从位置\"+ this.startPos+ \"开始下载 \");
Map flags = DownLoaderActivity.flags; Boolean flag = flags.get(this.downUrl.toString());while (flag && downLength < block && (offset = inStream.read(buffer, 0, max)) != -1) {
saveFile.write(buffer, 0, offset); downLength += offset;
downloader.update(this.threadId, block * (threadId - 1) + downLength);
downloader.saveLogFile(); downloader.append(offset);
int spare = block-downLength;//求剩下的字节数 if(spare < max) max = (int) spare;
flag = flags.get(this.downUrl.toString()); }
saveFile.close();
............................ return downLength; } }
说明:
Map flags = DownLoaderActivity.flags;Boolean flag = flags.get(this.downUrl.toString());
得到当前传入的flag的值。
while (flag && downLength < block && (offset =
inStream.read(buffer, 0, max)) != -1) { 判断下载的条件: 2. flag为true,
3. 当前线程已经下载的长度小于规定下载的长度 4. 每条线程每次下载的长度不为-1.
同时满足三条才可以进行下载。
flag = flags.get(this.downUrl.toString());
此句很重要,实时在监视flag的值,如果此时点击暂停则会传入false,下载功能就停止,设想一下,如果没有在页面上显示的是暂停状态,进度条的值是不变的,但是它的内部原来下载的线程还在一直的工作,可以用flag打印出它作比较。 if (flag == true) 就继续执行
新建实体bean名为InternetFile InternetFile.java
package com.sharpandroid.domain;
public class InternetFile {
private Integer fileid; private String name;
private String savepath; public InternetFile(){ }
public InternetFile(Integer fileid,String name,String savepath){
this.fileid = fileid; this.name = name;
this.savepath = savepath; }
public Integer getFileid() { return fileid; }
public void setFileid(Integer fileid) { this.fileid = fileid; }
public String getName() { return name;
}
}
public void setName(String name) { this.name = name; }
public String getSavepath() { return savepath; }
public void setSavepath(String savepath) { this.savepath = savepath; }
数据库部分:
在DBOpenHelper.java中更新代码:
package com.sharpandroid_video.download.service;
public class DBOpenHelper extends SQLiteOpenHelper { private static final String DBNAME = \"sharpandroid.db\"; private static final int VERSION = 1;
public DBOpenHelper(Context context) { super(context, DBNAME, null, VERSION); }
// 创建两个表 @Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(\"CREATE TABLE IF NOT EXISTS filedown (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, position INTEGER)\");
db.execSQL(\"CREATE TABLE IF NOT EXISTS downfile (fileid integer primary key autoincrement, name varchar(100), savepath varchar(255))\"); }
// 对表的表本进行更新 @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(\"DROP TABLE IF EXISTS filedown\"); db.execSQL(\"DROP TABLE IF EXISTS downfile\"); onCreate(db); } } 说明:
db.execSQL(\"CREATE TABLE IF NOT EXISTS downfile (fileid
integer primary key autoincrement, name varchar(100), savepath varchar(255))\");
在FileService.java中代码更新为:
package com.sharpandroid_video.download.service;
public class FileService {
private DBOpenHelper openHelper;
........................ /**
新建表downfile,它们的字段名分别为:
fileid为主键自动增长、name文件名、savepath保存路径。
* 网络下载文件的存储
*将下载完的文件名和文件的目录分别保存在数据库中。 */
public void save(InternetFile internetFile){
SQLiteDatabase database = openHelper.getWritableDatabase(); database.execSQL(\"insert into downfile(name, savepath) values(?,?)\new Object[]{
internetFile.getName(),internetFile.getSavepath()}); database.close(); } /**
* 下载文件的分页显示 * @param startResult * @param maxResult * @return */
public List getScrollData(int startResult, int maxResult){List InternetFiles = new ArrayList();SQLiteDatabase database = openHelper.getWritableDatabase(); Cursor cursor = database.rawQuery(\"select * from downfile limit ?,?\
new String[]{String.valueOf(startResult), String.valueOf(maxResult)});
while(cursor.moveToNext()){
InternetFiles.add(new InternetFile(cursor.getInt(0), cursor.getString(1), cursor.getString(2))); }
return InternetFiles; } }
在DownloadProgressListener 中代码更新为:
package com.sharpandroid_video.download.net.download;
public interface DownloadProgressListener { public void onDownloadSize(int size); }
下载模块的删除
新建DelFile类,实现对下载文件的删除操作
package com.sharpandroid_video.download.service;
public class DelFile {
private static final String TAG = \"DelFile\";
public static Boolean delFile(String filename){ try {
File file = new
File(Environment.getExternalStorageDirectory(), filename); Boolean flag = file.delete(); Log.i(TAG,flag.toString()); } catch (Exception e) { e.printStackTrace(); }
return true; } }
说明:
File file = new File(Environment.getExternalStorageDirectory(),
filename);
根据文件目录和文件名得到下载的文件。 Boolean flag = file.delete();
删除得到的文件,返回其值,如果为true则代表删除成功,如果为false则代表删除失败。 效果图如下:
点击【下载】如图: 点击【暂停】如图
点击【下载】继续下载 :
删除如图:
数据库中文件如图:
1.3.5 下载文件播放
已下载视频列表
实现思路:
已下载页面SaveFileActivity需要从数据库中读取已经下载的文件信息,构造自己的Adapter适配器,将Adapter加入到list列表中,将列表显示在页面上。当点
击每一个下载信息时会取得其保存地址,以意图形式发送到播放页面,完成播放操作。
新建SaveFileActivity类,用于显示已经下载文件的列表信息 public class SaveFileActivity extends Activity {
private static final String TAG =\"SaveFileActivity\"; private ListView listView;
private FileService fileService; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.savefile);
listView = (ListView) this.findViewById(R.id.listView); fileService = new FileService(this);
List internetFiles = fileService.getScrollData(0, 8);List> data = new ArrayList>();for(InternetFile internetFile : internetFiles){
HashMap map = new HashMap();map.put(\"fileid\
String.valueOf(internetFile.getFileid()));
map.put(\"name\
map.put(\"savepath\ data.add(map); }
SimpleAdapter adapter = new
SimpleAdapter(SaveFileActivity.this,data,R.layout.savefile, new String[]{\"fileid\new int[]{R.id.fileid,R.id.filename,R.id.savepath});
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) { HashMap itemdata = (HashMap) listView.getItemAtPosition(position);String savepath = itemdata.get(\"savepath\"); String name = itemdata.get(\"name\"); String fileid =itemdata.get(\"fileid\");
Log.i(TAG, \"personid=\"+ fileid+ \" name=\"+name + \" savepath=\"+ savepath);
Intent intent = new
Intent(SaveFileActivity.this,VideoPlayer.class);
intent.putExtra(\"savepath\ startActivity(intent); } }); } }
说明:
List internetFiles =fileService.getScrollData(0, 8);
调用fileService对象中的getScrollData方法得到规定每页显示的行数,并
返回internetFiles对象。
List> data = newArrayList>(); 定义一个HashMap数组并放入list列表中。 map.put(\"fileid\key为设定为fileid,value为调用internetFile的getFileid方法并转化为字符串。
data.add(map);
把得到的map放入已经定义的list列表中。
SimpleAdapter adapter = new SimpleAdapter
(SaveFileActivity.this,data,R.layout.savefile, new String[]{\"fileid\new
int[]{R.id.fileid,R.id.filename,R.id.savepath});
自定义一个SimpleAdapter。
listView.setAdapter(adapter);
将定义好的SimpleAdapter放入到listView控件中。 HashMap itemdata = (HashMap)listView.getItemAtPosition(position);
根据选择的position得到所在行的HashMap数组。
String savepath = itemdata.get(\"savepath\");
Intent intent = new
Intent(SaveFileActivity.this,VideoPlayer.class);
得到选择的itemdata的get方法得到文件的保存地址。
intent.putExtra(\"savepath\
startActivity(intent);
建立一个显示意图,并且向要打开的Activity类传送savepath数据。 效果图如下:
视频文件播放
在根据传递的URL视频地址,视频下载完成之后,将视频文件在手机SD卡上的存储路径传递给VideoPlayer类,然后播放视频文件。VideoPlayer类播放视频的代码我们在之前讲多媒体的时候,已经讲解过,这里就不再过多的解释,其中添加一个更新进度条和时间的内部类updateTime,代码如下;
新建VideoPlayer.java类实现文件的播放 实现
package com.sharpandroid.voide.activity;
public class VideoPlayer extends Activity{ private SurfaceView surfaceView; private MediaPlayer mediaPlayer; private ImageButton playbutton; private ImageButton upbutton; private ImageButton nextbutton;
private TextView playTime; private TextView totalTime; private SeekBar progressBar;
private String path;
private Handler mHandler = new Handler();
private boolean flog=true;
private static final String TAG = \"VideoPlayActivity\";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.video); Intent intent=this.getIntent(); path=intent.getStringExtra(\"path\");
playTime=(TextView)findViewById(R.id.playTime); totalTime=(TextView)findViewById(R.id.totalTime); progressBar=(SeekBar)findViewById(R.id.progress_bar);
surfaceView = (SurfaceView)this.findViewById(R.id.surfaceView); ButtonOnclickEnvent envent = new ButtonOnclickEnvent(); playbutton = (ImageButton)this.findViewById(R.id.button_play); playbutton.setOnClickListener(envent);
upbutton = (ImageButton)this.findViewById(R.id.button_up); upbutton.setOnClickListener(envent);
nextbutton = (ImageButton)this.findViewById(R.id.button_next); nextbutton.setOnClickListener(envent);
surfaceView.getHolder().setFixedSize(176, 144); mediaPlayer = new MediaPlayer();
playbutton.setImageResource(R.drawable.button_play); }
@Override
@Override
protected void onResume() {
if(mediaPlayer!=null){
if(!mediaPlayer.isPlaying()) mediaPlayer.start();
@Override
protected void onPause() { }
if(mediaPlayer!=null){ }
super.onPause();
if(mediaPlayer.isPlaying()) mediaPlayer.pause();
protected void onStart() { }
super.onStart();
//设置分辨率
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
}
super.onResume();
@Override
protected void onDestroy() { }
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDisplay(surfaceView.getHolder()); try { }
mediaPlayer.start();
mediaPlayer.setDataSource(path); mediaPlayer.prepare(); e.printStackTrace(); if(mediaPlayer!=null){ }
super.onDestroy();
if(mediaPlayer.isPlaying()) mediaPlayer.stop(); mediaPlayer.release();
public void play(){
} catch (Exception e) {
private class ButtonOnclickEnvent implements View.OnClickListener{
@Override
public void onClick(View v) {
try {
switch (v.getId()) {
case R.id.button_play: //播放
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
playbutton.setImageResource(R.drawable.button_play); flog=false;
if(flog) {
play();
}else{
//
}
new updateTime().start();
}else{ }
playbutton.setImageResource(R.drawable.button_pause); totalTime.setText(getTime(mediaPlayer.getDuration()));
mediaPlayer.start();
//获得音乐总时间
new updateTime().start(); } break;
case R.id.button_up: //播放后退 }
Log.e(TAG, e.toString());
mediaPlayer.seekTo(mediaPlayer.getCurrentPosition()-200); break;
mediaPlayer.seekTo(mediaPlayer.getCurrentPosition()+200); break;
mediaPlayer.start();
case R.id.button_next://播放快进
mediaPlayer.start();
} catch (Exception e) {
}
}
class updateTime extends Thread{
public void run() {
while (true) {
if( mediaPlayer.isPlaying())
mHandler.post(new Runnable() {
public void run(){
try {
progressBar.setMax(mediaPlayer.getDuration());
progressBar.setProgress(mediaPlayer.getCurrentPosition());//获得音乐播放的进度
}
}
}
});
}
}
Log.i(\"A\Log.i(\"A\int pos = 0; try {
pos = mediaPlayer.getCurrentPosition();
//获得音乐播放的进度
} catch (Exception e) { }
int min = (pos/1000)/60; int sec = (pos/1000)%60; if(sec<10)
playTime.setText(\"\"+min+\":0\"+sec);
//把音乐播放的进度,转换成时间
else
e.printStackTrace();
playTime.setText(\"\"+min+\":\"+sec); e.printStackTrace();
String.valueOf(mediaPlayer.getDuration())); String.valueOf(mediaPlayer.getCurrentPosition()));
} catch (Exception e) {
try {
Thread.sleep(1000); e.printStackTrace();
} catch (InterruptedException e) {
}
}
public String getTime(int c)//将进度转变为时间 { }
String time; int length=c/1000; int a= length/60; int b=length%60;
time=String.valueOf(a)+\":\"+String.valueOf(b); return time;
效果图如下:
AndroidManifest.xml具体代码为:
package=\"com.sharpandroid_video.sharpandroid\" xmlns:android=\"http://schemas.android.com/apk/res/android\">