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

先看下主配置文件:

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.xiaoma.www" 
    android:versionCode="20111111" 
    android:versionName="1.0" > 
 
    <uses-sdk android:minSdkVersion="15" /> 
 
    <application 
        android:icon="@drawable/ic_launcher" 
        android:label="@string/app_name" > 
        <activity 
            android:name=".BroadCastUpdateVersionActivity" 
            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=".DownloadService"></service> 
         
        <!-- XML配置方式实现广播注册 --> 
        <!-- <receiver android:enabled=["true" | "false"] 
          android:exported=["true" | "false"] 
          android:icon="drawable resource" 
          android:label="string resource" 
          android:name="string" 
          android:permission="string" 
          android:process="string" > 
          . . .这些是receiver里面的属性,爽吧?嘿嘿,不懂的朋友们可跟下链接 : 
               http://developer.android.com/guide/topics/manifest/receiver-element.html 
        </receiver> --> 
        <!--   
            <receiver android:name="此处是你写的单独的广播子类,必须是完整路径" > 
                <intent-filter> 
                    <action android:name="com.xiaoma.comeon"/> 
                </intent-filter>             
            </receiver> 
        --> 
    </application> 
 
</manifest>

再看下主控制类:

package com.xiaoma.www; 
 
import android.app.Activity; 
import android.app.AlertDialog; 
import android.app.Dialog; 
import android.content.BroadcastReceiver; 
import android.content.Context; 
import android.content.DialogInterface; 
import android.content.Intent; 
import android.content.IntentFilter; 
import android.content.pm.PackageManager.NameNotFoundException; 
import android.net.Uri; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.Toast; 
 
/**   
* @Title: BroadCastUpdateVersionActivity.java 
* @Package com.xiaoma.www 
* @Description: 运用广播机制来完成版本更新模块 
* @author MZH 
*/ 
public class BroadCastUpdateVersionActivity extends Activity { 
     
    private Button checkBtn; 
    private BroadcastUpdateReceiver bur = null ;  
    private static final String BROADCAST_ACTION = "com.xiaoma.comeon"; 
     
    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
         
        /** 
         * 此处:注册广播的方式两种,小马顺带讲下 
         * 方式一:XML方式在Manifest配置中注册    请看全局配置文件注册receiver 
         * 方式二:纯代码注册如下,此处需要特别注意的是,如果使用代码注册广播的话,注册必须在发起 
         *      广播之前 ,否则广播无效或报错,还有就是尽量用内部类实现广播时采用这种注册方式 
         */ 
         
