android implements the notification bar to download the update app example

  • 2020-05-30 21:01:22
  • OfStack

1. Design idea, VersionCode is defined as the version upgrade parameter.
android provides two properties for us to define the version:


<manifest package="com.cnblogs.tianxia.subway"
android:versionCode="1" <!--Integer Type that the system does not display to the user -->
android:versionName="1.0"<!--String Type, system display user -->
></manifest>

Google suggests that we use versionCode autoincrement to indicate the version upgrade, whether it is a big change or a small change, while versionName is the software version that the user sees, used as a display. So we chose VersionCode as our defined version upgrade parameter.

2. Project directory
In order to provide practical guidance for real projects or enterprises, I simulated an independent project with reasonable and rigorous project directory setting, rather than just one demo.
Suppose we take Shanghai subway as the project and name it "Subway". The project structure is as follows:

3. Comparison between version initialization and version number.
Define the variables localVersion and serverVersion in the global file Global.java to hold the local version number and the server version number, respectively.


public class Global {
// Version information 
public static int localVersion = 0;
public static int serverVersion = 0;
public static String downloadDir = "app/download/";
}

Since this article only focuses on updates, I'll define the initGlobal() method directly in SubwayApplication to prevent too much other irrelevant code redundancy.

/**
*  Initializes global variables 
*  In practice, in this method serverVersion Get from the server side, preferably in the startup screen activity Performed in the 
*/
public void initGlobal(){
try{
Global.localVersion = getPackageManager().getPackageInfo(getPackageName(),0).versionCode; // Set the local version number 
Global.serverVersion = 1;// Assume the server version is 2 , the local version defaults to 1
}catch (Exception ex){
ex.printStackTrace();
}
}

If a new release is detected and the user is prompted to update, I have defined the checkVersion() method in SubwayActivity:

/**
*  Check for updated versions 
*/
public void checkVersion(){
if(Global.localVersion < Global.serverVersion){
// A new version is found and the user is prompted to update 
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle(" Software upgrade ")
.setMessage(" Discover a new version , It is recommended to update immediately .")
.setPositiveButton(" update ", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Enable update service UpdateService
// In order to put update Better modularized, passable 1 some updateService Depend on the value of the 
// Such as the layout ID Resources, ID , dynamically acquired title , Here to app_name As an example 
Intent updateIntent =new Intent(SubwayActivity.this, UpdateService.class);
updateIntent.putExtra("titleId",R.string.app_name);
startService(updateIntent);
}
})
.setNegativeButton(" cancel ",new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert.create().show();
}else{
// Clean up. Skip it 
//cheanUpdateFile(), I'll include the code at the end of this article 
}
}

Ok, now let's string these things together:
Step 1 performs initGlobal() in SubwayApplication's onCreate() method to initialize the version variable.


public void onCreate() {
super.onCreate();
initGlobal();
}

Step 2 detects the version update checkVersion() in SubwayActivity's onCreate() method.

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
checkVersion();

The entry is now open. As you can see in line 18 of the checkVersion method, when the user clicks update, we start the update service and download the latest version from the server.
4. Download from the server side in the background using Service, and then prompt the user to complete the download and close the service.
Define one service, UpdateService.java, and first define the variables associated with download and notification:


// The title 
private int titleId = 0;
// File storage 
private File updateDir = null;  
private File updateFile = null;
// Notification bar 
private NotificationManager updateNotificationManager = null;
private Notification updateNotification = null;
// Notice bar jump Intent
private Intent updateIntent = null;
private PendingIntent updatePendingIntent = null;

Prepare the relevant downloads in the onStartCommand() method:


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Get the value 
titleId = intent.getIntExtra("titleId",0);
// Create a file 
if(android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState())){
updateDir = new File(Environment.getExternalStorageDirectory(),Global.downloadDir);
updateFile = new File(updateDir.getPath(),getResources().getString(titleId)+".apk");
}
this.updateNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
this.updateNotification = new Notification();
// To set up the download process, click the notification bar and return to the main interface 
updateIntent = new Intent(this, SubwayActivity.class);
updatePendingIntent = PendingIntent.getActivity(this,0,updateIntent,0);
// Set the notification bar to display content 
updateNotification.icon = R.drawable.arrow_down_float;
updateNotification.tickerText = " Start the download ";
updateNotification.setLatestEventInfo(this," Shanghai metro ","0%",updatePendingIntent);
// A notice 
updateNotificationManager.notify(0,updateNotification);
// open 1 Five new threads to download if used Service Simultaneous downloads will cause ANR The problem, Service It's going to block itself 
new Thread(new updateRunnable()).start();// This is the point of downloading, the process of downloading 
return super.onStartCommand(intent, flags, startId);
}

