使用Rertrofit+Rxjava实现Android版本更新功能

使用Retrofit+Rxjava实现版本更新的功能

效果图

               


实现思路:

(一)从服务器上下载数据,得到版本号,与手机中app的版本号进行对比,如果服务器版本号大于当前应用的版本号,则提示,下载更新(因为无法对外提供服务器数据,因此 本文只提供下载apk的方法,判断是否更新的方法,根据服务器传递的数据,自行加载判断,获取当前手机的版本号方法,会提供。)

(二)下载apk,并且监听下载的进度,通过自定义的AlertDialog实现进度的展示

(三)下载完成,进行自定安装

具体实现:

I、得到当前手机应用的版本号

我们可以在AndroidManifest.xml中设置程序的版本号等,如Android:versionName="1.0",那如果想在代码中获取这个版本号呢,可以用如下方法(这些修改版本号时只需要修改AndroidManifest.xml中的设置,不用修改代码了):

  1. /** 
  2.  * 返回当前程序版本名 
  3.  */  
  4. public static String getAppVersionName(Context context) {  
  5.     String versionName = "";  
  6.     try {  
  7.         // ---get the package info---  
  8.         PackageManager pm = context.getPackageManager();  
  9.         PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);  
  10.         versionName = pi.versionName;  
  11.         versioncode = pi.versionCode;
  12.         if (versionName == null || versionName.length() <= 0) {  
  13.             return "";  
  14.         }  
  15.     } catch (Exception e) {  
  16.         Log.e("VersionInfo""Exception", e);  
  17.     }  
  18.     return versionName;  
  19. }
  20.  
  21.  获取当前应用的版本号:
  22. private String getVersionName() throws Exception  {         

     // 获取packagemanager的实例  

            PackageManager packageManager = getPackageManager();  

           // getPackageName()是你当前类的包名,0代表是获取版本信息  、

         PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(),0);  

            String version = packInfo.versionName;  

           return version;  }  



II、从服务器得到版本号getServerVersion()。。。(由于保密原因该方法无法提供,比较简单,自己可以根据自己项目的接口,下载得到,在此不再赘述)

III、自定义Dialog,用于显示下载的进度条。

Android SDK已经提供有进度条组件ProgressDialog组件,但用的时候我们会发现可能风格与我们应用的整体风格不太搭配,而且ProgressDialog的可定制性也不太强,这时就需要我们自定义实现一个ProgressDialog。
通过看源码我们发现,ProgressDialog继承自Alertdialog,有一个ProgressBar和两个TextView组成的,通过对ProgressDialog的源码进行改进就可以实现一个自定义的ProgressDialog。

1、效果:

首先看一下自定义CommonProgressDialog和原生ProgressDialog的对比:

2、代码aa.xml 布局文件:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="460px"
        android:gravity="center"
        android:layout_gravity="center"
        android:orientation="vertical"
        android:background="@mipmap/bgdialog">
        <TextView
            android:id="@+id/progress_message"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="44px"
            android:layout_marginTop="113px"
            android:layout_gravity="center_horizontal"
            android:textColor="#ffffff"
            />
        <ProgressBar
            android:id="@+id/progress"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="712px"
            android:layout_height="30px"
            android:layout_marginTop="100px"
            android:layout_gravity="center_horizontal"
            android:layout_centerHorizontal="true"
            android:progressDrawable="@drawable/bb"
            />

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
            <TextView
                android:id="@+id/progress_percent"
                android:layout_width="80px"
                android:layout_height="wrap_content"
                android:textSize="30px"
                android:layout_marginLeft="280px"
                android:gravity="center_horizontal"
                android:textColor="#ffffff"
                />
            <TextView
                android:id="@+id/progress_number"
                android:layout_width="250px"
                android:layout_height="wrap_content"
                android:layout_marginLeft="120px"
                android:textSize="30px"
                android:gravity="center_horizontal"
                android:textColor="#ffffff"
                />
        </LinearLayout>
        <Button
            android:id="@+id/btn_cancle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="取消下载 "
            />
    </LinearLayout>
</FrameLayout>
2 、bb.xml Progressbar进度条图片和背景图片设置(主要设置了进度条的形状(圆角),以及进度显色的颜色)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">

              <shape>

                 <corners android:radius="5dip" />

                <gradient
                    android:endColor="#ddd"
                      android:startColor="#ddd" />
              </shape>
         </item>
      <item android:id="@android:id/progress">

           <clip>

               <shape>

                   <corners android:radius="5dip" />

                    <gradient
                        android:endColor="#ddd"
                       android:startColor="#80ff0000" />
              </shape>
          </clip>
      </item>

</layer-list>
3、CustomerDialog.java类:
package org.jokar.download_test.utils;

import android.app.AlertDialog;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.RequiresApi;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.StyleSpan;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import org.jokar.download_test.R;