        //注册是否有新版本广播    
        registerBroadCast(); 
        init(); 
    } 
     
    /** 
     * 是否有新版本广播注册实现 
     */ 
    private void registerBroadCast(){ 
        //注册之前先得有个BroadCastReceiver的子类 
        bur = new BroadcastUpdateReceiver(); 
        IntentFilter filter = new IntentFilter(); 
        //下面的BROADCAST_ACTION与全局配置中的receiver标签子标签 
        //intentfilter的action的name值是一致的哦 
        filter.addAction(BROADCAST_ACTION); 
        registerReceiver(bur, filter); 
    } 
     
    /** 
     * 内部类实现广播 
    * @Title: BroadCastUpdateVersionActivity.java 
    * @Package com.xiaoma.www 
    * @Description: 接收是否下载完成广播事件 
    * @author MZH 
     */ 
    public class BroadcastUpdateReceiver extends BroadcastReceiver{ 
 
        @Override 
        public void onReceive(Context context, Intent intent) { 
            Bundle bundle = intent.getExtras(); 
            String status = bundle.getString("服务器返回给你的标志位"); 
            if (status.equals("如:success")){ 
                String urlStr = "file:///"+ bundle.getString("Path"); 
                //以下这个Intent是指当下载完成后,用新的安装VIEW来提示用户是否安装刚下载好的APK 
                Intent i = new Intent(Intent.ACTION_VIEW); 
                //解析设置服务器返回数据类型 
                intent.setDataAndType(Uri.parse(urlStr),  
                        "application/vnd.android.package-archive"); 
                startActivity(intent); 
            }else{ 
                Toast.makeText(BroadCastUpdateVersionActivity.this, "下载更新版本失败", Toast.LENGTH_SHORT).show(); 
            } 
 
            BroadCastUpdateVersionActivity.this.finish();  
        } 
    } 
     
    /** 
     * 初始化信息实现 
     */ 
    private void init(){ 
         checkBtn = (Button)findViewById(R.id.checkVersion); 
         checkBtn.setOnClickListener(new OnClickListener() { 
             
            @Override 
            public void onClick(View v) { 
                 
                /** 
                 * 这里小马讲下在AndroidManifest.xml文件中版本号的一些限制,小马注释写详细些 
                 * 希望大家不要嫌啰嗦,我只希望帮忙大家更多,了解得更透彻 
                 * 首先:http://developer.android.com/guide/topics/manifest/manifest-element.html 
                 * 可双上面的链接中看到如下信息: 
                 *   <manifest xmlns:android="http://schemas.android.com/apk/res/android" 
                      package="string" 
                      android:sharedUserId="string" 
                      android:sharedUserLabel="string resource"  
                      android:versionCode="integer" 
                      android:versionName="string" 
                                            顺便了解下下面这句啦,哈哈,激动,是设置我们的应用默认安装的位置:自动、手机内存、SD卡 
                      android:installLocation=["auto" | "internalOnly" | "preferExternal"] > 
                      . . . 
                      </manifest> 
                 * 跟进版本versionCode与versionNames可查看限制: 
                 * 再次强调一下,看到英文不要怕,不懂了用工具查,提高编程提高英文水平 
                 * versionCode中此句最重要: 
                 *    The value must be set as an integer, such as "100" 
                 * versionName也只看一句: 
                 *    The version number shown to users. 
                 *  
                 */ 
                try { 
                    //取得当前应用的包 
                    String packageName = getPackageName(); 
                    //根据包名取得当前应用的版本号 
                    int myVersion = getPackageManager().getPackageInfo(packageName, 0).versionCode; 
                     
                    /** 
                     * 取服务器上的新版本文件版本号与当前应用的版本比较,如果当前版本低于服务器时弹出更新提示如下, 
                     * 访问服务器这步小马跳过,因为今天这个试例讲解广播实现版本更新嘛,通常使用webservice访问服务器 
                     * 朋友们可以把访问服务器的代码直接写到这个地方进行版本比对哦 
                     */ 
                    showAlertDialog(); 
                } catch (NameNotFoundException e) { 
                    e.printStackTrace(); 
                } 
            } 
        }); 
    } 
     
  //版本更新弹出对话框 
    private void showAlertDialog(){ 
        Dialog dialog = new AlertDialog.Builder(this) 
          .setTitle("新版本提示") 
        .setMessage("发现新版本,是否需要升!") 
          .setPositiveButton("确定",new DialogInterface.OnClickListener() { 
              public void onClick(DialogInterface dialog,int whichButton) { 
                      //下载服务控制 
                      downloadService(); 
          }}).setNegativeButton("取消", new DialogInterface.OnClickListener(){ 
            public void onClick(DialogInterface dialog, int which) { 
                 dialog.dismiss(); 
            } 
          }).create(); 
        dialog.show(); 
   } 
     
    private void downloadService(){ 
        String PathName = "从服务器取到的完整的路径如:http://www.google.cn/webhp?source=g_cn/XXX.apk"; 
        Intent intent = new Intent(); 
        intent.putExtra("URL", "访问服务器的URL"); 
        intent.putExtra("Path", PathName); 
        //记得在全局配置中注册DownloadService服务 
        intent.setClass(this, DownloadService.class); 
        /** 
         * 因为是这种方式启动的service,小马就在此插张图,供朋友们理解在DownloadService.class里面 
         * 小马为什么把处理过程写在onStart()中而不是onBind()中。 
         */ 
        startService(intent); 
    } 
}

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

