运用广播机制来完成版本更新模块(详解)


 这段时间做版本升级,做的过程中碰到问题太多了,呵呵,小马写在博客里面,供自己日后复习,也供大家共同学习改进我的代码,有好的建议请直接指点小马,感激不尽,下面直接来看代码吧:

先看下主配置文件:


  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     package="com.xiaoma.www" 
  4.     android:versionCode="20111111" 
  5.     android:versionName="1.0" > 
  6.  
  7.     <uses-sdk android:minSdkVersion="15" /> 
  8.  
  9.     <application 
  10.         android:icon="@drawable/ic_launcher" 
  11.         android:label="@string/app_name" > 
  12.         <activity 
  13.             android:name=".BroadCastUpdateVersionActivity" 
  14.             android:label="@string/app_name" > 
  15.             <intent-filter> 
  16.                 <action android:name="android.intent.action.MAIN" /> 
  17.                 <category android:name="android.intent.category.LAUNCHER" /> 
  18.             </intent-filter> 
  19.         </activity> 
  20.          
  21.         <!-- 下载服务注册 --> 
  22.         <service android:name=".DownloadService"></service> 
  23.          
  24.         <!-- XML配置方式实现广播注册 --> 
  25.         <!-- <receiver android:enabled=["true" | "false"] 
  26.           android:exported=["true" | "false"] 
  27.           android:icon="drawable resource" 
  28.           android:label="string resource" 
  29.           android:name="string" 
  30.           android:permission="string" 
  31.           android:process="string" > 
  32.           . . .这些是receiver里面的属性,爽吧?嘿嘿,不懂的朋友们可跟下链接 : 
  33.                http://developer.android.com/guide/topics/manifest/receiver-element.html 
  34.         </receiver> --> 
  35.         <!--   
  36.             <receiver android:name="此处是你写的单独的广播子类,必须是完整路径" > 
  37.                 <intent-filter> 
  38.                     <action android:name="com.xiaoma.comeon"/> 
  39.                 </intent-filter>             
  40.             </receiver> 
  41.         --> 
  42.     </application> 
  43.  
  44. </manifest> 

