Updateアップグレードプロジェクト
36301 ワード
Updateプロセスと問題分析
前言
この間、Updateのアップグレードのメンテナンスプロジェクトをしましたが、いろいろな波乱があって、自分の多くの問題を発見したので、わざわざブログを書いてまとめました.このプロジェクトは最初は同僚が書いたもので、彼は古いUpdateコードで自分でいくつかのクラスを新築して現在のニーズを実現しました.その後、このアップグレードアプリケーションは非常に緊急なプロジェクトでオンラインになり、テスト妹はいくつかのバグを発見し、それから私に転送して解決を維持し、結果として引き継いだ後、表面のいくつかのバグを解決するだけではないことを発見しました.最初は他の人のコードと構想の枠組みの上で小修小補をして、いくつかのバグを解決して、結果はテストして毎回異なる新しい問題が爆発することを測定して、ぼんやりした感じは大きな問題が発生するようです.しかし、その時急いで問題を解決してバージョンを出して、流れの枠組みを徹底的に変えようとしたが、時間が迫ってそうしなかったと思った.最終的な結果はその週、私は毎日家に帰るまで残業して12時だったが、翌日までこのプロジェクトをオンラインにしたバグはまだ終わっていない.最終的な結果、このアプリケーションはオンラインになっていません.私も批判されました.
このプロジェクトが膠着に陥ったとき、私はなぜ今日のような局面をもたらしたのかを反省し始めた.転んだ以上、収穫と進歩があっても転んだ痛みを無駄にしないように、よくまとめるべきだ.
フレームワークフローの概要
このプロジェクトには、強制アップグレード、サイレントアップグレード、オンラインアップグレード、ローカルアップグレードの3つの機能があります.起動後、システムのバックグラウンドでは、ネットワーク接続があれば直接ダウンロードし、インタフェースに入るとダウンロードの進捗状況が表示されることを常に検出する必要があります.強制アップグレード時にバックグラウンドのダウンロードが完了すると、Dialogウィンドウが直接ポップアップされ、キャンセルや終了はできません.最初に書かれたプロセスフレームワークは次のとおりです.
ブートストラップ
handler
ブロードキャスト更新インタフェース
BroadcastReceiver
IntentService
Dialogの強制アップグレード
オンラインActivity
Activityのローカルアップグレード
このように書くと、コードを変更する過程でこれらの問題が発見されました.
その後、次の2週間でコードを再構築し、小さな変更をしました.
1、インタフェースコールバック方式でブロードキャスト通信を代替し、サービスとActivityが交互にBinderで代替する2、InentService 3のサービス代替、リファレンスシステムのソースコードのWifiの状態制御を採用し、1つの状態クラスを定義してオンラインアップグレード全体の検出、クエリー、ダウンロード、アップグレード中のすべての状態変化に対応するUI表示を制御する
現在のプロセスフレームワークは次のとおりです.
ブートストラップ
handler
Binder+インタフェース更新インタフェース
BroadcastReceiver
Service
Dialogの強制アップグレード
オンラインActivity
Activityのローカルアップグレード
IntentServiceとServiceの違いとbindServiceの混合起動方式
私のプロジェクトでは、サービスは起動ブロードキャストでstartServiceを起動し、ActivityはフロントでbindServiceを起動する必要があるので、ハイブリッド起動方式のライフサイクル実行順序をまとめます.
、startService
//@param startId A unique integer representing this specific request to
// start. Use with {@link #stopSelfResult(int)}.
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, " szh onStartCommand-----startId=" + startId);
return super.onStartCommand(intent, flags, startId);
}
D/MainActivity( 2807): szh click start Service---
D/MyService( 2807): szh onCreate-----
D/MyService( 2807): szh onStartCommand-----startId=1,Thread.currentThread().getId()=1
D/MainActivity( 2807): szh click start Service---
D/MyService( 2807): szh onStartCommand-----startId=2,Thread.currentThread().getId()=1
D/MainActivity( 2807): szh click start Service---
D/MyService( 2807): szh onStartCommand-----startId=3,Thread.currentThread().getId()=1
startServiceメソッドを複数回実行すると、onCreate()メソッドが初めて実行され、後でServiceが起動した場合はonStartCommandメソッドのみが実行されることがわかります.しかし、この中にはstartService()のたびに新しいStartIdがあります.ソースコードの注釈を見ると、このStartIdは実際には起動要求の整形データであり、特別な意味はありません.重要なのはthreadIdと同じで、後でサービスがオープンした場合にonStartCommandメソッドしか実行されず、新しいスレッドは開かないことを示しています.
、 bindService
root@JmGO_M61_INT:/ # logcat |grep szh
D/MainActivity( 4302): szh click bind Service---
D/MyService( 4302): szh onCreate-----
D/MyService( 4302): szh on Bind-----,Thread.currentThread().getId()=1
D/MainActivity( 4302): szh onServiceConnected---
D/MainActivity( 4302): szh click bind Service---
D/MainActivity( 4302): szh click bind Service---
logでは、bindServicesを複数回実行すると、onCreate->onBind->onServiceConnectedは、onStartCommandメソッドを実行しないことに注意する必要があります.サービスをバインドした後、bindServicesメソッドを再度呼び出すと、onBindメソッドを複数回呼び出さないことに注意してください.
、 startService bindService
root@JmGO_M61_INT:/ # logcat | grep szh
D/MainActivity( 4544): szh onStart----
D/MainActivity( 4544): szh onResume----
D/MainActivity( 4544): szh click start Service---
D/MyService( 4544): szh onCreate-----
D/MyService( 4544): szh onStartCommand-----startId=1,Thread.currentThread().getId()=1
D/MainActivity( 4544): szh click bind Service---
D/MyService( 4544): szh on Bind-----,Thread.currentThread().getId()=1
D/MainActivity( 4544): szh onServiceConnected---
D/MainActivity( 4544): szh click bind Service---
D/MainActivity( 4544): szh click bind Service---
D/MainActivity( 4544): szh click start Service---
D/MyService( 4544): szh onStartCommand-----startId=2,Thread.currentThread().getId()=1
実行順序:onCreatee->onStartCommand d->onBind->onServiceConnectedここでは、先にstartServiceを実行するとonCreateが実行され、次にonStartCommandが実行され、bindServiceを実行するとonBindメソッドが実行され、その後同じように何度もbindiceを実行してもonBindメソッドは実行されず、次にstartServiceを実行するとonStartCommandのみが実行されます
、 bindService startService
D/MainActivity( 4893): szh onStart----
D/MainActivity( 4893): szh onResume----
D/MainActivity( 4893): szh click bind Service---
D/MyService( 4893): szh onCreate-----
D/MyService( 4893): szh on Bind-----,Thread.currentThread().getId()=1
D/MyService( 4893): szh onStartCommand-----startId=7,Thread.currentThread().getId()=1
D/MainActivity( 4893): szh onServiceConnected---
D/MainActivity( 4893): szh click start Service---
D/MyService( 4893): szh onStartCommand-----startId=8,Thread.currentThread().getId()=1
bindServiceを見つけてからstartServiceでonCreate->onBind->onStartCommand->onServiceConnected->onStartCommand
まとめ:1、2つの方式が混在してサービスを起動する過程でサービスのonCreate方法とonBind方法はいずれも一度だけ実行してから実行しないことを発見しました.2、ハイブリッド起動のサービスは同じスレッドにあり、新しいスレッドは新たに起動しない
実際にサービスを実行していないonDestroyメソッド、つまり、これらの操作を行ったばかりのときにサービスが破棄されていないことに気づきましたか.実際にはbindServiceがサービスを開始した場合にのみ、バインドされたすべてのactivityがバインド解除されてunbind->onDestroyが実行されます.bindServiceの間でstartServiceを再実行すると、unbindServiceはonDestroy破棄サービスを実行しません.このときstartServiceはstopSelf()を実行しない限り、サービスは破棄されません.
サービスバインドサービスのエラー書き方
---------------Activity --------------
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG,"szh onServiceConnected---");
//myBind=(MyService.MyBind)service;
//myBind.setOnServiceChangeListener(MainActivity.this);
myService=((MyService.MyBind) service).getService();
myService.checkDownload();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"szh onServiceDisconnected---");
}
};
----------------Service ----------------------
public void checkDownload(){
Log.d(TAG,"szh checkDownload---");
}
/* */
public class MyBind extends Binder {
private OnServiceChangeListener onServiceChangeListener;
public MyService getService() {
return MyService.this;
}
public void setOnServiceChangeListener(OnServiceChangeListener listener) {
this.onServiceChangeListener = listener;
}
}
bindServiceを先に実行してunbindServiceを実行した結果を見てみましょう.
D/MainActivity( 2695): szh onStart----
D/MainActivity( 2695): szh onResume----
D/MainActivity( 2695): szh click bind Service---
D/MyService( 2695): szh onCreate-----
D/MyService( 2695): szh on Bind-----,Thread.currentThread().getId()=1
D/MyService( 2695): szh onStartCommand-----startId=3,Thread.currentThread().getId()=1
D/MainActivity( 2695): szh onServiceConnected---
D/MyService( 2695): szh checkDownload---
D/MainActivity( 2695): szh click unbind Service---
D/MyService( 2695): szh onUnbind-----
その結果、onUnbindメソッドを実行した後、onDestroyメソッドがサービスを破棄することはありません.どうしてですか.彼はgetServiceメソッドでServiceオブジェクトを得たので、オブジェクトを介してその中のメソッドを呼び出すのは普通のクラスと何の違いがありますか?サービスが破棄されてメモリが流出した場合、binderでサービスをバインドしていないと書かれています.さらに恐ろしいのはcsdnで検索したブログ10編のうち5編以上がこのように書かれていることです.細かく考えていると怖くて、自分で走ったことがないのにcopyが来ているということです.binderの核心思想はインタフェースを暴露してclient端に呼び出すことであり、clientはサービスのあるbinderオブジェクトを持つだけで必要な操作を行うことができ、直接サービスの中の方法を呼び出すことができない.このように書くのは規範的ではない.私が踏んだ穴を見て、みんながここを見て、このような低級な間違いを犯さないことを望んでいる.
プロセス間通信のいくつかの方式についての反省
プロセスとスレッドとは
私たちのアプリケーションが起動されると、システムはLniuxプロセスをこのプログラムに割り当て、私たちのアプリケーションにはスレッドがたくさんあります.スレッドはプロセスの有機的な構成部分であり,CPUスケジューリングの基礎である.プロセスにはスレッドが含まれていると理解できます.
プロセス間通信とスレッド間通信の方法はどれらがありますか。
:
BroadCast
AIDL
ContentProvider
Messager
Socket
:
Handler
AsyncTask
runInUIThread
具体的な方法はこのブログを参考にすることができます.Androidプロセス間通信とスレッド間通信のまとめAIDLとブロードキャストが一般的なプロセス間通信方式であることを知ると,なぜ前の最初のフレームワークでサービスとActivityのインタラクション方式としてブロードキャストを用いることが望ましくないのか,また同じプロセスでもAIDLは必要ないのかが分かる.
ブログ参照
1、Android Recoveryアップグレード原理