package com.xiaoma.www; 
 
import java.io.File; 
import java.io.InputStream; 
 
import com.xiaoma.utils.FileUtils; 
 
import android.app.Service; 
import android.content.Intent; 
import android.os.Bundle; 
import android.os.IBinder; 
 
 
/**   
* @Title: DownloadService.java 
* @Package com.xiaoma.www 
* @Description: 启用后台下载新版本控制类 
* @author MZH 
*/ 
public class DownloadService extends Service { 
 
    @Override 
    public IBinder onBind(Intent intent) { 
        return null; 
    } 
     
    @Override 
    public void onStart(Intent intent, int startId) { 
        if(intent != null){ 
            String urlStr = intent.getStringExtra("URL"); 
            String fullPathName = intent.getStringExtra("Path"); 
            DownloadThread downloadThread = new DownloadThread(urlStr, fullPathName); 
            Thread thread = new Thread(downloadThread); 
            thread.start(); 
        } 
        super.onStart(intent, startId); 
    } 
 
    class DownloadThread implements Runnable{ 
        private String mUrl = null; 
        private String mPathName = null; 
         
        public DownloadThread(String aUrl, String PathName){ 
            mUrl = aUrl; 
            mPathName = PathName; 
        } 
         
        @Override 
        public void run() { 
            int result = downFile(mUrl, mPathName); 
            Intent intent = new Intent("com.xiaoma.comeon"); 
            Bundle bundle = new Bundle(); 
            if( -1 == result){    
                bundle.putString("Status", "error"); 
            }else { 
                bundle.putString("Status", "success"); 
                bundle.putString("Path", mPathName); 
            } 
            intent.putExtras(bundle); 
            sendBroadcast(intent); 
        } 
    } 
     
    public int downFile(String urlStr, String fullPathName){ 
        InputStream inputStream = null; 
        try{ 
            File file = new File(fullPathName); 
            if (file.exists()){ 
                return 1; 
            }else{ 
                FileUtils fu = new FileUtils(); 
                inputStream = fu.getStreamFromUrl(urlStr); 
                File f = fu.writeInput(fullPathName, inputStream); 
                if (f == null){ 
                    return -1; 
                } 
            } 
        }catch(Exception e){ 
            e.printStackTrace(); 
            return -1; 
        }finally{ 
            try{ 
                inputStream.close(); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
        } 
        return 0; 
    } 
 
}

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

package com.xiaoma.utils; 
 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.HttpURLConnection; 
import java.net.MalformedURLException; 
import java.net.URL; 
 
/** 
 * @Title: DeleteFile.java 
 * @Description: 文件、文件夹操作类 
 * @author MZH 
 */ 
public class FileUtils{ 
    private URL url = null ; 
    public FileUtils(){ 
    } 
     
    public File writeInput(String PathName, InputStream input){ 
        File file = null; 
        OutputStream output = null; 
        try{ 
            file = new File( PathName ); 
            if (file.exists()) 
                return file; 
                 
            int length = 0; 
            output = new FileOutputStream(file); 
            byte buffer[] = new byte[1024]; 
            while((length = input.read(buffer)) > 0){ 
                output.write(buffer, 0, length); 
            } 
             
        }catch(Exception e){ 
            e.printStackTrace(); 
        }finally{ 
            try{ 
                output.close(); 
            }catch(Exception e){ 
                e.printStackTrace(); 
            } 
        } 
         
        return file; 
    } 
     
    public InputStream getStreamFromUrl(String urlStr) 
            throws MalformedURLException, IOException { 
        url = new URL(urlStr); 
        HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); 
        InputStream inputStream = urlConn.getInputStream(); 
        return inputStream; 
    } 
}

相关推荐