再看下主控制类:


  1. package com.xiaoma.www; 
  2.  
  3. import android.app.Activity; 
  4. import android.app.AlertDialog; 
  5. import android.app.Dialog; 
  6. import android.content.BroadcastReceiver; 
  7. import android.content.Context; 
  8. import android.content.DialogInterface; 
  9. import android.content.Intent; 
  10. import android.content.IntentFilter; 
  11. import android.content.pm.PackageManager.NameNotFoundException; 
  12. import android.net.Uri; 
  13. import android.os.Bundle; 
  14. import android.view.View; 
  15. import android.view.View.OnClickListener; 
  16. import android.widget.Button; 
  17. import android.widget.Toast; 
  18.  
  19. /**   
  20. * @Title: BroadCastUpdateVersionActivity.java 
  21. * @Package com.xiaoma.www 
  22. * @Description: 运用广播机制来完成版本更新模块 
  23. * @author MZH 
  24. */ 
  25. public class BroadCastUpdateVersionActivity extends Activity { 
  26.      
  27.     private Button checkBtn; 
  28.     private BroadcastUpdateReceiver bur = null ;  
  29.     private static final String BROADCAST_ACTION = "com.xiaoma.comeon"
  30.      
  31.     /** Called when the activity is first created. */ 
  32.     @Override 
  33.     public void onCreate(Bundle savedInstanceState) { 
  34.         super.onCreate(savedInstanceState); 
  35.         setContentView(R.layout.main); 
  36.          
  37.         /** 
  38.          * 此处:注册广播的方式两种,小马顺带讲下 
  39.          * 方式一:XML方式在Manifest配置中注册    请看全局配置文件注册receiver 
  40.          * 方式二:纯代码注册如下,此处需要特别注意的是,如果使用代码注册广播的话,注册必须在发起 
  41.          *      广播之前 ,否则广播无效或报错,还有就是尽量用内部类实现广播时采用这种注册方式 
  42.          */ 
  43.          
  44.         //注册是否有新版本广播    
  45.         registerBroadCast(); 
  46.         init(); 
  47.     } 
  48.      
  49.     /** 
  50.      * 是否有新版本广播注册实现 
  51.      */ 
  52.     private void registerBroadCast(){ 
  53.         //注册之前先得有个BroadCastReceiver的子类 
  54.         bur = new BroadcastUpdateReceiver(); 
  55.         IntentFilter filter = new IntentFilter(); 
  56.         //下面的BROADCAST_ACTION与全局配置中的receiver标签子标签 
  57.         //intentfilter的action的name值是一致的哦 
  58.         filter.addAction(BROADCAST_ACTION); 
  59.         registerReceiver(bur, filter); 
  60.     } 
  61.      
  62.     /** 
  63.      * 内部类实现广播 
  64.     * @Title: BroadCastUpdateVersionActivity.java 
  65.     * @Package com.xiaoma.www 
  66.     * @Description: 接收是否下载完成广播事件 
  67.     * @author MZH 
  68.      */ 
  69.     public class BroadcastUpdateReceiver extends BroadcastReceiver{ 
  70.  
  71.         @Override 
  72.         public void onReceive(Context context, Intent intent) { 
  73.             Bundle bundle = intent.getExtras(); 
  74.             String status = bundle.getString("服务器返回给你的标志位"); 
  75.             if (status.equals("如:success")){ 
  76.                 String urlStr = "file:///"+ bundle.getString("Path"); 
  77.                 //以下这个Intent是指当下载完成后,用新的安装VIEW来提示用户是否安装刚下载好的APK 
  78.                 Intent i = new Intent(Intent.ACTION_VIEW); 
  79.                 //解析设置服务器返回数据类型 
  80.                 intent.setDataAndType(Uri.parse(urlStr),  
  81.                         "application/vnd.android.package-archive"); 
  82.                 startActivity(intent); 
  83.             }else
  84.                 Toast.makeText(BroadCastUpdateVersionActivity.this"下载更新版本失败", Toast.LENGTH_SHORT).show(); 
  85.             } 
  86.  
  87.             BroadCastUpdateVersionActivity.this.finish();  
  88.         } 
  89.     } 
  90.      
  91.     /** 
  92.      * 初始化信息实现 
  93.      */ 
  94.     private void init(){ 
  95.          checkBtn = (Button)findViewById(R.id.checkVersion); 
  96.          checkBtn.setOnClickListener(new OnClickListener() { 
  97.              
  98.             @Override 
  99.             public void onClick(View v) { 
  100.                  
  101.                 /** 
  102.                  * 这里小马讲下在AndroidManifest.xml文件中版本号的一些限制,小马注释写详细些 
  103.                  * 希望大家不要嫌啰嗦,我只希望帮忙大家更多,了解得更透彻 
  104.                  * 首先:http://developer.android.com/guide/topics/manifest/manifest-element.html 
  105.                  * 可双上面的链接中看到如下信息: 
  106.                  *   <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
  107.                       package="string" 
  108.                       android:sharedUserId="string" 
  109.                       android:sharedUserLabel="string resource"  
  110.                       android:versionCode="integer" 
  111.                       android:versionName="string" 
  112.                                             顺便了解下下面这句啦,哈哈,激动,是设置我们的应用默认安装的位置:自动、手机内存、SD卡 
  113.                       android:installLocation=["auto" | "internalOnly" | "preferExternal"] > 
  114.                       . . . 
  115.                       </manifest> 
  116.                  * 跟进版本versionCode与versionNames可查看限制: 
  117.                  * 再次强调一下,看到英文不要怕,不懂了用工具查,提高编程提高英文水平 
  118.                  * versionCode中此句最重要: 
  119.                  *    The value must be set as an integer, such as "100" 
  120.                  * versionName也只看一句: 
  121.                  *    The version number shown to users. 
  122.                  *  
  123.                  */ 
  124.                 try { 
  125.                     //取得当前应用的包 
  126.                     String packageName = getPackageName(); 
  127.                     //根据包名取得当前应用的版本号 
  128.                     int myVersion = getPackageManager().getPackageInfo(packageName, 0).versionCode; 
  129.                      
  130.                     /** 
  131.                      * 取服务器上的新版本文件版本号与当前应用的版本比较,如果当前版本低于服务器时弹出更新提示如下, 
  132.                      * 访问服务器这步小马跳过,因为今天这个试例讲解广播实现版本更新嘛,通常使用webservice访问服务器 
  133.                      * 朋友们可以把访问服务器的代码直接写到这个地方进行版本比对哦 
  134.                      */ 
  135.                     showAlertDialog(); 
  136.                 } catch (NameNotFoundException e) { 
  137.                     e.printStackTrace(); 
  138.                 } 
  139.             } 
  140.         }); 
  141.     } 
  142.      
  143.   //版本更新弹出对话框 
  144.     private void showAlertDialog(){ 
  145.         Dialog dialog = new AlertDialog.Builder(this
  146.           .setTitle("新版本提示"
  147.         .setMessage("发现新版本,是否需要升!"
  148.           .setPositiveButton("确定",new DialogInterface.OnClickListener() { 
  149.               public void onClick(DialogInterface dialog,int whichButton) { 
  150.                       //下载服务控制 
  151.                       downloadService(); 
  152.           }}).setNegativeButton("取消"new DialogInterface.OnClickListener(){ 
  153.             public void onClick(DialogInterface dialog, int which) { 
  154.                  dialog.dismiss(); 
  155.             } 
  156.           }).create(); 
  157.         dialog.show(); 
  158.    } 
  159.      
  160.     private void downloadService(){ 
  161.         String PathName = "从服务器取到的完整的路径如:http://www.google.cn/webhp?source=g_cn/XXX.apk"
  162.         Intent intent = new Intent(); 
  163.         intent.putExtra("URL""访问服务器的URL"); 
  164.         intent.putExtra("Path", PathName); 
  165.         //记得在全局配置中注册DownloadService服务 
  166.         intent.setClass(this, DownloadService.class); 
  167.         /** 
  168.          * 因为是这种方式启动的service,小马就在此插张图,供朋友们理解在DownloadService.class里面 
  169.          * 小马为什么把处理过程写在onStart()中而不是onBind()中。 
  170.          */ 
  171.         startService(intent); 
  172.     } 

贴下Service启动方式的截图:

运用广播机制来完成版本更新模块(详解)

下面来看下后台服务下载的代码:


  1. package com.xiaoma.www; 
  2.  
  3. import java.io.File; 
  4. import java.io.InputStream; 
  5.  
  6. import com.xiaoma.utils.FileUtils; 
  7.  
  8. import android.app.Service; 
  9. import android.content.Intent; 
  10. import android.os.Bundle; 
  11. import android.os.IBinder; 
  12.  
  13.  
  14. /**   
  15. * @Title: DownloadService.java 
  16. * @Package com.xiaoma.www 
  17. * @Description: 启用后台下载新版本控制类 
  18. * @author MZH 
  19. */ 
  20. public class DownloadService extends Service { 
  21.  
  22.     @Override 
  23.     public IBinder onBind(Intent intent) { 
  24.         return null; 
  25.     } 
  26.      
  27.     @Override 
  28.     public void onStart(Intent intent, int startId) { 
  29.         if(intent != null){ 
  30.             String urlStr = intent.getStringExtra("URL"); 
  31.             String fullPathName = intent.getStringExtra("Path"); 
  32.             DownloadThread downloadThread = new DownloadThread(urlStr, fullPathName); 
  33.             Thread thread = new Thread(downloadThread); 
  34.             thread.start(); 
  35.         } 
  36.         super.onStart(intent, startId); 
  37.     } 
  38.  
  39.     class DownloadThread implements Runnable{ 
  40.         private String mUrl = null
  41.         private String mPathName = null
  42.          
  43.         public DownloadThread(String aUrl, String PathName){ 
  44.             mUrl = aUrl
  45.             mPathName = PathName; 
  46.         } 
  47.          
  48.         @Override 
  49.         public void run() { 
  50.             int result = downFile(mUrl, mPathName); 
  51.             Intent intent = new Intent("com.xiaoma.comeon"); 
  52.             Bundle bundle = new Bundle(); 
  53.             if( -1 == result){    
  54.                 bundle.putString("Status", "error"); 
  55.             }else { 
  56.                 bundle.putString("Status", "success"); 
  57.                 bundle.putString("Path", mPathName); 
  58.             } 
  59.             intent.putExtras(bundle); 
  60.             sendBroadcast(intent); 
  61.         } 
  62.     } 
  63.      
  64.     public int downFile(String urlStr, String fullPathName){ 
  65.         InputStream inputStream = null
  66.         try{ 
  67.             File file = new File(fullPathName); 
  68.             if (file.exists()){ 
  69.                 return 1; 
  70.             }else{ 
  71.                 FileUtils fu = new FileUtils(); 
  72.                 inputStream = fu.getStreamFromUrl(urlStr); 
  73.                 File f = fu.writeInput(fullPathName, inputStream); 
  74.                 if (f == null){ 
  75.                     return -1; 
  76.                 } 
  77.             } 
  78.         }catch(Exception e){ 
  79.             e.printStackTrace(); 
  80.             return -1; 
  81.         }finally{ 
  82.             try{ 
  83.                 inputStream.close(); 
  84.             } catch (Exception e) { 
  85.                 e.printStackTrace(); 
  86.             } 
  87.         } 
  88.         return 0; 
  89.     } 
  90.  

以下是后台下载时用到的文件工具类代码:

 


  1. package com.xiaoma.utils; 
  2.  
  3. import java.io.File; 
  4. import java.io.FileOutputStream; 
  5. import java.io.IOException; 
  6. import java.io.InputStream; 
  7. import java.io.OutputStream; 
  8. import java.net.HttpURLConnection; 
  9. import java.net.MalformedURLException; 
  10. import java.net.URL; 
  11.  
  12. /** 
  13.  * @Title: DeleteFile.java 
  14.  * @Description: 文件、文件夹操作类 
  15.  * @author MZH 
  16.  */ 
  17. public class FileUtils{ 
  18.     private URL url = null ; 
  19.     public FileUtils(){ 
  20.     } 
  21.      
  22.     public File writeInput(String PathName, InputStream input){ 
  23.         File file = null
  24.         OutputStream output = null
  25.         try{ 
  26.             file = new File( PathName ); 
  27.             if (file.exists()) 
  28.                 return file; 
  29.                  
  30.             int length = 0
  31.             output = new FileOutputStream(file); 
  32.             byte buffer[] = new byte[1024]; 
  33.             while((length = input.read(buffer)) > 0){ 
  34.                 output.write(buffer, 0, length); 
  35.             } 
  36.              
  37.         }catch(Exception e){ 
  38.             e.printStackTrace(); 
  39.         }finally{ 
  40.             try{ 
  41.                 output.close(); 
  42.             }catch(Exception e){ 
  43.                 e.printStackTrace(); 
  44.             } 
  45.         } 
  46.          
  47.         return file; 
  48.     } 
  49.      
  50.     public InputStream getStreamFromUrl(String urlStr) 
  51.             throws MalformedURLException, IOException { 
  52.         url = new URL(urlStr); 
  53.         HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); 
  54.         InputStream inputStream = urlConn.getInputStream(); 
  55.         return inputStream; 
  56.     } 

大体的就是以上讲的这样啦,如果有朋友有好的建议想法,可直接指点小马,小马虚心请教,感谢大家同小马交流,共同提高进步,谢谢啦,附近有带源码,有需要的朋友可直接下载,最好下载前指下小马代码的不足,有批评才有进步,谢谢

 

 

附件:http://down.51cto.com/data/2359700





     本文转自华华世界 51CTO博客,原文链接:http://blog.51cto.com/mzh3344258/766686,如需转载请自行联系原作者





上一篇:为什么Web 设计会‘死’?


下一篇:Apache Oozie Coordinator 作业自定义配置定时任务