App更新进度显示在后台通知栏详解

1.场景还原

      最近在项目中遇到App更新的问题,老大让更新进度直接显示在后台通知栏中,以前我都是用ProgressDialog撸成的,话说用户体验不好,要改成后台通知栏效果,好吧,谁让我不是老大的!改呗...今天就后台通知栏显示更新进度功能给大家伙分享一下,先上图:

App更新进度显示在后台通知栏详解_第1张图片
2.PendingIntent的介绍

    根据pend英文意思就知道是延迟的intent,主要用来在某个事件完成后执行特定的Action通常通过getActivity,getBroadcast ,getService来得到pendingintent的实例,当前activity并不能马上启动它所包含的intent,而是在外部执行 pendingintent时,调用intent的;常用在通知栏及短信发送系统中。PendingIntent一般作为参数传给某个实例,在该实例完成某个操作后自动执行PendingIntent上的Action,也可以通过PendingIntent的send函数手动执行,并可以在send函数中设置OnFinished表示send成功后执行的动作。

public static PendingIntent getActivity(Context context, int requestCode,
        Intent intent, @Flags int flags) {
    return getActivity(context, requestCode, intent, flags, null);
}
在该篇中的应用:
Intent intent = new Intent(Intent.ACTION_VIEW);//用于显示用户的数据。比较通用,会根据用户的数据类型打开相应的Activityintent.setDataAndType(uri,"application/vnd.android.package-archive");
pendingIntent = PendingIntent.getActivity(UpdateService.this, 0, intent, 0);
第一个参数是上下文,毋庸置疑!第二个参数是requestCode请求码,第三个是intent,第四个是Flags标志:

如果使用PendingIntent.FLAG_UPDATE_CURRENT,那么每次notifiId都是相同的数字,说明PendingIntent是一个,旧的参数被更新了。

如果使用PendingIntent.FLAG_ONE_SHOT,那么PendingIntent只是第一次有效,后来再点击别的Notification就无效。一般flags置为0。

3.Notification.builder的介绍

     在notification.setLastestEventInfo()方法被淘汰后,Notification.builder应运而生成功的替代了setLastestEventInfo(),这两种方式都是对通知栏状态的设置,比如:通知栏的标题,内容,以及进度完成后跳转的逻辑(pendingIntent),好了,好好看代码。


4.该功能的具体实现

1.Manifest.xml:
xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.updateappdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="17"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.updateappdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        
   <service 
          android:name=".UpdateService" >
   service>
        
    application>


manifest>
用户权限以及service注册不能忘记配置!
2.MainActivity
public class MainActivity extends Activity{

   public static final String appName = "updateAppTest";

   public static final String downUrl = "http://gdown.baidu.com/data/wisegame/bd47bd249440eb5f/shenmiaotaowang2.apk";
   
   private Button updateButton = null;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      
      setContentView(R.layout.activity_main);
      
      findViewById(R.id.updateButton).setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View view) {
            Intent intent = new Intent(MainActivity.this,UpdateService.class);
            intent.putExtra("Key_App_Name",appName);
            intent.putExtra("Key_Down_Url",downUrl);
            startService(intent);
         }
      });
   }


}
在主界面定义下载app的名字,以及下载链接,然后通过intent启动下载servcie
3.Fileutil类
/**
 * 文件处理类
 * @author zhangxing
 */
public class FileUtil {
   
   public static File updateDir = null;
   public static File updateFile = null;

   public static final String KonkaApplication = "konkaUpdateApplication";
   
   public static boolean isCreateFileSucess;


   public static void createFile(String app_name) {
      
      if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState())) {
         isCreateFileSucess = true;
         
         updateDir = new File(Environment.getExternalStorageDirectory()+ "/" + KonkaApplication +"/");
         updateFile = new File(updateDir + "/" + app_name + ".apk");

         if (!updateDir.exists()) {
            updateDir.mkdirs();
         }
         if (!updateFile.exists()) {
            try {
               updateFile.createNewFile();
            } catch (IOException e) {
               isCreateFileSucess = false;
               e.printStackTrace();
            }
         }

      }else{
         isCreateFileSucess = false;
      }
   }
}
这个类主要是创建包容apk的文件夹路径。
4.重头戏UpdateService的演绎
public class UpdateService extends Service {
   
   public static final String Install_Apk = "Install_Apk";
   /********download progress step*********/
   private static final int down_step_custom = 3;
   
   private static final int TIMEOUT = 10 * 1000;//设置反应时间
   private static String down_url;
   private static final int DOWN_OK = 1;
   private static final int DOWN_ERROR = 0;
   
   private String app_name;
   
   private NotificationManager notificationManager;
   private Notification notification;
   private Notification.Builder builder;
   private Intent updateIntent;
   private PendingIntent pendingIntent;
   private RemoteViews contentView;

      
   @Override
   public IBinder onBind(Intent arg0) {
      return null;
   }


   @Override
   public int onStartCommand(Intent intent, int flags, int startId) {
      
      app_name = intent.getStringExtra("Key_App_Name");
      down_url = intent.getStringExtra("Key_Down_Url");
      

      FileUtil.createFile(app_name);
      
      if(FileUtil.isCreateFileSucess == true){         
         createNotification();
         createThread();
      }else{
         Toast.makeText(this, R.string.insert_card, Toast.LENGTH_SHORT).show();
         stopSelf();
         
      }
      
      return super.onStartCommand(intent, flags, startId);
   }


   

