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

Fumihiko Shiroyama
Fumihiko ShiroyamaSoftware Developer at mana.bo, inc.
絶対落ちないアプリの作り方
DroidKaigi 2015/04/25
株式会社マナボ 白山 文彦 (@fushiroyama)
サンプルコード
https://github.com/srym/DroidKaigiSample
• 白山 文彦 (@fushiroyama)
• 株式会社マナボ (http://mana.bo/)
• Android
• Ruby on Rails
• DevOps
• Full Text Search
• 筋トレ
今日は絶対に落ちないアプリについて
考察してみたいと思います。
だがその前に伝えておきたことがある…
_人人人人人人人人人人_
> そんなものはない <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
なんでAndroidアプリは
落ちる運命にあるのだろうか?
• バージョンが多種多様
• 端末が多種多様
• ベンダによる カスタマイズ
• 鬼門:カメラアプリ
• http://alpha.mixi.co.jp/entry/
2013/11572/ ※ここに苦労がまとまってます
• プログラマの無知と怠慢
• バージョンが多種多様
• 端末が多種多様
• ベンダによる カスタマイズ
• 鬼門:カメラアプリ
• http://alpha.mixi.co.jp/entry/
2013/11572/ ※ここに苦労がまとまってます
• プログラマの無知と怠慢
プログラマの無知と怠慢は
何とかしたい!
今日は短い時間なので
テーマを絞って話したいと思
います。
クラッシュのないアプリ作りの
スタートは、クラッシュの事実
に向き合うことから始まります。
https://crashlytics.com/
弊社のCrashlyticsで
実際にクラッシュの多いミスを
元に資料を作りました!
1. FragmentTransactionの取り扱いミス
2. ライフサイクルの終わったコントローラへの不正なアクセス
3. APIとの連携ミス
4. カメラアプリとの連携ミス
5. 大量の画像によるOutOfMemory
6. Activity/Fragmentの再生成・復元ミス などなど…
アジェンダ
• ライフサイクルの理解
• 非同期処理とコールバック
• Contextの正体
• Fragmentあれこれ
• Handlerの本質
• 静的解析を活かす
• 本当に落ちないことが本当に幸せか?
ライフサイクルの理解
絶対落ちないアプリの作り方
ホントにホントに理解出来てる?
• Activityはユーザ操作等によって短期間
で頻繁に生き死にを繰り返す
• Activityの生死はプログラマが手出し出
来ない
• Activityが状態として死を迎えた時と、
実際にオブジェクトがGCされるタイミ
ングは違う
超・初級編:
onSaveInstanceState
onRestoreInstanceState
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」
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);

}

}

}
• 渡されたIntentの中身を取り出して次の
Activityのfieldに保存しておくことは良くある
と思うが、これをうっかり保存しわすれてその
フィールドがある前提でアクセスしてクラッ
シュ。誰もが初心者の時にやったことがある
のではないでしょうか。
onSaveInstanceState
強制ギプス
絶対落ちないアプリの作り方
これで漏れを検知できる
初級編:非同期処理
Androidの非同期ライブラリ
• AsyncTask
• Loader
• Java’s Thread
• Handler (!)
• 3rd Party Libraries
• OkHttp
• Volley
• Retrofit
これらに共通して言えること
非同期処理はコントローラよ
り寿命が長いことがままある
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」
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より
長生きする可能性
がある
Activityより長生き…
ここにクラシュの罠がたくさんある
まずはAsyncTask
実はAsyncTaskは非推奨
(ワタシ的に)
• 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/
• もともと長くて数秒の非同期処理にのみ使うことを推奨されてい
る
• 基本やりっ放しなので処理を丸々無駄にする
• cancel()すればいいのでは?
• BitmapFactory.decodeStream()みたいなキャンセルできない
操作もある
• バージョンによってシーケンシャルかパラレルかが異なる
• 画面回転等で結果を引き継げない
• onRetainNonConfigurationInstanceとか使えばいいけどそん
なことするぐらいなら後述のLoader使ったほうがいい
どうしてもAsyncTaskを
使いたい場合…
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」
もうほんのちょっ
とマシな例
@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」
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」
AsyncTaskはちょろっとした処
理をするのに便利なのも事実な
ので上手に付き合おう
AsyncTaskLoader
• ActivityやFragmentのライフサイクルと非同
期処理を切り離すことができる
• コールバックをコントローラ側に簡単に記述で
きる。結果はメインスレッドで受け取れる。
• 一番重要な点は、画面回転等でも非同期処理を
引き継げるような書き方が簡単にできること。
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」
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();

}

}