import java.text.NumberFormat;
/**
 * Created by Administrator on 2016/12/8.
 */

public class CustomerDialog extends AlertDialog {
    private ProgressBar mProgress;
    private TextView mProgressNumber;
    private TextView mProgressPercent;
    private TextView mProgressMessage;
    private Handler mViewUpdateHandler;
    private int mMax;
    private CharSequence mMessage;
    private boolean mHasStarted;
    private int mProgressVal;
    private Button btn_cancle;

    private String TAG="CommonProgressDialog";
    private String mProgressNumberFormat;
    private NumberFormat mProgressPercentFormat;

    public void setBonClickListenre(BonClickListenre bonClickListenre) {
        this.bonClickListenre = bonClickListenre;
    }

    private BonClickListenre bonClickListenre;
    @RequiresApi(api = Build.VERSION_CODES.N)
    public CustomerDialog(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        initFormats();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.aa);
        mProgress=(ProgressBar) findViewById(R.id.progress);
        mProgressNumber=(TextView) findViewById(R.id.progress_number);
        mProgressPercent=(TextView) findViewById(R.id.progress_percent);
        mProgressMessage=(TextView) findViewById(R.id.progress_message);
        btn_cancle= (Button) findViewById(R.id.btn_cancle);
        btn_cancle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                bonClickListenre.BBonClick(view);
            }
        });

        //      LayoutInflater inflater = LayoutInflater.from(getContext());
        mViewUpdateHandler = new Handler() {



            @RequiresApi(api = Build.VERSION_CODES.N)
            @Override
            public void handleMessage(Message msg) {
                // TODO Auto-generated method stub
                super.handleMessage(msg);
                int progress = mProgress.getProgress();
                int max = mProgress.getMax();
                double dProgress = (double)progress/(double)(1024 * 1024);
                double dMax = (double)max/(double)(1024 * 1024);
                if (mProgressNumberFormat != null) {
                    String format = mProgressNumberFormat;
                    mProgressNumber.setText(String.format(format, dProgress, dMax));
                } else {
                    mProgressNumber.setText("");
                }
                if (mProgressPercentFormat != null) {
                    double percent = (double) progress / (double) max;
                    SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent));
                    tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD),
                            0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    mProgressPercent.setText(tmp);
                } else {
                    mProgressPercent.setText("");
                }
            }

        };
        if (mMessage != null) {
            setMessage(mMessage);
        }
        if (mMax > 0) {
            setMax(mMax);
        }
        if (mProgressVal > 0) {
            setProgress(mProgressVal);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void initFormats() {
        mProgressNumberFormat = "%1.2fM/%2.2fM";
        mProgressPercentFormat = NumberFormat.getPercentInstance();
        mProgressPercentFormat.setMaximumFractionDigits(0);
    }
    private void onProgressChanged() {
        mViewUpdateHandler.sendEmptyMessage(0);


    }
    public void setProgressStyle(int style) {
        //mProgressStyle = style;
    }
    public int getMax() {
        if (mProgress != null) {
            return mProgress.getMax();
        }
        return mMax;
    }
    public void setMax(int max) {
        if (mProgress != null) {
            mProgress.setMax(max);
            onProgressChanged();
        } else {
            mMax = max;
        }
    }
    public void setIndeterminate(boolean indeterminate) {
        if (mProgress != null) {
            mProgress.setIndeterminate(indeterminate);
        }
        //      else {
        //            mIndeterminate = indeterminate;
        //        }
    }
    public void setProgress(int value) {
        if (mHasStarted) {
            mProgress.setProgress(value);
            onProgressChanged();
        } else {
            mProgressVal = value;
        }
    }


    @Override
    public void setMessage(CharSequence message) {
        // TODO Auto-generated method stub
        //super.setMessage(message);
        if(mProgressMessage!=null){
            mProgressMessage.setText(message);
        }
        else{
            mMessage = message;
        }
    }


    public  interface BonClickListenre{
        public void BBonClick(View view);
    }
    @Override
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();
        mHasStarted = true;
    }


    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();
        mHasStarted = false;
    }
}
IV:下载apk,并且监听进度(关键步骤)
(1):增加下载进度监听
    
public class DownloadProgressInterceptor implements Interceptor {

    private DownloadProgressListener listener;

    public DownloadProgressInterceptor(DownloadProgressListener listener) {
        this.listener = listener;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Response originalResponse = chain.proceed(chain.request());

        return originalResponse.newBuilder()
                .body(new DownloadProgressResponseBody(originalResponse.body(), listener))
                .build();
    }
}
ii:
/**
 * 下载进度listener
 * Created by JokAr on 16/5/11.
 */
public interface DownloadProgressListener {
    void update(long bytesRead, long contentLength, boolean done);
}
iii:
/**
 * ResponseBody for download
 * Created by JokAr on 16/5/11.
 */
