In the past few days, we have implemented an APK version update function, and found that it involves a lot of things. I have written the relevant content into a relatively independent category for future reference and share it with you. You are welcome to criticize and correct it.
The following classes are implemented:
(1) File Download: a custom class is designed. You only need to input a Handler, URLStr, storage path, and download function. Handler is mainly used for inter-thread communication and the progress bar in the new notification.
When handler sends a message to update the UI thread to display the progress, be sure not to send the message too frequently. The system will send the message after setting the counter for a certain period of time. Otherwise, the system may crash.
(2) Notification: Provides the default built-in form and custom Notification bar layout.
(3) Service: Background Service, startService Startup Mode
Package com. Example. The test;
Import the Java. IO. BufferedInputStream;
Import the Java. IO. The File;
Import the Java. IO. FileNotFoundException;
Import the Java. IO. FileOutputStream;
Import the Java. IO. IOException;
Import the Java. IO. InputStream;
The import java.net.HttpURLConnection;
The import java.net.MalformedURLException;
The import android. The annotation. SuppressLint;
The import android. OS. The Environment;
The import android. OS. Handler;
The import android. OS. The Message;
The import android. OS. StrictMode.
The 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; // the incoming Handler is used to notify the download progress like an Activity or service
String urlStr; / / download URL
The File apkFile; // file save path
Boolean isFinished; // download completed
Boolean interupted = false; // whether to force the download thread to stop
Public DownFileThread(Handler Handler,String urlStr,String filePath)
{
The Log. I (TAG, urlStr);
Enclosing mHandler = handler;
Enclosing urlStr = urlStr;
ApkFile = new File (filePath);
IsFinished = false;
}
The public File getApkFile ()
{
If (isFinished)
Return apkFile;
The else
Return null;
}
Public Boolean isFinished () {
Return isFinished;
}
/ * *
* forced termination of file download
* /
Public void interuptThread ()
{
Interupted = true;
}
@ Override
Public void the run () {
// TODO auto-generated method stub
If (Environment. GetExternalStorageState (.) equals (
Environment. MEDIA_MOUNTED)) {
Java.net.URL url = null;
HttpURLConnection conn = null;
InputStream cost = null;
/ / if (DEVELOPER_MODE)
{
StrictMode. SetThreadPolicy (new StrictMode. ThreadPolicy. Builder ()
DetectDiskReads ()
DetectDiskWrites ()
DetectNetwork () / / or detectAll () for all detectable the problems
PenaltyLog ()
The build ());
StrictMode. SetVmPolicy (new StrictMode. VmPolicy. Builder ()
DetectLeakedSqlLiteObjects ()
DetectLeakedClosableObjects ()
PenaltyLog ()
PenaltyDeath ()
The build ());
}
Try {
Url = new java.net.URL (urlStr);
Conn = (HttpURLConnection) url. OpenConnection ();
Conn. SetConnectTimeout (5000);
Conn. SetReadTimeout (20000);
Cost = conn. GetInputStream ();
} catch (MalformedURLException e) {
The Log i. (TAG, "MalformedURLException");
E.p rintStackTrace ();
} catch (Exception e) {
Log. I (TAG, "failed to get input stream ");
E.p rintStackTrace ();
}
FileOutputStream fos = null;
Try {
Fos = new FileOutputStream (apkFile);
} catch (FileNotFoundException e) {
Log. I (TAG, "failed to get output stream: new FileOutputStream(apkFile);" );
E.p rintStackTrace ();
}
BufferedInputStream bis = new BufferedInputStream(iStream);
Byte [] buffer = new byte[1024];
Int len.
// gets the total length of the file
Int length = conn. GetContentLength ();
Double rate = 100 / length (double); // Max progress converted to 100
Int total = 0;
Int times = 0; // set the update frequency, frequent operation of the UI thread will cause the system to crash
Try {
Log. I ("threadStatus", "start downloading ");
While (false==interupted && (len = bis. Read (buffer))! = 1) {
Fos. Write (buffer, 0, len);
// gets the length that has been read
Total + = len;
Int p = (int) (total * rate);
The Log i. (" num ", rate + ", "+ +", "total + p).
If (times > = 512 | | p = = 100)
{/ *
This prevents the system from slowing down or even crashing due to frequent notifications.
Very important... * /
The Log i. (" time ", "time");
Times = 0;
The Message MSG = Message. Obtain ();
MSG. What = p;
MHandler. SendMessage (MSG);
}
Times++;
}
Fos. Close ();
The bis. Close ();
Cost. The close ();
If (total = = length)
{
IsFinished = true;
MHandler. SendEmptyMessage (DOWNLOAD_COMPLETE);
Log. I (TAG, "download finished ");
}
Log. I (TAG, "mandatory end of stream ");
/ / mhandler. SendEmptyMessage (4);
} catch (IOException e) {
Log. I (TAG, "exception ends ");
MHandler. SendEmptyMessage (DOWNLOAD_FAIL);
E.p rintStackTrace ();
}
}
The else
{
Log. I (TAG, "external memory card does not exist, download failed!" );
MHandler. SendEmptyMessage (DOWNLOAD_FAIL);
}
}
}
Package com. Example. The test;
The import android. App. Notification;
The import android. App. NotificationManager;
The import android. App. PendingIntent;
The import android. The content. The Context;
The import android. Widget. RemoteViews;
/ * *
* Notification class, which can use either the system's default Notification layout or a custom layout
*
* @ author lz
*
* /
Public class MyNotification {
Public final static int DOWNLOAD_COMPLETE = -2;
Public final static int DOWNLOAD_FAIL = -1;
The Context mContext; //Activity or Service context
Notification Notification; / / notification
NotificationManager nm;
String titleStr; // notification title
String contentStr; // notification content
PendingIntent contentIntent; // action after clicking the notification
Int notificationID; // the unique ID of the notification
Int iconID; // notification bar icon
Long the when = System. CurrentTimeMillis ();
RemoteViews remoteView = null; // custom notification bar view
/ * *
*
* @param context Activity or Service context
* @param contentIntent click on the action after notification
* unique identifier id for @param id notification
* /
Public MyNotification(Context Context,PendingIntent contentIntent,int id) {
// TODO auto-generated constructor stub
MContext = context;
NotificationID = id;
Enclosing contentIntent = contentIntent;
Enclosing the nm = (NotificationManager) mContext. GetSystemService (Context. NOTIFICATION_SERVICE);
}
/ * *
* displays custom notifications
* @param icoId custom view image ID
* @param titleStr notice column title
* @param layoutId custom layout file ID
* /
Public void showCustomizeNotification (int icoId, String titleStr, int layoutId) {
Enclosing titleStr = titleStr;
Notification = new notification (R.d rawable ic_launcher, titleStr, when);
Notification. The flags = notification. FLAG_ONLY_ALERT_ONCE;
Notification. The flags | = notification. FLAG_AUTO_CANCEL;
Notification. The contentIntent = this. ContentIntent;
// 1, create a custom message layout view.xml
// 2, use the RemoteViews method to define the image and text in the program code. Then pass the RemoteViews object to the contentView field
If (remoteView = = null)
{
RemoteView = new RemoteViews (mContext getPackageName (), layoutId);
RemoteView. SetImageViewResource (R.i d.i vNotification icoId);
RemoteView. SetTextViewText (R.i which vTitle titleStr);
RemoteView. SetTextViewText (R.i which vTip, "start download");
RemoteView. SetProgressBar (R.i d.p bNotification, 100, 0, false);
Notification. ContentView = remoteView;
}
Nm. Notify (notificationID, notification);
}
/ * *
* change the value of the progress bar in the custom layout file
* @param p progress value (0~100)
* /
Public void changeProgressStatus (int) p
{
If (notification contentView! = null)
{
If (p = = DOWNLOAD_FAIL)
Notification. ContentView. SetTextViewText (R.i which vTip, "download failed! ");
Else if (p = = 100)
Notification. ContentView. SetTextViewText (R.i which vTip, the download is complete, click "install");
The else
Notification. ContentView. SetTextViewText (R.i which vTip, "progress (%)" + p + ":");
Notification. ContentView. SetProgressBar (R.i d.p bNotification, 100, p, false);
}
Nm. Notify (notificationID, notification);
}
Public void changeContentIntent (PendingIntent intent)
{
Enclosing contentIntent = intent;
Notification. ContentIntent = intent;
}
/ * *
* displays system default format notifications
* @param iconId notification bar iconId
* @param title ext notification bar title
* @param contentStr notification bar content
* /
Public void showDefaultNotification(int iconId,String titleText,String contentStr) {
Enclosing titleStr = titleText;
Enclosing contentStr = contentStr;
Enclosing iconID = iconID;
Notification = new notification ();
Notification. TickerText = titleStr;
Notification. Icon = iconID;
Notification. The flags = notification. FLAG_INSISTENT;
Notification. The flags | = notification. FLAG_AUTO_CANCEL;
Notification. The contentIntent = this. ContentIntent;
// add sound effects
/ / notification. Defaults | = notification. DEFAULT_SOUND;
// add vibration, later learned to add vibration Permission: Virbate Permission
// mnotification. defaults |= notification. DEFAULT_VIBRATE;
// add status flag
//FLAG_AUTO_CANCEL this notice can be cleared by the clear button in the status bar
//FLAG_NO_CLEAR this notification can be cleared by the clear button in the status bar
//FLAG_ONGOING_EVENT notification placed at running
/ / FLAG_INSISTENT notice has been playing music effect
Notification. The flags = notification. FLAG_ONLY_ALERT_ONCE;
ChangeNotificationText (contentStr);
}
/ * *
* change the notification content of the default notification bar
* @ param content
* /
Public void changeNotificationText (String content)
{
Notification. SetLatestEventInfo (mContext titleStr, content, contentIntent);
// set the setLatestEventInfo method, otherwise the App will report an error exception
// NotificationManager mNotificationManager = (NotificationManager) getSystemService(context.notification_service);
// register this notice
// if the notification for the NOTIFICATION_ID already exists, information about the latest notification, such as tickerText, is displayed
Nm. Notify (notificationID, notification);
}
/ * *
* removal notice
* /
Public void removeNotification ()
{
// cancels only the Notification of the current Context
Nm. Cancel (notificationID);
}
}
Package com. Example. The test;
Import the Java. IO. The File;
The import android. App. Notification;
The import android. App. NotificationManager;
The import android. App. PendingIntent;
The import android. App. Service;
The import android. The content. The Context;
The import android. Content. Intent;
The import android.net.Uri;
The import android. OS. The Environment;
The import android. OS. Handler;
The import android. OS. IBinder;
The import android. OS. The Message;
The import android. The provider. Settings. Global;
The import android. Util. Log;
Public class DownloadServices extends Service {
Private final static int DOWNLOAD_COMPLETE = -2;
Private final static int DOWNLOAD_FAIL = -1;
// custom advice bar class
MyNotification MyNotification;
String filePathString; // absolute path to download file (including file name)
// notification bar jumps to Intent
Private Intent updateIntent = null;
Private PendingIntent updatePendingIntent = null;
DownFileThread DownFileThread; // custom file download thread
Private Handler updateHandler = new Handler(){
@ Override
Public void handleMessage(Message MSG) {
The switch (MSG. What) {
Case DOWNLOAD_COMPLETE:
// click to install 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; // ring to remind
MyNotification. ChangeNotificationText (" the download is complete, please click on the install!" );
// stop service
/ / myNotification removeNotification ();
StopSelf ();
Break;
Case DOWNLOAD_FAIL:
// download failed
/ / myNotification changeProgressStatus (DOWNLOAD_FAIL);
MyNotification. ChangeNotificationText (file download failed! "" );
StopSelf ();
Break;
Default: // in download
The Log. I (" service ", "default" + MSG. What);
/ / myNotification changeNotificationText (MSG. What + "%");
MyNotification. ChangeProgressStatus (MSG. What);
}
}
};
Public DownloadServices () {
// TODO auto-generated constructor stub
/ / McOntext = context;
The Log i. (" service ", "DownloadServices1");
}
@ Override
Public void onCreate () {
// TODO auto-generated method stub
The Log i. (" service ", "onCreate");
Super. The onCreate ();
}
@ Override
Public void onDestroy () {
// TODO auto-generated method stub
The 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
The Log i. (" service ", "onStartCommand");
UpdateIntent = new Intent(this, mainactivity.class);
PendingIntent updatePendingIntent = PendingIntent. GetActivity (updateIntent this, 0, 0).
MyNotification = new myNotification (this, updatePendingIntent, 1);
. / / myNotification. ShowDefaultNotification (R.d rawable ic_launcher, "test", "start download");
MyNotification. ShowCustomizeNotification (R.d rawable ic_launcher, download "test", R.l ayout. Notification);
FilePathString = Environment. External.getexternalstoragedirectory (.) getAbsolutePath () + "/ family. Apk";
// start a new thread download. If you use Service to download synchronously, it will cause ANR problems and the Service itself will block
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
The Log i. (" service ", "onStart");
Super. OnStart (intent, startId);
}
@ Override
Public IBinder onBind(Intent arg0) {
// TODO auto-generated method stub
The Log i. (" service ", "onBind");
Return null;
}
}