• Loaderを管理するLoaderManagerはActivityやFragment
ごとにひとつ。
• 画面回転でもLoaderManagerインスタンスは死なない。
• LoaderManager#initLoaderではコールバックをセットし
直しつつ処理を引き継ぐ。
• LoaderManager#restartLoaderでは既存の非同期処理を破
棄して新たに非同期処理を行う。
AsyncTaskとの最大の違い
• AsyncTaskの中にコールバックメソッドがある
• →利用側にコールバックのロジックを持つのが
手間
• AsyncTaskLoaderはLoaderCallbacksを利用側
が実装するので使いやすい
EventBus
• Observerパターンのような感じでライフサイクルオブジェクト
は自分のライフサイクルに合わせてイベントの購読/非購読する
• 非同期処理が終わったら購読者に完了イベントを一斉通知する
• コールバックが基本一対一なのに対し、一対多へ通知も可能。
• Loader同様、ライフサイクルオブジェクトより長命な処理が無
駄にならず、ライフサイクル側でregister/unregisterするので
コールバック時にライフサイクルが終わっている危険性も無い。
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」
BusProvider.getInstance().post(new NewVersionAvailableEvent(latestVersion));
イベントを発火
@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) {

}
• square/otto
• https://github.com/square/otto
• greenbot/EventBus
• https://github.com/greenrobot/EventBus
• おれおれコールバック設計
• http://qiita.com/hnakagawa/items/984557b13aede61d05d0
• EventBusとは違うけど非常に参考になる
RxJava/RxAndroid
RxJava/RxAndroid
• ここ一年で物凄い勢いで注目を集めているライブラリ及びプ
ログラミング手法
• Reactive Functional Programming
• LINQのような集合操作メソッド群と遅延評価を合わせたよう
な関数型的プログラミング手法
• コールバックヘルからの脱却!
• これだけで長大な記事になるので機会があれば後日記事にし
ます!!!(今回は泣く泣く断念)
Contextの正体を意識する
• Context…アプリケーションの様々な情報にアク
セスするためのインタフェース
• 画像、文字等の各種リソース
• アプリケーションそのものの情報
• パーミッション等々
概念が抽象的すぎてよくわからない
大きく分けて
ApplicationContext
ActivityContext
もうあと2つぐら
いあるらしいけど
なぜContextの正体を知って
いる必要があるか?
ActivityContextが長く参照さ
れる=深刻なメモリリーク
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;

}

}

}

だいたいのケースで
ApplicationContextが使える
じゃあ全部
ApplicationContext
でいいの?
• Activity 外から startActivity する場合は Intent
に FLAG_ACTIVITY_NEW_TASK が含まれている必要
がある。
• AlertDialog.BuilderにApplicationContextを渡すと
WindowTokenの取得に失敗
• Toast時に意図しないテーマが出たりすることも
new	
  AlertDialog.Builder(getApplicationContext());