   private final Handler handler = new Handler() {


      @Override
      public void handleMessage(Message msg) {
         switch (msg.what) {
         case DOWN_OK:


            Uri uri = Uri.fromFile(FileUtil.updateFile);
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(uri,"application/vnd.android.package-archive");
            pendingIntent = PendingIntent.getActivity(UpdateService.this, 0, intent, 0);

            //notification.flags = Notification.FLAG_AUTO_CANCEL; //点击后消失

             builder.setContentTitle(app_name);
            builder.setContentText(getString(R.string.down_sucess));
            builder.setContentIntent(pendingIntent);
            Notification notification2 = builder.getNotification();
            notification2.flags = Notification.FLAG_AUTO_CANCEL; //点击后消失
            //notification.setLatestEventInfo(UpdateService.this,app_name, getString(R.string.down_sucess), pendingIntent);
            //notification.setLatestEventInfo(UpdateService.this,app_name, app_name + getString(R.string.down_sucess), null);
            notificationManager.notify(R.layout.notification_item, notification2);


            stopSelf();
            break;

         case DOWN_ERROR:
            builder.setContentTitle(app_name);
            builder.setContentText(getString(R.string.down_fail));
            builder.setContentIntent(null);
            Notification notification3 = builder.getNotification();
            notification3.flags = Notification.FLAG_AUTO_CANCEL;
            //notification.setLatestEventInfo(UpdateService.this,app_name, getString(R.string.down_fail), pendingIntent);
            //notification.setLatestEventInfo(UpdateService.this,app_name, getString(R.string.down_fail), null);

            stopSelf();
            break;

         default:

            break;
         }
      }
   };

   /**
    * 自动安装的方法,用户点击安装时执行
    */
   private void installApk() {


      Uri uri = Uri.fromFile(FileUtil.updateFile);
      Intent intent = new Intent(Intent.ACTION_VIEW);

      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
      
      intent.setDataAndType(uri,"application/vnd.android.package-archive");                
        UpdateService.this.startActivity(intent);         
   }
   

   public void createThread() {
      new DownLoadThread().start();
   }

   
   private class DownLoadThread extends Thread{
      @Override
      public void run() {

         Message message = new Message();
         try {                       
            long downloadSize = downloadUpdateFile(down_url,FileUtil.updateFile.toString());
            if (downloadSize > 0) {                
               // down success                               
               message.what = DOWN_OK;
               handler.sendMessage(message);                                                     
            }
         } catch (Exception e) {
            e.printStackTrace();
            message.what = DOWN_ERROR;
            handler.sendMessage(message);
         }                 
      }     
   }


   /**
    * 创建一个通知栏
    */

   public void createNotification() {

       builder = new Notification.Builder(UpdateService.this)
            .setSmallIcon(R.drawable.ic_launcher)
            .setContentText(getString(R.string.is_downing));


      notification = builder.getNotification();

      notification.flags = Notification.FLAG_ONGOING_EVENT; 

      contentView = new RemoteViews(getPackageName(),R.layout.notification_item);
      contentView.setTextViewText(R.id.notificationTitle, app_name + getString(R.string.is_downing));
      contentView.setTextViewText(R.id.notificationPercent, "0%");
      contentView.setProgressBar(R.id.notificationProgress, 100, 0, false);
      notification.contentView = contentView;

      notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
      notificationManager.notify(R.layout.notification_item, notification);
   }



   public long downloadUpdateFile(String down_url, String file)throws Exception {
      
      int down_step = down_step_custom;
      int totalSize;
      int downloadCount = 0;
      int updateCount = 0;
      
      InputStream inputStream;
      OutputStream outputStream;

      URL url = new URL(down_url);
      HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
      httpURLConnection.setConnectTimeout(TIMEOUT);
      httpURLConnection.setReadTimeout(TIMEOUT);
      totalSize = httpURLConnection.getContentLength();
      
      if (httpURLConnection.getResponseCode() == 404) {
         throw new Exception("fail!");

      }
      
      inputStream = httpURLConnection.getInputStream();
      outputStream = new FileOutputStream(file, false);
      
      byte buffer[] = new byte[1024];
      int readsize = 0;
      
      while ((readsize = inputStream.read(buffer)) != -1) {
         

                  
         outputStream.write(buffer, 0, readsize);
         downloadCount += readsize;
         if (updateCount == 0 || (downloadCount * 100 / totalSize - down_step) >= updateCount) {
            updateCount += down_step;
            contentView.setTextViewText(R.id.notificationPercent,updateCount + "%");
            contentView.setProgressBar(R.id.notificationProgress, 100,updateCount, false);       
            notification.contentView = contentView;
            notificationManager.notify(R.layout.notification_item, notification);        
         }
      }
      if (httpURLConnection != null) {
         httpURLConnection.disconnect();
      }
      inputStream.close();
      outputStream.close();
      
      return downloadCount;
   }

}
其中的Notification.Builder成功的替代了已被淘汰的setLastestEventInfo()方法:
 builder.setContentTitle(app_name);
 builder.setContentText(getString(R.string.down_sucess));
 builder.setContentIntent(pendingIntent);
setLastestEventInfo()中是这样的:
notification.setLatestEventInfo(UpdateService.this,app_name, getString(R.string.down_sucess), pendingIntent);
再者,还包含一个安装app的方法:
private void installApk() {
   
   Uri uri = Uri.fromFile(FileUtil.updateFile);
   Intent intent = new Intent(Intent.ACTION_VIEW);

   intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
   
   intent.setDataAndType(uri,"application/vnd.android.package-archive");                
       UpdateService.this.startActivity(intent);          
}
该方法其实也没多大必要写,不过,如果想自动安装的话,这个方法就派上用场了。另外
notification.flags = Notification.FLAG_AUTO_CANCEL; //点击后消失
下载完成后点击通知栏中的notification,然后它会自动消失。
好了,今天就到这了,传送门地址: http://download.csdn.net/detail/zhangxing52077/9711712,我是张星,欢迎大家的关注,后期章节更精彩!



你可能感兴趣的:(android)