Android版本更新(Service下载 Notification进度条)
程序员文章站
2022-05-16 09:06:43
...
功能:版本更新、文件后台下载以及Notification显示进度条。
效果图:
主要代码:
package com.ljp.download; import java.io.File; import android.app.ActivityGroup; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import com.ljp.download.service.AppUpgradeService; import com.ljp.version.R; public class MainActivity extends ActivityGroup { private Button button1; private String mDownloadUrl = "http://gdown.baidu.com/data/wisegame/ba226d3cf2cfc97b/baiduyinyue_4920.apk"; private String apkUpdateMsg = "1.内容1\n2.内容2\n3.内容3"; private Dialog updateVersionDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_main); button1 = (Button) findViewById(R.id.button1); button1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showDialog(); } }); } private void showDialog() { updateVersionDialog = new AlertDialog.Builder(MainActivity.this).setTitle("有新版本需要更新").setMessage(apkUpdateMsg) .setPositiveButton("现在更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { downLoadApk(); } }).setNegativeButton("以后再说", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.dismiss(); } }).create(); updateVersionDialog.show(); } /** * 文件下载 */ private void downLoadApk() { Intent intent = new Intent(MainActivity.this, AppUpgradeService.class); intent.putExtra("mDownloadUrl", mDownloadUrl); startService(intent); updateVersionDialog.dismiss(); } }
package com.ljp.download.service; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RemoteViews; import android.widget.TextView; import android.widget.Toast; import com.ljp.download.DownloadUtils; import com.ljp.download.MainActivity; import com.ljp.version.R; /** * 程序版本更新Service * @author yingjun10627 * */ public class AppUpgradeService extends Service { private NotificationManager mNotificationManager = null; private Notification mNotification = null; private PendingIntent mPendingIntent = null; private String mDownloadUrl; private File destDir = null; private File destFile = null; public static final String downloadPath = "/winner"; public static final int mNotificationId = 111; private static final int DOWNLOAD_FAIL = -1; private static final int DOWNLOAD_SUCCESS = 0; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLOAD_SUCCESS: Toast.makeText(getApplicationContext(), "下载成功", Toast.LENGTH_LONG).show(); install(destFile); mNotificationManager.cancel(mNotificationId); break; case DOWNLOAD_FAIL: Toast.makeText(getApplicationContext(), "下载失败", Toast.LENGTH_LONG).show(); mNotificationManager.cancel(mNotificationId); break; default: break; } } }; @Override public int onStartCommand(Intent intent, int flags, int startId) { if(intent==null){ stopSelf(); return super.onStartCommand(intent, flags, startId); } mDownloadUrl = intent.getStringExtra("mDownloadUrl"); if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { destDir = new File(Environment.getExternalStorageDirectory().getPath() + downloadPath); if (destDir.exists()) { File destFile = new File(destDir.getPath() + "/" + URLEncoder.encode(mDownloadUrl)); if (destFile.exists() && destFile.isFile() && checkApkFile(destFile.getPath())) { install(destFile); stopSelf(); return super.onStartCommand(intent, flags, startId); } } } else { return super.onStartCommand(intent, flags, startId); } mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNotification = new Notification(); Intent completingIntent = new Intent(); completingIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); completingIntent.setClass(getApplicationContext(), AppUpgradeService.class); // 创建Notifcation对象,设置图标,提示文字,策略 mPendingIntent = PendingIntent.getActivity(AppUpgradeService.this, R.string.app_name, completingIntent, PendingIntent.FLAG_UPDATE_CURRENT); mNotification.icon = R.drawable.ic_launcher; mNotification.tickerText = "开始下载"; mNotification.contentIntent = mPendingIntent; mNotification.contentView = new RemoteViews(getPackageName(), R.layout.app_upgrade_notification); mNotification.contentView.setProgressBar(R.id.app_upgrade_progressbar, 100, 0, false); mNotification.contentView.setTextViewText(R.id.app_upgrade_title, "正在下载..."); mNotification.contentView.setTextViewText(R.id.app_upgrade_text, "当前进度:0%"); mNotificationManager.cancel(mNotificationId); mNotificationManager.notify(mNotificationId, mNotification); new AppUpgradeThread().start(); return super.onStartCommand(intent, flags, startId); } /** * 用于监听文件下载 */ private DownloadUtils.DownloadListener downloadListener = new DownloadUtils.DownloadListener() { @Override public void downloading(int progress) { System.out.println(progress); mNotification.contentView.setProgressBar(R.id.app_upgrade_progressbar, 100, progress, false); mNotification.contentView.setTextViewText(R.id.app_upgrade_text, "当前进度:" + progress + "%"); mNotificationManager.notify(mNotificationId, mNotification); } @Override public void downloaded() { mNotification.contentView.setViewVisibility(R.id.app_upgrade_progressbar, View.GONE); mNotification.defaults = Notification.DEFAULT_SOUND; mNotification.contentIntent = mPendingIntent; mNotification.contentView.setTextViewText(R.id.app_upgrade_title, "下载完成"); mNotificationManager.notify(mNotificationId, mNotification); if (destFile.exists() && destFile.isFile() && checkApkFile(destFile.getPath())) { Message msg = mHandler.obtainMessage(); msg.what = DOWNLOAD_SUCCESS; mHandler.sendMessage(msg); } mNotificationManager.cancel(mNotificationId); } }; /** * 用于文件下载线程 * @author yingjun10627 * */ class AppUpgradeThread extends Thread { @Override public void run() { if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { if (destDir == null) { destDir = new File(Environment.getExternalStorageDirectory().getPath() + downloadPath); } if (destDir.exists() || destDir.mkdirs()) { destFile = new File(destDir.getPath() + "/" + URLEncoder.encode(mDownloadUrl)); if (destFile.exists() && destFile.isFile() && checkApkFile(destFile.getPath())) { install(destFile); } else { try { DownloadUtils.download(mDownloadUrl, destFile, false, downloadListener); } catch (Exception e) { Message msg = mHandler.obtainMessage(); msg.what = DOWNLOAD_FAIL; mHandler.sendMessage(msg); e.printStackTrace(); } } } } stopSelf(); } } /** * apk文件安装 * * @param apkFile */ public void install(File apkFile) { Uri uri = Uri.fromFile(apkFile); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(uri, "application/vnd.android.package-archive"); startActivity(intent); } /** * 判断文件是否完整 * * @param apkFilePath * @return */ public boolean checkApkFile(String apkFilePath) { boolean result = false; try { PackageManager pManager = getPackageManager(); PackageInfo pInfo = pManager.getPackageArchiveInfo(apkFilePath, PackageManager.GET_ACTIVITIES); if (pInfo == null) { result = false; } else { result = true; } } catch (Exception e) { result = false; e.printStackTrace(); } return result; } @Override public IBinder onBind(Intent intent) { return null; } }
package com.ljp.download; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.zip.GZIPInputStream; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; public class DownloadUtils { private static final int CONNECT_TIMEOUT = 10000; private static final int DATA_TIMEOUT = 40000; private final static int DATA_BUFFER = 8192; public interface DownloadListener { public void downloading(int progress); public void downloaded(); } public static long download(String urlStr, File dest, boolean append, DownloadListener downloadListener) throws Exception { int downloadProgress = 0; long remoteSize = 0; int currentSize = 0; long totalSize = -1; if (!append && dest.exists() && dest.isFile()) { dest.delete(); } if (append && dest.exists() && dest.exists()) { FileInputStream fis = null; try { fis = new FileInputStream(dest); currentSize = fis.available(); } catch (IOException e) { throw e; } finally { if (fis != null) { fis.close(); } } } HttpGet request = new HttpGet(urlStr); if (currentSize > 0) { request.addHeader("RANGE", "bytes=" + currentSize + "-"); } HttpParams params = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(params, CONNECT_TIMEOUT); HttpConnectionParams.setSoTimeout(params, DATA_TIMEOUT); HttpClient httpClient = new DefaultHttpClient(params); InputStream is = null; FileOutputStream os = null; try { HttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { is = response.getEntity().getContent(); remoteSize = response.getEntity().getContentLength(); Header contentEncoding = response.getFirstHeader("Content-Encoding"); if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { is = new GZIPInputStream(is); } os = new FileOutputStream(dest, append); byte buffer[] = new byte[DATA_BUFFER]; int readSize = 0; int temp=0; while ((readSize = is.read(buffer)) > 0) { os.write(buffer, 0, readSize); os.flush(); totalSize += readSize; if (downloadListener != null) { downloadProgress = (int) (totalSize * 100 / remoteSize); if(downloadProgress>=temp){ temp++; downloadListener.downloading(downloadProgress); } } } if (totalSize < 0) { totalSize = 0; } } } finally { if (os != null) { os.close(); } if (is != null) { is.close(); } } if (totalSize < 0) { throw new Exception("Download file fail: " + urlStr); } if (downloadListener != null) { downloadListener.downloaded(); } return totalSize; } }
Service启动方式说明:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。