E/AndroidRuntime: Caused by:
android.view.WindowManager$BadTokenException:
Unable to add window -- token null is not for an application
やはり、ちゃんと理解して気
持ちよく使おう!
原則:ActivityContextをActivity
より長命などこかに渡す場面に遭
遇したら、設計を見なおせ!
Fragmentあれこれ
Fragmentは気をつけないと非
常にクラッシュの元になります
原則その1:
Fragmentインスタンスにsetしない
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();
どっちも
間違い!
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);

}
原則その2:リスナもsetできない
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();
もちろん
間違い!
原則その3:リスナは
setSerializableで渡せない
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);

}
一見行けそうだが
…
@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への
暗黙の参照
• https://docs.oracle.com/javase/jp/1.4/guide/serialization/spec/serial-
arch.doc10.html
• (引用)ローカルクラスおよび匿名クラスを含む内部クラス (static メンバクラスでは
ない入れ子のクラス) の直列化は、いくつかの理由により、使用しないことを強くお勧
めします。非 static コンテキストで宣言された内部クラスには、囲むクラスインスタン
スへの暗黙的な非 transient 参照が含まれるので、そのような内部クラスインスタンス
を直列化すると、関連する外部クラスインスタンスも直列化されることになります。内
部クラスを実装する javac (またはその他の JavaTM コンパイラ) によって生成された
合成フィールドは、実装に依存するので、コンパイラによって相違が生じることがあり
ます。
@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」
EventBusはActivity-Fragmentの
インタラクションにも有効
FragmentTransactionに
ご用心!
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();
• onSaveInstanceState以降にFragmentTransactionを伴う処理を行うと
IllegalStateExceptionが発生する
• これは、そのタイミング以降になにか変更をしても、もしインスタンスが再
生成された場合に元の状態に戻しようがないため
• FragmentTransaction.commitAllowingStateLoss()すれば例外が上がらな
いようにはできる
• 意外な盲点として、DialogFragment#show, dissmissはFragmentTransaction
を伴う処理であるということ。
• 非同期通信の間何かダイアログを出し、完了後にdissmissするような処理は非
常にありがちなので、タイミング次第で発生するクラッシュになる。
• 弊社のクラッシュでもFragmentTransactionに起因する例外が非常に多かっ
た!
Fragment#isResumed()
isベンリ
if (isResumed()) {

dialog.dismiss();

}


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版を作る
と気休めになる
onResume/onPause間で
安全にFragmentTransactionする
テクニック紹介
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」
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();

}
@Override

public void processMessage(Message message) {

if (message.what != WHAT_SHOW_DIALOG) {

return;

}
dialog.show(getSupportFragmentManager(), "TAG");

}
Handlerを理解する
Handlerとはなにか
mHandler.post(new Runnable() {

@Override

public void run() {

Toast.makeText(context, text, Toast.LENGTH_SHORT).show();



}

});
ワーカスレッドか
ら呼び出し
ワーカスレッドからUIスレッドを
触るときに使う不思議なやつ…?
だけではないんです。
• 任意のThread(メッセージループ)にメッセージを送ったりメッ
セージを取り出して処理したりする人
• AndroidではLooperがメッセージループ
• Messageがメッセージ(そのまま!)
• LooperはMessageを貯めておいて随時実行するキューを持ってい
る(MessageQueue)
• 単純なキューではない。遅延実行等を加味されてキューに積まれる。
なぜこれを知っておく必要があるか?
AndroidのUI
=シングルスレッドモデル
UI更新はUIスレッドのメッセージ
キューに積んで処理してもらう必要
がある。
new Handler()された場所のThreadに紐づく=UIス
レッドでnewされたらUIスレッドにメッセージが送れ
るというだけ!
あるいは
new Handler(Looper.getMainLooper());
AndroidではUIスレッド以外でUI操
作を試みた時点でクラッシュする
いままでなんとなくHandler使っ
てませんでしたか?
Handlerとその奥に流れる思想を理解で
きたらいよいよAndroid中級者です!
Handlerの応用例
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);
静的解析のチカラを借りる
Javaはよくも悪くも強い静的型付
け言語である。
型、アノテーション、いずれも強
力なのだから最大限利用すべき
@Nullable
@NonNull
nullチェックがないと警告
nullを渡すと警告
@BooleanRes
@ColorStateListRes
@DrawableRes
@IntArrayRes
@IntegerRes
@LayoutRes
@MovieRes
@TextRes
@TextArrayRes
@StringArrayRes
https://github.com/excilys/
androidannotations/wiki/Resources
int型でも、対応するリソースの
intでないとコンパイルエラー
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の代入を
コンパイル時に防げる
絶対に落ちないアプリが
本当に幸せか?
• ゼロ除算の発生しうる場所だったの
でガチガチのチェックをしてクラッ
シュすることがないように初期値を
入れたりしたが、実はAPIのバグ以
外で0が返ることはありえない場所
• かえってAPIの不具合の発見を遅ら
せる結果になった
落ちるときは素直に落ちるのも手
お聞きいただきありがとうございました。
We're Hiring!
• 教育で世界を変える仲間を募集しています!
• iOS技術者
• Android技術者
• http://mana.bo/corp/recruit/
1 of 124

