分享到:
点击次数:333  更新时间:2016-10-11 16:24:04  【打印此页】  【关闭
澳门新濠天地娱乐场澳门新濠天地娱乐定制
当前位置:主页 > 新闻动态 > 技术交流 > Android文件下载及自定义通知显示下载进度

Android文件下载及自定义通知显示下载进度

责任编辑:admin 发布时间:2016-11-11 09:26 浏览次数:

主要实现了一下几个类:
(1)文件下载:设计自定义类,只需传入一个Handler、下载地址URLStr及保存路径及可实现下载的功能。handler主要用于线程间通信,跟新通知中的进度条。
     对于handler发送消息更新UI线程实现进度展示的时候一定注意不要太过频繁,过设置计数器隔一定时间才发送消息,不然容易引起系统奔溃
   (2) 通知(Notification):提供系统默认自带形式以及自定义通知栏布局两种形式。
  (3) 服务:后台服务,startService启动模式
 
    package com.example.test; 
     
    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 android.annotation.SuppressLint; 
    import android.os.Environment; 
    import android.os.Handler; 
    import android.os.Message; 
    import android.os.StrictMode; 
    import android.util.Log; 
     
    @SuppressLint("NewApi") 
    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) 
        { 
            Log.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; 
        } 
         
        @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(5000); 
                    conn.setReadTimeout(20000); 
                    iStream = conn.getInputStream(); 
                } catch (MalformedURLException e) { 
                    Log.i(TAG, "MalformedURLException"); 
                    e.printStackTrace(); 
                } catch (Exception e) { 
                    Log.i(TAG, "获得输入流失败"); 
                    e.printStackTrace(); 
                } 
                FileOutputStream fos = null; 
                try { 
                    fos = new FileOutputStream(apkFile); 
                } catch (FileNotFoundException e) { 
                     Log.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 total = 0; 
                int times=0;//设置更新频率,频繁操作UI线程会导致系统奔溃 
                try { 
                     Log.i("threadStatus", "开始下载"); 
                    while (false==interupted  && ((len = bis.read(buffer)) != -1)) { 
                        fos.write(buffer, 0, len); 
                        // 获取已经读取长度 
                         
                        total += len; 
                        int p=(int)(total*rate); 
                        Log.i("num", rate+","+total+","+p); 
                        if(times>=512 || p==100) 
                        {/*
                        这是防止频繁地更新通知,而导致系统变慢甚至崩溃。 
                                                                 非常重要。。。。。*/ 
                            Log.i("time", "time"); 
                            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); 
                        Log.i(TAG, "下载完成结束"); 
                    } 
                     Log.i(TAG, "强制中途结束"); 
                    //mhandler.sendEmptyMessage(4); 
                } catch (IOException e) { 
                    Log.i(TAG, "异常中途结束"); 
                    mHandler.sendEmptyMessage(DOWNLOAD_FAIL); 
                    e.printStackTrace(); 
                } 
            } 
            else 
            { 
                Log.i(TAG, "外部存储卡不存在,下载失败!"); 
                mHandler.sendEmptyMessage(DOWNLOAD_FAIL); 
            } 
        } 
    } 
    package com.example.test; 
     
    import android.app.Notification; 
    import android.app.NotificationManager; 
    import android.app.PendingIntent; 
    import android.content.Context; 
    import android.widget.RemoteViews; 
    /** 
     * Notification类,既可用系统默认的通知布局,也可以用自定义的布局 
     *  
     * @author lz 
     * 
     */ 
    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);   
        }   
           
    } 
package com.example.test; 
 
import java.io.File; 
 
import android.app.Notification; 
import android.app.NotificationManager; 
import android.app.PendingIntent; 
import android.app.Service; 
import android.content.Context; 
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.provider.Settings.Global; 
import android.util.Log; 
 
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 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");                      
                     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("文件下载失败!"); 
                    stopSelf(); 
                    break; 
                default:  //下载中 
                    Log.i("service", "default"+msg.what); 
        //          myNotification.changeNotificationText(msg.what+"%"); 
            myNotification.changeProgressStatus(msg.what);   
            } 
        } 
    }; 
     
    public DownloadServices() { 
        // TODO Auto-generated constructor stub 
    //  mcontext=context; 
        Log.i("service","DownloadServices1"); 
         
    } 
 
    @Override 
    public void onCreate() { 
        // TODO Auto-generated method stub 
        Log.i("service","onCreate"); 
        super.onCreate(); 
    } 
 
    @Override 
    public void onDestroy() { 
        // TODO Auto-generated method stub 
        Log.i("service","onDestroy"); 
        if(downFileThread!=null) 
        downFileThread.interuptThread(); 
        stopSelf(); 
        super.onDestroy(); 
    } 
 
    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
        // TODO Auto-generated method stub 
        Log.i("service","onStartCommand"); 
 
        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); 
         
        filePathString=Environment.getExternalStorageDirectory().getAbsolutePath() + "/family.apk"; 
         
        //开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞 
        downFileThread=new  DownFileThread(updateHandler,"http://10.103.241.247:8013/update/download",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 
        Log.i("service","onStart"); 
        super.onStart(intent, startId); 
    } 
 
    @Override 
    public IBinder onBind(Intent arg0) { 
        // TODO Auto-generated method stub 
        Log.i("service","onBind"); 
        return null; 
    }