Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

絶対落ちないアプリの作り方

49 982 vues

Publié le

絶対落ちないアプリの作り方(DroidKaig 2015)

Publié dans : Logiciels
  • You have to choose carefully. ⇒ www.WritePaper.info ⇐ offers a professional writing service. I highly recommend them. The papers are delivered on time and customers are their first priority. This is their website: ⇒ www.WritePaper.info ⇐
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • Hi there! I just wanted to share a list of sites that helped me a lot during my studies: .................................................................................................................................... www.EssayWrite.best - Write an essay .................................................................................................................................... www.LitReview.xyz - Summary of books .................................................................................................................................... www.Coursework.best - Online coursework .................................................................................................................................... www.Dissertations.me - proquest dissertations .................................................................................................................................... www.ReMovie.club - Movies reviews .................................................................................................................................... www.WebSlides.vip - Best powerpoint presentations .................................................................................................................................... www.WritePaper.info - Write a research paper .................................................................................................................................... www.EddyHelp.com - Homework help online .................................................................................................................................... www.MyResumeHelp.net - Professional resume writing service .................................................................................................................................. www.HelpWriting.net - Help with writing any papers ......................................................................................................................................... Save so as not to lose
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • Dating direct: ♥♥♥ http://bit.ly/2F4cEJi ♥♥♥
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • Follow the link, new dating source: ❤❤❤ http://bit.ly/2F4cEJi ❤❤❤
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • -- DOWNLOAD THIS BOOKS INTO AVAILABLE FORMAT -- ......................................................................................................................... ......................................................................................................................... Download FULL PDF EBOOK here { http://bit.ly/2m6jJ5M } ......................................................................................................................... (Unlimited)
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici

絶対落ちないアプリの作り方

  1. 1. 絶対落ちないアプリの作り方 DroidKaigi 2015/04/25 株式会社マナボ 白山 文彦 (@fushiroyama)
  2. 2. サンプルコード https://github.com/srym/DroidKaigiSample
  3. 3. • 白山 文彦 (@fushiroyama) • 株式会社マナボ (http://mana.bo/) • Android • Ruby on Rails • DevOps • Full Text Search • 筋トレ
  4. 4. 今日は絶対に落ちないアプリについて 考察してみたいと思います。
  5. 5. だがその前に伝えておきたことがある…
  6. 6. _人人人人人人人人人人_ > そんなものはない <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
  7. 7. なんでAndroidアプリは 落ちる運命にあるのだろうか?
  8. 8. • バージョンが多種多様 • 端末が多種多様 • ベンダによる カスタマイズ • 鬼門:カメラアプリ • http://alpha.mixi.co.jp/entry/ 2013/11572/ ※ここに苦労がまとまってます • プログラマの無知と怠慢
  9. 9. • バージョンが多種多様 • 端末が多種多様 • ベンダによる カスタマイズ • 鬼門:カメラアプリ • http://alpha.mixi.co.jp/entry/ 2013/11572/ ※ここに苦労がまとまってます • プログラマの無知と怠慢
  10. 10. プログラマの無知と怠慢は 何とかしたい!
  11. 11. 今日は短い時間なので テーマを絞って話したいと思 います。
  12. 12. クラッシュのないアプリ作りの スタートは、クラッシュの事実 に向き合うことから始まります。
  13. 13. https://crashlytics.com/
  14. 14. 弊社のCrashlyticsで 実際にクラッシュの多いミスを 元に資料を作りました!
  15. 15. 1. FragmentTransactionの取り扱いミス 2. ライフサイクルの終わったコントローラへの不正なアクセス 3. APIとの連携ミス 4. カメラアプリとの連携ミス 5. 大量の画像によるOutOfMemory 6. Activity/Fragmentの再生成・復元ミス などなど…
  16. 16. アジェンダ • ライフサイクルの理解 • 非同期処理とコールバック • Contextの正体 • Fragmentあれこれ • Handlerの本質 • 静的解析を活かす • 本当に落ちないことが本当に幸せか?
  17. 17. ライフサイクルの理解
  18. 18. ホントにホントに理解出来てる?
  19. 19. • Activityはユーザ操作等によって短期間 で頻繁に生き死にを繰り返す • Activityの生死はプログラマが手出し出 来ない • Activityが状態として死を迎えた時と、 実際にオブジェクトがGCされるタイミ ングは違う
  20. 20. 超・初級編: onSaveInstanceState onRestoreInstanceState
  21. 21. public class MainActivity extends Activity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 startActivity(AnotherActivity.newIntent(this, "hello next intent"));
 }
 } サンプルコード 「saveinstancestate」
  22. 22. public class AnotherActivity extends Activity {
 private static final String KEY_TEXT = "key_text";
 
 private String text;
 
 public static Intent newIntent(Context context, String text) {
 Intent intent = new Intent(context, AnotherActivity.class);
 intent.putExtra(KEY_TEXT, text);
 return intent;
 }
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_another);
 
 Intent intent = getIntent();
 if (intent != null && intent.hasExtra(KEY_TEXT)) {
 text = intent.getStringExtra(KEY_TEXT);
 TextView textView = (TextView) findViewById(R.id.text);
 textView.setText(text);
 }
 }
 }
  23. 23. • 渡されたIntentの中身を取り出して次の Activityのfieldに保存しておくことは良くある と思うが、これをうっかり保存しわすれてその フィールドがある前提でアクセスしてクラッ シュ。誰もが初心者の時にやったことがある のではないでしょうか。
  24. 24. onSaveInstanceState 強制ギプス
  25. 25. これで漏れを検知できる
  26. 26. 初級編:非同期処理
  27. 27. Androidの非同期ライブラリ
  28. 28. • AsyncTask • Loader • Java’s Thread • Handler (!) • 3rd Party Libraries • OkHttp • Volley • Retrofit
  29. 29. これらに共通して言えること
  30. 30. 非同期処理はコントローラよ り寿命が長いことがままある
  31. 31. public class MainActivity extends Activity {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 new MyTask().execute();
 }
 
 private class MyTask extends AsyncTask<Void, Void, Void> {
 @Override
 protected Void doInBackground(Void... params) {
 // heavy task return null;
 }
 
 @Override
 protected void onPostExecute(Void aVoid) {
 // do something on Activity
 }
 }
 } サンプルコード 「asynctaskbadexample」
  32. 32. public class MainActivity extends Activity {
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 new MyTask().execute();
 }
 
 private class MyTask extends AsyncTask<Void, Void, Void> {
 @Override
 protected Void doInBackground(Void... params) {
 // heavy task return null;
 }
 
 @Override
 protected void onPostExecute(Void aVoid) {
 // do something on Activity
 }
 }
 } Activityより 長生きする可能性 がある
  33. 33. Activityより長生き… ここにクラシュの罠がたくさんある
  34. 34. まずはAsyncTask
  35. 35. 実はAsyncTaskは非推奨 (ワタシ的に)
  36. 36. • The dark side of AsyncTask • http://bon-app-etit.blogspot.jp/2013/04/ the-dark-side-of-asynctask.html • AsyncTask is bad and you should feel bad • http://simonvt.net/2014/04/17/ asynctask-is-bad-and-you-should-feel- bad/
  37. 37. • もともと長くて数秒の非同期処理にのみ使うことを推奨されてい る • 基本やりっ放しなので処理を丸々無駄にする • cancel()すればいいのでは? • BitmapFactory.decodeStream()みたいなキャンセルできない 操作もある • バージョンによってシーケンシャルかパラレルかが異なる • 画面回転等で結果を引き継げない • onRetainNonConfigurationInstanceとか使えばいいけどそん なことするぐらいなら後述のLoader使ったほうがいい
  38. 38. どうしてもAsyncTaskを 使いたい場合…
  39. 39. public class MainActivity extends Activity {
 private static final String TAG = MainActivity.class.getSimpleName();
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 new MyTask(new MyTask.Callback() {
 @Override
 public void onFinish() {
 Log.d(TAG, "finish");
 }
 }).execute();
 }
 
 private static class MyTask extends AsyncTask<Void, Void, Void> {
 private Callback callback;
 
 private MyTask(Callback callback) {
 this.callback = callback;
 }
 
 @Override
 protected Void doInBackground(Void... params) {
 // do something
 return null;
 }
 
 @Override
 protected void onPostExecute(Void aVoid) {
 callback.onFinish();
 }
 
 private interface Callback {
 void onFinish();
 }
 }
 } ほんのちょっと マシな例 サンプルコード 「asynctaskbetterexample」
  40. 40. もうほんのちょっ とマシな例 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 new MyTask(new MyTask.Callback() {
 @Override
 public void onFinish() {
 Log.d(TAG, "finish");
 }
 }).execute();
 }
 
 private static class MyTask extends AsyncTask<Void, Void, Void> {
 private WeakReference<Callback> callbackRef;
 
 private MyTask(Callback callback) {
 callbackRef = new WeakReference<Callback>(callback);
 }
 
 @Override
 protected Void doInBackground(Void... params) {
 // do something
 return null;
 }
 
 @Override
 protected void onPostExecute(Void aVoid) {
 Callback callback = callbackRef.get();
 if (callback != null)
 callback.onFinish();
 }
 
 private interface Callback {
 void onFinish();
 }
 } サンプルコード 「asynctaskmorebetterexample」
  41. 41. private MyTask task;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 task = new MyTask(new MyTask.Callback() {
 @Override
 public void onFinish() {
 Log.d(TAG, "finish");
 }
 });
 task.execute();
 }
 
 @Override
 protected void onDestroy() {
 super.onDestroy();
 task.cancel(true);
 }
 
 private static class MyTask extends AsyncTask<Void, Void, Void> {
 // 前略
 
 @Override
 protected Void doInBackground(Void... params) {
 while (taskRemaining()) {
 if (isCancelled()) {
 Log.d(TAG, "canceled");
 return null;
 }
 doHeavyTask();
 }
 return null;
 }
 
 // 後略
 } もうほんの あと少しマシな例 サンプルコード 「asynctaskmuchmorebetterexample」
  42. 42. AsyncTaskはちょろっとした処 理をするのに便利なのも事実な ので上手に付き合おう
  43. 43. AsyncTaskLoader
  44. 44. • ActivityやFragmentのライフサイクルと非同 期処理を切り離すことができる • コールバックをコントローラ側に簡単に記述で きる。結果はメインスレッドで受け取れる。 • 一番重要な点は、画面回転等でも非同期処理を 引き継げるような書き方が簡単にできること。
  45. 45. public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {
 private static final String TAG = MainActivity.class.getSimpleName();
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 LoaderManager manager = getLoaderManager();
 manager.initLoader(0, null, this);
 }
 
 @Override
 public Loader<String> onCreateLoader(int id, Bundle args) {
 return new MyLoader(this.getApplicationContext());
 }
 
 @Override
 public void onLoadFinished(Loader<String> loader, String data) {
 Log.d(TAG, data);
 }
 
 @Override
 public void onLoaderReset(Loader<String> loader) {
 // NOP
 } サンプルコード 「loadersimpleexample」
  46. 46. private static class MyLoader extends AsyncTaskLoader<String> {
 private String mCachedData;
 
 private MyLoader(Context context) {
 super(context);
 }
 
 @Override
 public String loadInBackground() {
 return "fetched";
 }
 
 @Override
 public void deliverResult(String data) {
 if (isReset()) {
 if (mCachedData != null) {
 mCachedData = null;
 }
 return;
 }
 mCachedData = data;
 if (isStarted()) {
 super.deliverResult(data);
 }
 }
 
 @Override
 protected void onStartLoading() {
 if (mCachedData != null) {
 deliverResult(mCachedData);
 return;
 }
 
 if (takeContentChanged() || mCachedData == null) {
 forceLoad();
 }
 }
 
 @Override
 protected void onStopLoading() {
 cancelLoad();
 super.onStopLoading();
 }
 
 @Override
 protected void onReset() {
 onStopLoading();
 super.onReset();
 }
 }

  47. 47. • Loaderを管理するLoaderManagerはActivityやFragment ごとにひとつ。 • 画面回転でもLoaderManagerインスタンスは死なない。 • LoaderManager#initLoaderではコールバックをセットし 直しつつ処理を引き継ぐ。 • LoaderManager#restartLoaderでは既存の非同期処理を破 棄して新たに非同期処理を行う。
  48. 48. AsyncTaskとの最大の違い
  49. 49. • AsyncTaskの中にコールバックメソッドがある • →利用側にコールバックのロジックを持つのが 手間 • AsyncTaskLoaderはLoaderCallbacksを利用側 が実装するので使いやすい
  50. 50. EventBus
  51. 51. • Observerパターンのような感じでライフサイクルオブジェクト は自分のライフサイクルに合わせてイベントの購読/非購読する • 非同期処理が終わったら購読者に完了イベントを一斉通知する • コールバックが基本一対一なのに対し、一対多へ通知も可能。 • Loader同様、ライフサイクルオブジェクトより長命な処理が無 駄にならず、ライフサイクル側でregister/unregisterするので コールバック時にライフサイクルが終わっている危険性も無い。
  52. 52. import com.squareup.otto.Bus;
 
 public final class BusProvider {
 private static final Bus BUS = new Bus();
 
 public static Bus getInstance() {
 return BUS;
 }
 
 private BusProvider() {
 }
 } サンプルコード 「eventbusexample」
  53. 53. BusProvider.getInstance().post(new NewVersionAvailableEvent(latestVersion)); イベントを発火
  54. 54. @Override
 protected void onResume() {
 super.onResume();
 BusProvider.getInstance().register(this);
 }
 @Override
 protected void onPause() {
 super.onPause();
 BusProvider.getInstance().unregister(this);
 }
 
 @Subscribe
 public void onEventReceived(HogeEvent event) {
 }
  55. 55. • square/otto • https://github.com/square/otto • greenbot/EventBus • https://github.com/greenrobot/EventBus • おれおれコールバック設計 • http://qiita.com/hnakagawa/items/984557b13aede61d05d0 • EventBusとは違うけど非常に参考になる
  56. 56. RxJava/RxAndroid
  57. 57. RxJava/RxAndroid
  58. 58. • ここ一年で物凄い勢いで注目を集めているライブラリ及びプ ログラミング手法 • Reactive Functional Programming • LINQのような集合操作メソッド群と遅延評価を合わせたよう な関数型的プログラミング手法 • コールバックヘルからの脱却! • これだけで長大な記事になるので機会があれば後日記事にし ます!!!(今回は泣く泣く断念)
  59. 59. Contextの正体を意識する
  60. 60. • Context…アプリケーションの様々な情報にアク セスするためのインタフェース • 画像、文字等の各種リソース • アプリケーションそのものの情報 • パーミッション等々
  61. 61. 概念が抽象的すぎてよくわからない
  62. 62. 大きく分けて ApplicationContext ActivityContext もうあと2つぐら いあるらしいけど
  63. 63. なぜContextの正体を知って いる必要があるか?
  64. 64. ActivityContextが長く参照さ れる=深刻なメモリリーク
  65. 65. public class MainActivity extends Activity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 new MyTask(getApplicationContext()).execute();
 }
 
 private class MyTask extends AsyncTask<Void, Void, Void> {
 private Context context;
 
 private MyTask(Context context) {
 this.context = context;
 }
 
 @Override
 protected Void doInBackground(Void... params) {
 context.getString(R.string.hello_world);
 return null;
 }
 }
 }

  66. 66. だいたいのケースで ApplicationContextが使える
  67. 67. じゃあ全部 ApplicationContext でいいの?
  68. 68. • Activity 外から startActivity する場合は Intent に FLAG_ACTIVITY_NEW_TASK が含まれている必要 がある。 • AlertDialog.BuilderにApplicationContextを渡すと WindowTokenの取得に失敗 • Toast時に意図しないテーマが出たりすることも
  69. 69. new  AlertDialog.Builder(getApplicationContext()); E/AndroidRuntime: Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
  70. 70. やはり、ちゃんと理解して気 持ちよく使おう!
  71. 71. 原則:ActivityContextをActivity より長命などこかに渡す場面に遭 遇したら、設計を見なおせ!
  72. 72. Fragmentあれこれ
  73. 73. Fragmentは気をつけないと非 常にクラッシュの元になります
  74. 74. 原則その1: Fragmentインスタンスにsetしない
  75. 75. Fragment fragment = new BlankFragment();
 fragment.setParam(param);
 getFragmentManager().beginTransaction()
 .replace(android.R.id.content, fragment)
 .commit(); —————————————————————————————————————————————————————— Fragment fragment = new BlankFragment(param1, param2);
 getFragmentManager().beginTransaction()
 .replace(android.R.id.content, fragment)
 .commit(); どっちも 間違い!
  76. 76. public class BlankFragment extends Fragment {
 private static final String ARG_PARAM1 = "param1";
 private static final String ARG_PARAM2 = "param2";
 
 private String mParam1;
 private String mParam2;
 
 public static BlankFragment newInstance(String param1, String param2) {
 BlankFragment fragment = new BlankFragment();
 Bundle args = new Bundle();
 args.putString(ARG_PARAM1, param1);
 args.putString(ARG_PARAM2, param2);
 fragment.setArguments(args);
 return fragment;
 }
 
 public BlankFragment() {
 // Required empty public constructor
 }
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 if (getArguments() != null) {
 mParam1 = getArguments().getString(ARG_PARAM1);
 mParam2 = getArguments().getString(ARG_PARAM2);
 }
 }
 
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
 Bundle savedInstanceState) {
 // Inflate the layout for this fragment
 return inflater.inflate(R.layout.fragment_blank, container, false);
 }
  77. 77. 原則その2:リスナもsetできない
  78. 78. BlankFragment fragment = BlankFragment.newInstance("param1", "param2");
 fragment.setListener(new BlankFragment.OnFragmentInteractionListener() {
 @Override
 public void onFragmentInteraction(Uri uri) {
 // interaction
 }
 });
 
 getFragmentManager().beginTransaction()
 .replace(android.R.id.content, fragment)
 .commit(); もちろん 間違い!
  79. 79. 原則その3:リスナは setSerializableで渡せない
  80. 80. public class BlankFragment extends Fragment {
 private static final String ARG_PARAM1 = "param1";
 private static final String ARG_PARAM2 = "param2";
 private static final String ARG_LISTENER = "listener";
 
 private String mParam1;
 private String mParam2;
 private OnFragmentInteractionListener mListener;
 
 public static BlankFragment newInstance(String param1, String param2, OnFragmentInteractionListener listener) {
 BlankFragment fragment = new BlankFragment();
 Bundle args = new Bundle();
 args.putString(ARG_PARAM1, param1);
 args.putString(ARG_PARAM2, param2);
 args.putSerializable(ARG_LISTENER, listener);
 fragment.setArguments(args);
 return fragment;
 }
 
 public BlankFragment() {
 // Required empty public constructor
 }
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 if (getArguments() != null) {
 mParam1 = getArguments().getString(ARG_PARAM1);
 mParam2 = getArguments().getString(ARG_PARAM2);
 mListener = (OnFragmentInteractionListener) getArguments().getSerializable(ARG_LISTENER);
 }
 } public interface OnFragmentInteractionListener extends Serializable {
 public void onFragmentInteraction(Uri uri);
 } 一見行けそうだが …
  81. 81. @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 BlankFragment fragment = BlankFragment.newInstance("param1", "param2", new BlankFragment.OnFragmentInteractionListener() {
 @Override
 public void onFragmentInteraction(Uri uri) {
 // interaction
 }
 });
 
 getFragmentManager().beginTransaction()
 .replace(android.R.id.content, fragment)
 .commit();
 } Activityへの 暗黙の参照
  82. 82. • https://docs.oracle.com/javase/jp/1.4/guide/serialization/spec/serial- arch.doc10.html • (引用)ローカルクラスおよび匿名クラスを含む内部クラス (static メンバクラスでは ない入れ子のクラス) の直列化は、いくつかの理由により、使用しないことを強くお勧 めします。非 static コンテキストで宣言された内部クラスには、囲むクラスインスタン スへの暗黙的な非 transient 参照が含まれるので、そのような内部クラスインスタンス を直列化すると、関連する外部クラスインスタンスも直列化されることになります。内 部クラスを実装する javac (またはその他の JavaTM コンパイラ) によって生成された 合成フィールドは、実装に依存するので、コンパイラによって相違が生じることがあり ます。
  83. 83. @Override
 public void onAttach(Activity activity) {
 super.onAttach(activity);
 try {
 mListener = (OnFragmentInteractionListener) activity;
 } catch (ClassCastException e) {
 throw new ClassCastException(activity.toString()
 + " must implement OnFragmentInteractionListener");
 }
 } Activityで implement サンプルコードの 「fragmentexample」
  84. 84. EventBusはActivity-Fragmentの インタラクションにも有効
  85. 85. FragmentTransactionに ご用心!
  86. 86. BlankFragment fragment = BlankFragment.newInstance("param1", "param2");
 fragment.setListener(new BlankFragment.OnFragmentInteractionListener() {
 @Override
 public void onFragmentInteraction(Uri uri) {
 // interaction
 }
 });
 
 getFragmentManager().beginTransaction()
 .replace(android.R.id.content, fragment)
 .commit();
  87. 87. • onSaveInstanceState以降にFragmentTransactionを伴う処理を行うと IllegalStateExceptionが発生する • これは、そのタイミング以降になにか変更をしても、もしインスタンスが再 生成された場合に元の状態に戻しようがないため • FragmentTransaction.commitAllowingStateLoss()すれば例外が上がらな いようにはできる
  88. 88. • 意外な盲点として、DialogFragment#show, dissmissはFragmentTransaction を伴う処理であるということ。 • 非同期通信の間何かダイアログを出し、完了後にdissmissするような処理は非 常にありがちなので、タイミング次第で発生するクラッシュになる。 • 弊社のクラッシュでもFragmentTransactionに起因する例外が非常に多かっ た!
  89. 89. Fragment#isResumed() isベンリ
  90. 90. if (isResumed()) {
 dialog.dismiss();
 }
  91. 91. 
 public class BaseActivity extends Activity {
 private volatile boolean mIsResumed = false;
 
 @Override
 protected void onResume() {
 super.onResume();
 mIsResumed = true;
 }
 
 @Override
 protected void onPause() {
 super.onPause();
 mIsResumed = false;
 }
 
 protected boolean isActivityResumed() {
 return mIsResumed;
 }
 
 protected boolean isActivityPaused() {
 return !mIsResumed;
 }
 
 }
 Activity版を作る と気休めになる
  92. 92. onResume/onPause間で 安全にFragmentTransactionする テクニック紹介
  93. 93. public abstract class PauseHandler<T> extends Handler {
 private final List<Message> messageQueueBuffer = Collections.synchronizedList(new ArrayList<Message>());
 
 private T obj;
 public final synchronized void resume(T obj) {
 this.obj = obj;
 
 while (messageQueueBuffer.size() > 0) {
 final Message msg = messageQueueBuffer.get(0);
 messageQueueBuffer.remove(0);
 sendMessage(msg);
 }
 }
 
 public final synchronized void pause() {
 obj = null;
 }
 
 @Override
 public final synchronized void handleMessage(Message msg) {
 if (obj == null) {
 final Message msgCopy = new Message();
 msgCopy.copyFrom(msg);
 messageQueueBuffer.add(msgCopy);
 } else {
 processMessage(obj, msg);
 }
 }
 
 protected abstract void processMessage(T obj, Message message);
 
 } サンプルコードの 「pausehandler」
  94. 94. private static class ActivityPauseHandler extends PauseHandler<BaseActivity> {
 @Override
 protected void processMessage(BaseActivity activity, Message message) {
 activity.processMessage(message);
 }
 } public ActivityPauseHandler mPauseHandler = new ActivityPauseHandler(); @Override
 protected void onResume() {
 super.onResume();
 mPauseHandler.resume(this);
 } @Override
 protected void onPause() {
 super.onPause();
 mPauseHandler.pause();
 }
  95. 95. @Override
 public void processMessage(Message message) {
 if (message.what != WHAT_SHOW_DIALOG) {
 return;
 } dialog.show(getSupportFragmentManager(), "TAG");
 }
  96. 96. Handlerを理解する
  97. 97. Handlerとはなにか
  98. 98. mHandler.post(new Runnable() {
 @Override
 public void run() {
 Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
 
 }
 }); ワーカスレッドか ら呼び出し
  99. 99. ワーカスレッドからUIスレッドを 触るときに使う不思議なやつ…?
  100. 100. だけではないんです。
  101. 101. • 任意のThread(メッセージループ)にメッセージを送ったりメッ セージを取り出して処理したりする人 • AndroidではLooperがメッセージループ • Messageがメッセージ(そのまま!) • LooperはMessageを貯めておいて随時実行するキューを持ってい る(MessageQueue) • 単純なキューではない。遅延実行等を加味されてキューに積まれる。
  102. 102. なぜこれを知っておく必要があるか?
  103. 103. AndroidのUI =シングルスレッドモデル
  104. 104. UI更新はUIスレッドのメッセージ キューに積んで処理してもらう必要 がある。
  105. 105. new Handler()された場所のThreadに紐づく=UIス レッドでnewされたらUIスレッドにメッセージが送れ るというだけ! あるいは new Handler(Looper.getMainLooper());
  106. 106. AndroidではUIスレッド以外でUI操 作を試みた時点でクラッシュする
  107. 107. いままでなんとなくHandler使っ てませんでしたか?
  108. 108. Handlerとその奥に流れる思想を理解で きたらいよいよAndroid中級者です!
  109. 109. Handlerの応用例
  110. 110. HandlerThread thread = new HandlerThread(NON_UI_HANDLER_THREAD_NAME);
 thread.start();
 mNonUiHandler = new Handler(thread.getLooper()); Canvas canvas = mHolder.lockCanvas();
 canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC);
 canvas.concat(mMatrix);
 drawImages(canvas);
 canvas.restoreToCount(saveCount);
 mHolder.unlockCanvasAndPost(canvas);
  111. 111. 静的解析のチカラを借りる
  112. 112. Javaはよくも悪くも強い静的型付 け言語である。
  113. 113. 型、アノテーション、いずれも強 力なのだから最大限利用すべき
  114. 114. @Nullable @NonNull nullチェックがないと警告 nullを渡すと警告
  115. 115. @BooleanRes @ColorStateListRes @DrawableRes @IntArrayRes @IntegerRes @LayoutRes @MovieRes @TextRes @TextArrayRes @StringArrayRes https://github.com/excilys/ androidannotations/wiki/Resources int型でも、対応するリソースの intでないとコンパイルエラー
  116. 116. private ConfabDetailState(int statusId, @StringRes int statusStringId, @StringRes int tutorLabelId, @ColorRes int borderColorId, @ColorRes int backgroundColorId) {
 mStatusId = statusId;
 mStatusStringId = statusStringId;
 mTutorLabelId = tutorLabelId;
 mBorderColorId = borderColorId;
 mBackgroundColorId = backgroundColorId;
 } 意図しないintの代入を コンパイル時に防げる
  117. 117. 絶対に落ちないアプリが 本当に幸せか?
  118. 118. • ゼロ除算の発生しうる場所だったの でガチガチのチェックをしてクラッ シュすることがないように初期値を 入れたりしたが、実はAPIのバグ以 外で0が返ることはありえない場所 • かえってAPIの不具合の発見を遅ら せる結果になった
  119. 119. 落ちるときは素直に落ちるのも手
  120. 120. お聞きいただきありがとうございました。
  121. 121. We're Hiring!
  122. 122. • 教育で世界を変える仲間を募集しています! • iOS技術者 • Android技術者 • http://mana.bo/corp/recruit/

×