Recommended

Kotlinアンチパターン by
KotlinアンチパターンKotlinアンチパターン
KotlinアンチパターンRecruit Lifestyle Co., Ltd.
53.1K views90 slides
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話 by
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話
DDDとクリーンアーキテクチャでサーバーアプリケーションを作っている話JustSystems Corporation
22.5K views46 slides
ここがつらいよWebRTC - WebRTC開発の落とし穴 by
ここがつらいよWebRTC - WebRTC開発の落とし穴ここがつらいよWebRTC - WebRTC開発の落とし穴
ここがつらいよWebRTC - WebRTC開発の落とし穴mganeko
4.3K views45 slides
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O... by
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...NTT DATA Technology & Innovation
2.2K views64 slides
やはりお前らのMVCは間違っている by
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているKoichi Tanaka
145.7K views66 slides
例外設計における大罪 by
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
68.6K views37 slides

More Related Content

What's hot

導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について by
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来についてshinjiigarashi
2.7K views59 slides
ワタシはSingletonがキライだ by
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだTetsuya Kaneuchi
17.9K views38 slides
WebSocket / WebRTCの技術紹介 by
WebSocket / WebRTCの技術紹介WebSocket / WebRTCの技術紹介
WebSocket / WebRTCの技術紹介Yasuhiro Mawarimichi
50.2K views139 slides
JVMのGCアルゴリズムとチューニング by
JVMのGCアルゴリズムとチューニングJVMのGCアルゴリズムとチューニング
JVMのGCアルゴリズムとチューニング佑哉 廣岡
21.7K views96 slides
イベント駆動プログラミングとI/O多重化 by
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化Gosuke Miyashita
15.4K views78 slides
iOSでライブラリを提供する際に気をつけたいこと by
iOSでライブラリを提供する際に気をつけたいことiOSでライブラリを提供する際に気をつけたいこと
iOSでライブラリを提供する際に気をつけたいことasakahara
23K views24 slides

What's hot(20)