public class DownloadProgressResponseBody extends ResponseBody {

    private ResponseBody responseBody;
    private DownloadProgressListener progressListener;
    private BufferedSource bufferedSource;

    public DownloadProgressResponseBody(ResponseBody responseBody,
                                        DownloadProgressListener progressListener) {
        this.responseBody = responseBody;
        this.progressListener = progressListener;
    }

    @Override
    public MediaType contentType() {
        return responseBody.contentType();
    }

    @Override
    public long contentLength() {
        return responseBody.contentLength();
    }

    @Override
    public BufferedSource source() {
        if (bufferedSource == null) {
            bufferedSource = Okio.buffer(source(responseBody.source()));
        }
        return bufferedSource;
    }

    private Source source(Source source) {
        return new ForwardingSource(source) {
            long totalBytesRead = 0L;

            @Override
            public long read(Buffer sink, long byteCount) throws IOException {
                long bytesRead = super.read(sink, byteCount);
                // read() returns the number of bytes read, or -1 if this source is exhausted.
                totalBytesRead += bytesRead != -1 ? bytesRead : 0;

                if (null != progressListener) {
                    progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                }
                return bytesRead;
            }
        };

    }
}
(2) 创建下载进度的元素类:
/**
 * Created by JokAr on 16/7/5.
 */
public class Download implements Parcelable {

    private int progress;
    private int  currentFileSize;
    private int  totalFileSize;

    public int getProgress() {
        return progress;
    }

    public void setProgress(int progress) {
        this.progress = progress;
    }

    public int  getCurrentFileSize() {
        return currentFileSize;
    }

    public void setCurrentFileSize(int currentFileSize) {
        this.currentFileSize = currentFileSize;
    }

    public int getTotalFileSize() {
        return totalFileSize;
    }

    public void setTotalFileSize(int totalFileSize) {
        this.totalFileSize = totalFileSize;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.progress);
        dest.writeLong(this.currentFileSize);
        dest.writeLong(this.totalFileSize);
    }

    public Download() {
    }

    protected Download(Parcel in) {
        this.progress = in.readInt();
        this.currentFileSize = (int) in.readLong();
        this.totalFileSize = (int) in.readLong();
    }

    public static final Parcelable.Creator<Download> CREATOR = new Parcelable.Creator<Download>() {
        @Override
        public Download createFromParcel(Parcel source) {
            return new Download(source);
        }

        @Override
        public Download[] newArray(int size) {
            return new Download[size];
        }
    };
}
(3)下载文件网络接口:注:这里@Url是传入完整的的下载URL;不用截取
/**
 * Created by JokAr on 16/7/5.
 */
public interface DownloadService {


    @Streaming
    @GET
    Observable<ResponseBody> download(@Url String url);
}
/**
 * Created by JokAr on 16/7/5.
 */
public class DownloadAPI {
    private static final String TAG = "DownloadAPI";
    private static final int DEFAULT_TIMEOUT = 15;
    public Retrofit retrofit;


    public DownloadAPI(String url, DownloadProgressListener listener) {

        DownloadProgressInterceptor interceptor = new DownloadProgressInterceptor(listener);

        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .retryOnConnectionFailure(true)
                .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                .build();


        retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .client(client)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();
    }

