[置顶] Android Service下载文件并自定义通知提示下载
2016-08-09 11:07
344 查看
最近要做一个更新sdk,里面用到了service后台下载,自定义通知提示下载进度,下面直接贴上代码.
下面是UpdateUtils.java ,告诉你如何使用
package com.cnziz.updatelib; import com.cnziz.updatelib.download.DownloadServices; import com.cnziz.updatelib.utils.Listener.onUpdateListener; import android.content.Context; import android.content.Intent; public class UpdateUtils { public static UpdateUtils mUpdateUtils; public static UpdateUtils getInstanse(){ if (null == mUpdateUtils) { mUpdateUtils = new UpdateUtils(); } return mUpdateUtils; } public void update(Context context, String appInfo, onUpdateListener mUpdateListener){ String url = "https://qd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk"; String filePath = "/sdcard/download"; download(context, url, filePath, mUpdateListener); } /** * 下载更新 * @param context * @param url 下载地址 * @param filePath 保存目录 * @param mUpdateListener */ public void download(Context context, String url, String filePath, onUpdateListener mUpdateListener){ Intent intent = new Intent(context, DownloadServices.class); intent.putExtra("url", url); intent.putExtra("file_path", filePath); context.startService(intent); } }
DownloadService.java
package com.cnziz.updatelib.download; import java.io.File; import java.io.IOException; import android.app.Notification; 4000 import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; import com.cnziz.updatelib.R; import com.cnziz.updatelib.utils.Listener.onUpdateListener; import com.cnziz.updatelib.utils.LogUtils; public class DownloadServices extends Service { private final static int DOWNLOAD_COMPLETE = -2; private final static int DOWNLOAD_FAIL = -1; // 自定义通知栏类 MyNotification myNotification; String filePathString; // 下载文件绝对路径(包括文件名) // 通知栏跳转Intent private Intent updateIntent = null; private PendingIntent updatePendingIntent = null; DownFileThread downFileThread; // 自定义文件下载线程 private onUpdateListener mUpdateListener; private Handler updateHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLOAD_COMPLETE: // 点击安装PendingIntent Uri uri = Uri.fromFile(downFileThread.getApkFile()); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(installIntent); // updatePendingIntent = PendingIntent.getActivity( // DownloadServices.this, 0, installIntent, 0); // myNotification.changeContentIntent(updatePendingIntent); // myNotification.notification.defaults = Notification.DEFAULT_SOUND;// 铃声提醒 // myNotification.changeNotificationText("下载完成,请点击安装!"); // 停止服务 // myNotification.removeNotification(); stopSelf(); break; case DOWNLOAD_FAIL: // 下载失败 // myNotification.changeProgressStatus(DOWNLOAD_FAIL); myNotification.changeNotificationText("文件下载失败!"); mUpdateListener.downloadFail(); stopSelf(); break; default: // 下载中 LogUtils.e("service", "index" + msg.what); // myNotification.changeNotificationText(msg.what+"%"); myNotification.changeProgressStatus(msg.what); } } }; public DownloadServices() { // TODO Auto-generated constructor stub // mcontext=context; LogUtils.e("service", "DownloadServices1"); } @Override public void onCreate() { // TODO Auto-generated method stub LogUtils.e("service", "onCreate"); super.onCreate(); } @Override public void onDestroy() { // TODO Auto-generated method stub LogUtils.e("service", "onDestroy"); if (downFileThread != null) downFileThread.interuptThread(); // if (null != myNotification) { // myNotification.removeNotification(); // } stopSelf(); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub LogUtils.e("service", "onStartCommand"); String url = intent.getStringExtra("url"); String filePath = intent.getStringExtra("file_path"); mUpdateListener = (onUpdateListener) intent.getParcelableExtra("listener"); // updateIntent = new Intent(this, MainActivity.class); // PendingIntent updatePendingIntent = PendingIntent.getActivity(this, // 0, // updateIntent, 0); myNotification = new MyNotification(this, updatePendingIntent, 1); // myNotification.showDefaultNotification(R.drawable.ic_launcher, "测试", // "开始下载"); myNotification.showCustomizeNotification(R.drawable.ic_launcher, "测试下载", R.layout.notification); if (!filePath.endsWith("/")) { filePath = filePath +"/"; } File path = new File(filePath); if (!path.exists()) { path.mkdir(); } String[] s = url.split("/"); filePathString = filePath + s[s.length-1]; File file = new File(filePathString); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞 downFileThread = new DownFileThread( updateHandler, url, filePathString); new Thread(downFileThread).start(); return super.onStartCommand(intent, flags, startId); } @Override @Deprecated public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub LogUtils.e("service", "onStart"); super.onStart(intent, startId); } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub LogUtils.e("service", "onBind"); return null; } }
下载线程 DownFileThread.java
package com.cnziz.updatelib.download; import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import com.cnziz.updatelib.utils.LogUtils; import android.annotation.SuppressLint; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.os.StrictMode; import android.util.Log; public class DownFileThread implements Runnable { public final static int DOWNLOAD_COMPLETE = -2; public final static int DOWNLOAD_FAIL = -1; public final static String TAG = "DownFileThread"; Handler mHandler; // 传入的Handler,用于像Activity或service通知下载进度 String urlStr; // 下载URL File apkFile; // 文件保存路径 boolean isFinished; // 下载是否完成 boolean interupted = false; // 是否强制停止下载线程 public DownFileThread(Handler handler, String urlStr, String filePath) { LogUtils.i(TAG, urlStr); this.mHandler = handler; this.urlStr = urlStr; apkFile = new File(filePath); isFinished = false; } public File getApkFile() { if (isFinished) return apkFile; else return null; } public boolean isFinished() { return isFinished; } /** * 强行终止文件下载 */ public void interuptThread() { interupted = true; } @SuppressLint("NewApi") @Override public void run() { // TODO Auto-generated method stub if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { java.net.URL url = null; HttpURLConnection conn = null; InputStream iStream = null; // if (DEVELOPER_MODE) { StrictMode .setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads().detectDiskWrites() .detectNetwork() // or .detectAll() for all // detectable problems .penaltyLog().build()); StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() .detectLeakedSqlLiteObjects() .detectLeakedClosableObjects().penaltyLog() .penaltyDeath().build()); } try { url = new java.net.URL(urlStr); conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5 * 1000); c180 conn.setReadTimeout(20 * 1000); iStream = conn.getInputStream(); } catch (MalformedURLException e) { LogUtils.e(TAG, "MalformedURLException"); e.printStackTrace(); } catch (Exception e) { LogUtils.e(TAG, "获得输入流失败"); e.printStackTrace(); } FileOutputStream fos = null; try { fos = new FileOutputStream(apkFile); } catch (FileNotFoundException e) { LogUtils.i(TAG, "获得输出流失败:new FileOutputStream(apkFile);"); e.printStackTrace(); } BufferedInputStream bis = new BufferedInputStream(iStream); byte[] buffer = new byte[1024]; int len; // 获取文件总长度 int length = conn.getContentLength(); double rate = (double) 100 / length; // 最大进度转化为100 int timeLoad = length/100/1024; int total = 0; int times = 0;// 设置更新频率,频繁操作UI线程会导致系统奔溃 try { LogUtils.e("threadStatus", "开始下载"); while (false == interupted && ((len = bis.read(buffer)) != -1)) { fos.write(buffer, 0, len); // 获取已经读取长度 total += len; int p = (int) (total * rate); // Log.e("num", rate + "," + total + "," + p); if (times >= timeLoad || p == 100) { /* * 这是防止频繁地更新通知,而导致系统变慢甚至崩溃。 非常重要。。。。。 */ LogUtils.e("time", String.valueOf(times)); times = 0; Message msg = Message.obtain(); msg.what = p; mHandler.sendMessage(msg); } times++; } fos.close(); bis.close(); iStream.close(); if (total == length) { isFinished = true; mHandler.sendEmptyMessage(DOWNLOAD_COMPLETE); LogUtils.e(TAG, "下载完成结束"); return; } LogUtils.e(TAG, "强制中途结束"); // mhandler.sendEmptyMessage(4); } catch (IOException e) { LogUtils.e(TAG, "异常中途结束"); mHandler.sendEmptyMessage(DOWNLOAD_FAIL); e.printStackTrace(); } } else { LogUtils.e(TAG, "外部存储卡不存在,下载失败!"); mHandler.sendEmptyMessage(DOWNLOAD_FAIL); } } }
自定义通知 MyNotification.java
package com.cnziz.updatelib.download; import com.cnziz.updatelib.R; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.widget.RemoteViews; public class MyNotification { public final static int DOWNLOAD_COMPLETE = -2; public final static int DOWNLOAD_FAIL = -1; Context mContext; // Activity或Service上下文 Notification notification; // notification NotificationManager nm; String titleStr; // 通知标题 String contentStr; // 通知内容 PendingIntent contentIntent; // 点击通知后的动作 int notificationID; // 通知的唯一标示ID int iconID; // 通知栏图标 long when = System.currentTimeMillis(); RemoteViews remoteView = null; // 自定义的通知栏视图 /** * * @param context * Activity或Service上下文 * @param contentIntent * 点击通知后的动作 * @param id * 通知的唯一标示ID */ public MyNotification(Context context, PendingIntent contentIntent, int id) { // TODO Auto-generated constructor stub mContext = context; notificationID = id; this.contentIntent = contentIntent; this.nm = (NotificationManager) mContext .getSystemService(Context.NOTIFICATION_SERVICE); } /** * 显示自定义通知 * * @param icoId * 自定义视图中的图片ID * @param titleStr * 通知栏标题 * @param layoutId * 自定义布局文件ID */ public void showCustomizeNotification(int icoId, String titleStr, int layoutId) { this.titleStr = titleStr; notification = new Notification(R.drawable.ic_launcher, titleStr, when); notification.flags = Notification.FLAG_ONLY_ALERT_ONCE; notification.flags |= Notification.FLAG_AUTO_CANCEL; notification.contentIntent = this.contentIntent; // 1、创建一个自定义的消息布局 view.xml // 2、在程序代码中使用RemoteViews的方法来定义image和text。然后把RemoteViews对象传到contentView字段 if (remoteView == null) { remoteView = new RemoteViews(mContext.getPackageName(), layoutId); remoteView.setImageViewResource(R.id.ivNotification, icoId); remoteView.setTextViewText(R.id.tvTitle, titleStr); remoteView.setTextViewText(R.id.tvTip, "开始下载"); remoteView.setProgressBar(R.id.pbNotification, 100, 0, false); notification.contentView = remoteView; } nm.notify(notificationID, notification); } /** * 更改自定义布局文件中的进度条的值 * * @param p * 进度值(0~100) */ public void changeProgressStatus(int p) { if (notification.contentView != null) { if (p == DOWNLOAD_FAIL) notification.contentView.setTextViewText(R.id.tvTip, "下载失败! "); else if (p == 100) notification.contentView.setTextViewText(R.id.tvTip, "下载完成,请点击安装"); else notification.contentView.setTextViewText(R.id.tvTip, "进度(" + p + "%)"); notification.contentView.setProgressBar(R.id.pbNotification, 100, p, false); } nm.notify(notificationID, notification); } public void changeContentIntent(PendingIntent intent) { this.contentIntent = intent; notification.contentIntent = intent; } /** * 显示系统默认格式通知 * * @param iconId * 通知栏图标ID * @param titleText * 通知栏标题 * @param contentStr * 通知栏内容 */ public void showDefaultNotification(int iconId, String titleText, String contentStr) { this.titleStr = titleText; this.contentStr = contentStr; this.iconID = iconId; notification = new Notification(); notification.tickerText = titleStr; notification.icon = iconID; notification.flags = Notification.FLAG_INSISTENT; notification.flags |= Notification.FLAG_AUTO_CANCEL; notification.contentIntent = this.contentIntent; // 添加声音效果 // notification.defaults |= Notification.DEFAULT_SOUND; // 添加震动,后来得知需要添加震动权限 : Virbate Permission // mNotification.defaults |= Notification.DEFAULT_VIBRATE ; // 添加状态标志 // FLAG_AUTO_CANCEL 该通知能被状态栏的清除按钮给清除掉 // FLAG_NO_CLEAR 该通知能被状态栏的清除按钮给清除掉 // FLAG_ONGOING_EVENT 通知放置在正在运行 // FLAG_INSISTENT 通知的音乐效果一直播放 notification.flags = Notification.FLAG_ONLY_ALERT_ONCE; changeNotificationText(contentStr); } /** * 改变默认通知栏的通知内容 * * @param content */ public void changeNotificationText(String content) { notification.setLatestEventInfo(mContext, titleStr, content, contentIntent); // 设置setLatestEventInfo方法,如果不设置会App报错异常 // NotificationManager mNotificationManager = (NotificationManager) // getSystemService(Context.NOTIFICATION_SERVICE); // 注册此通知 // 如果该NOTIFICATION_ID的通知已存在,会显示最新通知的相关信息 ,比如tickerText 等 nm.notify(notificationID, notification); } /** * 移除通知 */ public void removeNotification() { // 取消的只是当前Context的Notification nm.cancel(notificationID); } }
主要代码都在这了,下面是完整的项目链接
https://github.com/yan1348/ServiceDownLoad
相关文章推荐
- Android Service下载文件并自定义通知提示下载
- android文件下载及自定义通知显示下载进度
- IIS7.5 配置自定义后缀的ASP文件 无法执行 总是提示下载的解决方法
- android 通知栏提示下载文件
- Android 文件断点下载和通知栏的提示及apk更新安装
- android+https网址屏蔽证书+IntentService+NotifyManager通知栏+下载apk文件+在通知栏显示下载进度+完成之后提示安装
- 使文件下载的自定义连接支持 FlashGet 的断点续传多线程链接下载! C#/ASP.Net 实现!
- ASP中自定义文件下载
- 让自定义文件下载支持断点续传
- 关于在vs.net中的.htm里面添加连接,就会出现下载.ASPX文件的提示?
- ASP.NET中提示客户端下载文件
- asp中自定义文件下载方式.
- vb.net后台http下载无提示覆盖文件
- xml文件提示下载,IE打不开
- 下载的时候提示:“写入到文件时产生错误(请用磁盘检查工具检查修复)”的解决办法
- 提示缺少“S2CSplash.DLL"的解决方法,下载此文件放到才程序目录即可
- 30余个CSS导航菜单效果(提示:要将文件下载下来看才有用,“演示”没用)
- 使文件下载的自定义连接支持 FlashGet 的断点续传多线程链接下载! C#/ASP.Net 实现!
- Control Study->AdRotator广告控件显示自定义配置文件中广告以及与DataGrid控件结合使用显示图片(示例代码下载)
- ASP中自定义文件下载