導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について by shinjiigarashi
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について
shinjiigarashi2.7K views
ワタシはSingletonがキライだ by Tetsuya Kaneuchi
ワタシはSingletonがキライだワタシはSingletonがキライだ
ワタシはSingletonがキライだ
Tetsuya Kaneuchi17.9K views
JVMのGCアルゴリズムとチューニング by 佑哉 廣岡
JVMのGCアルゴリズムとチューニングJVMのGCアルゴリズムとチューニング
JVMのGCアルゴリズムとチューニング
佑哉 廣岡21.7K views
イベント駆動プログラミングとI/O多重化 by Gosuke Miyashita
イベント駆動プログラミングとI/O多重化イベント駆動プログラミングとI/O多重化
イベント駆動プログラミングとI/O多重化
Gosuke Miyashita15.4K views
iOSでライブラリを提供する際に気をつけたいこと by asakahara
iOSでライブラリを提供する際に気をつけたいことiOSでライブラリを提供する際に気をつけたいこと
iOSでライブラリを提供する際に気をつけたいこと
asakahara23K views
Dockerfileを改善するためのBest Practice 2019年版 by Masahito Zembutsu
Dockerfileを改善するためのBest Practice 2019年版Dockerfileを改善するためのBest Practice 2019年版
Dockerfileを改善するためのBest Practice 2019年版
Masahito Zembutsu63.7K views
関数型プログラミングのデザインパターンひとめぐり by Kazuyuki TAKASE
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり
Kazuyuki TAKASE3K views
node-gypを使ったネイティブモジュールの作成 by shigeki_ohtsu
node-gypを使ったネイティブモジュールの作成node-gypを使ったネイティブモジュールの作成
node-gypを使ったネイティブモジュールの作成
shigeki_ohtsu20.8K views
ストリーム処理を支えるキューイングシステムの選び方 by Yoshiyasu SAEKI
ストリーム処理を支えるキューイングシステムの選び方ストリーム処理を支えるキューイングシステムの選び方
ストリーム処理を支えるキューイングシステムの選び方
Yoshiyasu SAEKI40.2K views
スマホ(Android・iPhone)でWebRTC by Natsuki Yamanaka
スマホ(Android・iPhone)でWebRTCスマホ(Android・iPhone)でWebRTC
スマホ(Android・iPhone)でWebRTC
Natsuki Yamanaka18.2K views
負荷試験ツールlocustを使おう by iRidge, Inc.
負荷試験ツールlocustを使おう負荷試験ツールlocustを使おう
負荷試験ツールlocustを使おう
iRidge, Inc.1.1K views
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い by Ken Morishita
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞いiOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
iOS/Androidアプリエンジニアが理解すべき「Model」の振る舞い
Ken Morishita84.3K views
アプリの鍵が消える時_Droid kaigi2018 by ak_shio_555
アプリの鍵が消える時_Droid kaigi2018アプリの鍵が消える時_Droid kaigi2018
アプリの鍵が消える時_Droid kaigi2018
ak_shio_55510.5K views
ADRという考えを取り入れてみて by infinite_loop
ADRという考えを取り入れてみてADRという考えを取り入れてみて
ADRという考えを取り入れてみて
infinite_loop2.9K views
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜 by Yusuke Naka
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
実践 WebRTC 〜最新事例と開発ノウハウの紹介〜
Yusuke Naka17.3K views
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践 by Yoshifumi Kawai
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
AWS + Windows(C#)で構築する.NET最先端技術によるハイパフォーマンスウェブアプリケーション開発実践
Yoshifumi Kawai191.5K views
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】 by Masahito Zembutsu
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Docker入門-基礎編 いまから始めるDocker管理【2nd Edition】
Masahito Zembutsu82.3K views
iOSにおけるパフォーマンス計測 by Toshiyuki Hirata
iOSにおけるパフォーマンス計測iOSにおけるパフォーマンス計測
iOSにおけるパフォーマンス計測
Toshiyuki Hirata4.4K views

Viewers also liked

JobStreamerではじめるJavaBatchのクラウド分散実行 by
JobStreamerではじめるJavaBatchのクラウド分散実行JobStreamerではじめるJavaBatchのクラウド分散実行
JobStreamerではじめるJavaBatchのクラウド分散実行Yoshitaka Kawashima
11.4K views51 slides
開発を効率的に進めるられるまでの道程 by
開発を効率的に進めるられるまでの道程開発を効率的に進めるられるまでの道程
開発を効率的に進めるられるまでの道程Takao Sumitomo
27.4K views52 slides
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben by
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
出来るチューリング完全!SQLでもいろいろ出来る! #syobobenkyon mm
6.4K views38 slides
Droid kaigiプレゼン by
Droid kaigiプレゼンDroid kaigiプレゼン
Droid kaigiプレゼンSuguru Oho
23K views56 slides
データモデルは時空を越える by
データモデルは時空を越えるデータモデルは時空を越える
データモデルは時空を越えるterahide
5.1K views39 slides
Android学ぶを君へ。生き抜くためのナレッジ共有 by
Android学ぶを君へ。生き抜くためのナレッジ共有Android学ぶを君へ。生き抜くためのナレッジ共有
Android学ぶを君へ。生き抜くためのナレッジ共有Shinobu Okano
61.2K views160 slides

Viewers also liked(16)

JobStreamerではじめるJavaBatchのクラウド分散実行 by Yoshitaka Kawashima
JobStreamerではじめるJavaBatchのクラウド分散実行JobStreamerではじめるJavaBatchのクラウド分散実行
JobStreamerではじめるJavaBatchのクラウド分散実行
Yoshitaka Kawashima11.4K views
開発を効率的に進めるられるまでの道程 by Takao Sumitomo
開発を効率的に進めるられるまでの道程開発を効率的に進めるられるまでの道程
開発を効率的に進めるられるまでの道程
Takao Sumitomo27.4K views
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben by kyon mm
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
kyon mm6.4K views
Droid kaigiプレゼン by Suguru Oho
Droid kaigiプレゼンDroid kaigiプレゼン
Droid kaigiプレゼン
Suguru Oho23K views
データモデルは時空を越える by terahide
データモデルは時空を越えるデータモデルは時空を越える
データモデルは時空を越える
terahide5.1K views
Android学ぶを君へ。生き抜くためのナレッジ共有 by Shinobu Okano
Android学ぶを君へ。生き抜くためのナレッジ共有Android学ぶを君へ。生き抜くためのナレッジ共有
Android学ぶを君へ。生き抜くためのナレッジ共有
Shinobu Okano61.2K views
プログラミング言語Clojureのニャンパスでの活用事例 by sohta
プログラミング言語Clojureのニャンパスでの活用事例プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例
sohta13.6K views
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について by Shinichi Kozake
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情についてあなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について
Shinichi Kozake7.4K views
DB設計でこだわりたい三つの要素 by Takahiro YAMADA
DB設計でこだわりたい三つの要素DB設計でこだわりたい三つの要素
DB設計でこだわりたい三つの要素
Takahiro YAMADA20.4K views
イミュータブルデータモデル(世代編) by Yoshitaka Kawashima
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
Yoshitaka Kawashima38.1K views
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 - by Yuki Anzai
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -
Yuki Anzai52.2K views
マテリアルデザインを用いたデザインリニューアル [フリル編] by YUKI YAMAGUCHI
マテリアルデザインを用いたデザインリニューアル [フリル編]マテリアルデザインを用いたデザインリニューアル [フリル編]
マテリアルデザインを用いたデザインリニューアル [フリル編]
YUKI YAMAGUCHI93.7K views
Asian Automation Alliance 自動化を進める・止めるにあたってのヒント by Takahiro Toku
Asian Automation Alliance 自動化を進める・止めるにあたってのヒントAsian Automation Alliance 自動化を進める・止めるにあたってのヒント
Asian Automation Alliance 自動化を進める・止めるにあたってのヒント
Takahiro Toku4.5K views
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん by Yukari Sakurai
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃんRetrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん
Yukari Sakurai18.5K views
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2] by bitter_fox
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
bitter_fox13.6K views

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

ソーシャルアプリ勉強会(第一回資料)配布用 by
ソーシャルアプリ勉強会(第一回資料)配布用ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用Yatabe Terumasa
1.5K views47 slides
React Native GUIDE by
React Native GUIDEReact Native GUIDE
React Native GUIDEdcubeio
1.3K views85 slides
Rx java x retrofit by
Rx java x retrofitRx java x retrofit
Rx java x retrofitShun Nakahara
991 views49 slides
社内勉強会資料(Varnish Module) by
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)Iwana Chan
7K views35 slides
Async Enhancement by
Async EnhancementAsync Enhancement
Async Enhancementkamiyam .
2.5K views71 slides
AndroidでDIxAOP by
AndroidでDIxAOPAndroidでDIxAOP
AndroidでDIxAOPnfc research
1.1K views26 slides

Similar to 絶対落ちないアプリの作り方(20)

ソーシャルアプリ勉強会(第一回資料)配布用 by Yatabe Terumasa
ソーシャルアプリ勉強会(第一回資料)配布用ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用
Yatabe Terumasa1.5K views
React Native GUIDE by dcubeio
React Native GUIDEReact Native GUIDE
React Native GUIDE
dcubeio1.3K views
社内勉強会資料(Varnish Module) by Iwana Chan
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)
Iwana Chan7K views
Async Enhancement by kamiyam .
Async EnhancementAsync Enhancement
Async Enhancement
kamiyam .2.5K views
15分でCakePHPを始める方法(Nseg 2013-11-09 ) by hiro345
15分でCakePHPを始める方法(Nseg 2013-11-09 )15分でCakePHPを始める方法(Nseg 2013-11-09 )
15分でCakePHPを始める方法(Nseg 2013-11-09 )
hiro3454.4K views
AWS SDK for Smalltalk by Sho Yoshida
AWS SDK for SmalltalkAWS SDK for Smalltalk
AWS SDK for Smalltalk
Sho Yoshida3.5K views
Inside frogc in Dart by Goro Fuji
Inside frogc in DartInside frogc in Dart
Inside frogc in Dart
Goro Fuji1.5K views
第三回ありえる社内勉強会 「いわががのLombok」 by yoshiaki iwanaga
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
yoshiaki iwanaga14.1K views
laravel x モバイルアプリ by Masaki Oshikawa
laravel x モバイルアプリlaravel x モバイルアプリ
laravel x モバイルアプリ
Masaki Oshikawa3.7K views
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション by Kazuhiro Hara
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC WebアプリケーションPlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
Kazuhiro Hara12.1K views
Scalaでプログラムを作りました by Tomoharu ASAMI
Scalaでプログラムを作りましたScalaでプログラムを作りました
Scalaでプログラムを作りました
Tomoharu ASAMI5K views
omoon.org の裏側 〜FuelPHP の task 活用例〜 by Sotaro Omura
omoon.org の裏側 〜FuelPHP の task 活用例〜omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜
Sotaro Omura10K views
Application Architecture for Enterprise Win Store Apps with DDD Pattern by Atsushi Kambara
Application Architecture for Enterprise Win Store Apps with DDD PatternApplication Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD Pattern
Atsushi Kambara3.1K views
マイクロサービス時代の生存戦略 with HashiCorp by Masahito Zembutsu
マイクロサービス時代の生存戦略 with HashiCorpマイクロサービス時代の生存戦略 with HashiCorp
マイクロサービス時代の生存戦略 with HashiCorp
Masahito Zembutsu5.8K views
20170422 azure portal cli 使いこなし by Takayoshi Tanaka
20170422 azure portal cli 使いこなし20170422 azure portal cli 使いこなし
20170422 azure portal cli 使いこなし
Takayoshi Tanaka312 views

More from Fumihiko Shiroyama

Firebase with Android by
Firebase with AndroidFirebase with Android
Firebase with AndroidFumihiko Shiroyama
1.9K views85 slides
RxJava - Subject 入門 by
RxJava - Subject 入門RxJava - Subject 入門
RxJava - Subject 入門Fumihiko Shiroyama
3.1K views66 slides
GCP HTTPロードバランサ運用例 by
GCP HTTPロードバランサ運用例GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例Fumihiko Shiroyama
8.9K views71 slides
GDG Tokyo Firebaseを使った Androidアプリ開発 by
GDG Tokyo Firebaseを使った Androidアプリ開発GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発Fumihiko Shiroyama
3.7K views73 slides
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ by
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFirebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFumihiko Shiroyama
7.6K views45 slides
AndroidでEither by
AndroidでEitherAndroidでEither
AndroidでEitherFumihiko Shiroyama
1.3K views20 slides

More from Fumihiko Shiroyama(10)

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