    public void downloadAPK(@NonNull String url, final File file, Subscriber subscriber) {
        Log.d(TAG, "downloadAPK: " + url);

        retrofit.create(DownloadService.class)
                .download(url)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .map(new Func1<ResponseBody, InputStream>() {
                    @Override
                    public InputStream call(ResponseBody responseBody) {
                        return responseBody.byteStream();
                    }
                })
                .observeOn(Schedulers.computation())
                .doOnNext(new Action1<InputStream>() {
                    @Override
                    public void call(InputStream inputStream) {
                        try {
                            FileUtils.writeFile(inputStream, file);
                        } catch (IOException e) {
                            e.printStackTrace();

                        }
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }


}
(5)然后就是调用了: 
 该网络是在service里完成的
/**
 * Created by JokAr on 16/7/5.
 */
public class DownloadService extends IntentService {
    private static final String TAG = "DownloadService";

    private NotificationCompat.Builder notificationBuilder;
    private NotificationManager notificationManager;

    int downloadCount = 0;

   // private String apkUrl = "http://download.fir.im/v2/app/install/5818acbcca87a836f50014af?download_token=a01301d7f6f8f4957643c3fcfe5ba6ff";
    private  String apkUrl="http://123.57.221.150/guquanguanjia_v1.2.apk";
    public DownloadService() {
        super("DownloadService");
    }

    private File outputFile;

    @Override
    protected void onHandleIntent(Intent intent) {
       notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationBuilder = new NotificationCompat.Builder(this)
                .setContentTitle("Download")
                .setContentText("Downloading File")
                .setAutoCancel(true);

        notificationManager.notify(0, notificationBuilder.build());

        download();
    }

    private void download() {
        DownloadProgressListener listener = new DownloadProgressListener() {
            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                //不频繁发送通知,防止通知栏下拉卡顿
                int progress = (int) ((bytesRead * 100) / contentLength);
                if ((downloadCount == 0) || progress > downloadCount) {
                    Download download = new Download();
                    download.setTotalFileSize((int) contentLength);
                    download.setCurrentFileSize((int) bytesRead);
                    download.setProgress(progress);

                   sendNotification(download);
                }
            }
        };
        outputFile = new File(Environment.getExternalStoragePublicDirectory
                (Environment.DIRECTORY_DOWNLOADS), "file.apk");

        if (outputFile.exists()) {
            outputFile.delete();
        }


        String baseUrl = StringUtils.getHostName(apkUrl);

        new DownloadAPI(baseUrl, listener).downloadAPK(apkUrl, outputFile, new Subscriber() {
            @Override
            public void onCompleted() {
                downloadCompleted();
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
                downloadCompleted();
                Log.e(TAG, "onError: " + e.getMessage());
            }

            @Override
            public void onNext(Object o) {

            }
        });
    }

    private void downloadCompleted() {
        Download download = new Download();
        download.setProgress(100);
        sendIntent(download);

      notificationManager.cancel(0);
        notificationBuilder.setProgress(0, 0, false);
        notificationBuilder.setContentText("File Downloaded");
        notificationManager.notify(0, notificationBuilder.build());

        //安装apk
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
        startActivity(intent);
    }

   private void sendNotification(Download download) {

        sendIntent(download);
        notificationBuilder.setProgress(100, download.getProgress(), false);
        notificationBuilder.setContentText(
                StringUtils.getDataSize(download.getCurrentFileSize()) + "/" +
                        StringUtils.getDataSize(download.getTotalFileSize()));
        notificationManager.notify(0, notificationBuilder.build());
    }

    private void sendIntent(Download download) {

        Intent intent = new Intent(MainActivity.MESSAGE_PROGRESS);
        intent.putExtra("download", download);
        LocalBroadcastManager.getInstance(DownloadService.this).sendBroadcast(intent);
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        notificationManager.cancel(0);
    }
}
(6)MainActivity.Class类
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    public static final String MESSAGE_PROGRESS = "message_progress";
    private LocalBroadcastManager bManager;
    private CustomerDialog mDialog;
    Intent intent;

    private AppCompatButton btn_download;
    private ProgressBar progress;
    private TextView progress_text;
    private  Boolean flag=false;

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @RequiresApi(api = Build.VERSION_CODES.N)
        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent.getAction().equals(MESSAGE_PROGRESS)) {

                Download download = intent.getParcelableExtra("download");
                if (download.getProgress() == 100) {
                    if (mDialog.isShowing())
                    {
                        mDialog.setMessage("下载完成");
                        mDialog.dismiss();
                    }
                    flag=false;

                } else {

                    if (mDialog.isShowing()){
                        int  a=StringUtils.getDataSize((int) download.getCurrentFileSize());
                        int  b=StringUtils.getDataSize((int) download.getTotalFileSize());
                        mDialog.setMax(b);
                        mDialog.setProgress(a);
                    }
                }
            }
        }
    };


    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_download = (AppCompatButton) findViewById(R.id.btn_download);
        progress = (ProgressBar) findViewById(R.id.progress);
        progress_text = (TextView) findViewById(R.id.progress_text);
        mDialog = new CustomerDialog(MainActivity.this);

        registerReceiver();

        btn_download.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                    intent = new Intent(MainActivity.this, DownloadService.class);
                    startService(intent);
                flag=true;
                mDialog.setMessage("正在下载");
                mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mDialog.setCanceledOnTouchOutside(false);
                mDialog.show();

            }
        });
        mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                if (flag){

                    Toast.makeText(MainActivity.this,"下载任务后台运行中",Toast.LENGTH_LONG).show();

                }
            }
        });
    }

    private void registerReceiver() {

        bManager = LocalBroadcastManager.getInstance(this);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(MESSAGE_PROGRESS);
        bManager.registerReceiver(broadcastReceiver, intentFilter);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //解除注册时,使用注册时的manager解绑
        bManager.unregisterReceiver(broadcastReceiver);
    }
   /* @RequiresApi(api = Build.VERSION_CODES.N)
    public void ShowDialog() {



    }*/

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if(keyCode==KeyEvent.KEYCODE_BACK){
        }
        super.onKeyDown(keyCode,event);
        return true;
    }
}
源码下载链接。http://download.csdn.net/detail/zlb_lover/9706447


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值