It's all preparation

It can be seen from the code that updateRunnable class is the real downloaded class. For the sake of user experience, this class is executed by a single thread in the background.
The download process has two jobs: 1. Download data from the server; 2. 2. Inform users of download progress.
Thread notification, we first define an empty updateHandler.
[/code]
private Handler updateHandler = new Handler(){
@Override
public void handleMessage(Message msg) {

}
};
[/code]
To create the actual implementation of the updateRunnable class:


class updateRunnable implements Runnable {
Message message = updateHandler.obtainMessage();
public void run() {
message.what = DOWNLOAD_COMPLETE;
try{
// Increase the permissions <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">;
if(!updateDir.exists()){
updateDir.mkdirs();
}
if(!updateFile.exists()){
updateFile.createNewFile();
}
// Download the function to QQ For example, 
// Increase the permissions <uses-permission android:name="android.permission.INTERNET">;
long downloadSize = downloadUpdateFile("http://softfile.3g.qq.com:8080/msoft/179/1105/10753/MobileQQ1.0(Android)_Build0198.apk",updateFile);
if(downloadSize>0){
// Download successful 
updateHandler.sendMessage(message);
}
}catch(Exception ex){
ex.printStackTrace();
message.what = DOWNLOAD_FAIL;
// Download failed 
updateHandler.sendMessage(message);
}
}
}
</uses-permission></uses-permission>

There are many implementations of the download function. I will post the code here, and we will notify the user of the download progress when downloading:

public long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception {
// There are a lot of downloadable code, so I won't go into too much detail 
int downloadCount = 0;
int currentSize = 0;
long totalSize = 0;
int updateTotalSize = 0;
HttpURLConnection httpConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL(downloadUrl);
httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("User-Agent", "PacificHttpClient");
if(currentSize > 0) {
httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-");
}
httpConnection.setConnectTimeout(10000);
httpConnection.setReadTimeout(20000);
updateTotalSize = httpConnection.getContentLength();
if (httpConnection.getResponseCode() == 404) {
throw new Exception("fail!");
}
is = httpConnection.getInputStream(); 
fos = new FileOutputStream(saveFile, false);
byte buffer[] = new byte[4096];
int readsize = 0;
while((readsize = is.read(buffer)) > 0){
fos.write(buffer, 0, readsize);
totalSize += readsize;
// To prevent frequent notifications from straining the application, the percentage increases 10 To notify 1 time 
if((downloadCount == 0)||(int) (totalSize*100/updateTotalSize)-10>downloadCount){ 
downloadCount += 10;
updateNotification.setLatestEventInfo(UpdateService.this, " Is downloading ", (int)totalSize*100/updateTotalSize+"%", updatePendingIntent);
updateNotificationManager.notify(0, updateNotification);
} 
}
} finally {
if(httpConnection != null) {
httpConnection.disconnect();
}
if(is != null) {
is.close();
}
if(fos != null) {
fos.close();
}
}
return totalSize;
}

After the download is completed, we will prompt the user to complete the download and click "install", so let's complete the previous Handler.
Define two constants in UpdateService.java to represent the download status:


// Download status 
private final static int DOWNLOAD_COMPLETE = 0;
private final static int DOWNLOAD_FAIL = 1;

The main thread is processed according to the download status:

private Handler updateHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case DOWNLOAD_COMPLETE:
// Click on the install PendingIntent
Uri uri = Uri.fromFile(updateFile);
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
updatePendingIntent = PendingIntent.getActivity(UpdateService.this, 0, installIntent, 0);
updateNotification.defaults = Notification.DEFAULT_SOUND;// The bell remind  
updateNotification.setLatestEventInfo(UpdateService.this, " Shanghai metro ", " The download is complete , Click install. ", updatePendingIntent);
updateNotificationManager.notify(0, updateNotification);
// Stop the service 
stopService(updateIntent);
case DOWNLOAD_FAIL:
// Download failed 
updateNotification.setLatestEventInfo(UpdateService.this, " Shanghai metro ", " The download is complete , Click install. ", updatePendingIntent);
updateNotificationManager.notify(0, updateNotification);
default:
stopService(updateIntent);
}
}
};


At this point, the file is downloaded and progress is notified in the notification bar.
I found myself a lot of nonsense, in fact, a few words of things, back and forth to write so much, wordy, I will work towards streamlining in the following blog.
PS: the code for cheanUpdateFile() was mentioned earlier

File updateFile = new File(Global.downloadDir,getResources().getString(R.string.app_name)+".apk");
if(updateFile.exists()){
// Clear previous downloads when not needed to avoid wasting user space 
updateFile.delete(); 
}


Related articles: