変な話ィ
SHIROBAKO Advent Calendar 2016 - Adventar 21日目。
「変な話ィ」という接頭辞でイライラさせてくれる茶沢信輔さん。
さらには勝手な発言で周りを巻き込み、責任転嫁、武蔵野アニメーション陣を「三下」よばわりする正真正銘のドクズです。
うん、この角度がなかなかうざい。
さて今回、大体その「うざさ」から批判される茶沢さんですが、彼のいいところを書いていこうと思います。
茶沢のいいところ
まとめ
編集のお仕事はこちら
おまけ
更新し忘れて、ないです
12kg
12kgは1歳男児、2歳女児の平均と同じくらいだそうです。
この3ヶ月ちょっとで12kg落とすことに成功したので、つまり僕は1歳男児 or 2歳女児を産んだということになります。 すごい。
大学入ってからの体重推移が激しすぎて、いつか身体を壊すのでは・・・?
年月 | 身長 | 体重 | 備考 |
---|---|---|---|
2010/4 | 184cm | 93kg | デブ |
2013/12 | 187cm | 115kg | クソデブ |
2014/4 | 187cm | 86kg | デブ |
2015/3 | 187cm | 89kg | デブ |
2016/3 | 188cm | 95kg | クソデブ |
2016/9 | 188cm | 102kg | クソデブ |
2016/12 | 188cm | 89kg | デブ |
※「階段を10段あがって息が切れないのがデブ、息が切れるのがクソデブ」です
新卒から見た、宮森あおいに見る責任感とマネジメント
この記事は SHIROBAKO Advent Calendar 2016 4日目です。 ハードルがどんどん上がってきているので、一回休み的な形で見ていただけるとありがたいです。
僕は武蔵野アニメーションの制作進行を務めるおいちゃんこと宮森あおいについて書きたいと思います。
※ 画像出展 キャラクター|TVアニメ「SHIROBAKO」公式サイト
宮森は新卒で武蔵野アニメーションに入り、1話時点で新卒1年目半年ほど、作中で2年目となり制作デスクを担当、そのまま最終話を迎えます。
経歴としては浅いですが、非常に優秀な制作進行・デスクとしてステークホルダーとの調整・仕事の割り振り・進捗管理等々の仕事をこなしています。
さて 1->2年目という流れの中で、その優秀さを見せつけてくれる宮森の「責任感」と類まれな「マネジメント能力」について、印象的なセリフを抜粋して書きたいと思います。
その前に・・・
序盤に見せる精神的な弱さ
宮森は他のキャラよりも多くの精神的な弱さ、精神的な軸のなさも表現されています。
特に序盤は成長前というところで軽く振り返ってみましょう。
「ドーナツ食べたいっ! ドーナツドーナツ!ドーンといきたいよぉ!」
1話。かわいい。わかる。
「私は、まだ具体的に何になりたいとか何がしたいとか目標がなくて。私には、何ができるのかなぁ。」
4話。
自分が仕事をする、していく上での悩みがこの自問自答にも見えるセリフに表れていますね。
しれっと会話相手である絵麻に褒めてもらいたい感じがかわいいです。
「なんだろう・・・私の最終目標って・・・」
7話。
ひとの最終目標なんて知らないけどかわいいですね。このシーンの前の絵麻の冷たい表情もいいです。
「みんな、夢とかあるんだな。」
8話。
そうなのかもわからないですが、かわいいなぁ。ハンドルになりたい。
圧倒的成長を遂げる責任感
さて、ここからが本題です。デスクになる直前辺りから一気に精神的に成長します。
まあ最初から仕事っぷりはおかしいと思うのですが、そこらへんは割愛して。
「今回は、最初に監督の考えを聞いておきたいんです。何がやりたいのか、どう作りたいのか。」
13話。2年目直前にデスクに任命され、そしてチームマネジメントとして最初にとった行動です。
アニメの制作には全く詳しくありませんが、プロダクトを作るという立ち位置で見ると、舵取りをする人の言葉や意識はそのままプロダクトの方向性に反映されます。
舵取り者(ここでは監督)が目指すプロダクトの方向性を把握することこそが、そのプロダクト制作において、そしてその進行を調整する立場として重要であることをありのまま伝えているわけです。
そして「今回は、」という言葉から制作進行のときの反省を活かし、より良いものを作ろうという意志が見て取れます。素晴らしい責任感です。
「ちゃんとコミュニケーション取って欲しいです。瀬川さんたちと。」
21話。平岡と瀬川さんの間に確執ができ、その仲裁をしたときのシーンです。
平岡の知り合いである磯川から「クリエイターと制作が共有出来る目標を一緒に粘り強く探し続けて落とし所を見つける事が大事なんだと思うね。こっちもクオリティーを大切にしてるかどうかって、ちょっとした事でクリエイターも感じ取れるんだよ。いい作品を作ろうと戦っているのはみんな同じなんだから」という言葉で宮森は吹っ切れます。
第三者から見てもコミュニケーションが取れていないという点、特に瀬川さんと取って欲しいという点、そして暗に瀬川さんたち以外ともコミュニケーションが取れていないという事実をつきつけながら、先に「コミュニケーションを取って欲しい」という想いを伝えるあたり、話術の才能を感じさせますね。
他者への敬意を持ち、正直に気持ちを伝え、そしてプロダクトを完成させるという「全員に共通するゴール」へ一直線で向かっている点が垣間見えます。
同じゴールを持ちながら、チームメンバーで足を引っ張りあい、争うことは非常に無駄な行為ですからやらないように気をつけたいです。
一緒に仕事をする人に対する敬意と信頼
この面に関しては、こんな人にマネジメントされたい・・・という思うくらい良いセリフが多々あります。
その中でも言われたいセリフ、そしてその考え方を真似したいと思える2つを抜粋しました。
「この仕事は杉江さんにしか出来ないと思います。」
12話。このセリフに出てくる杉江さんはベテラン作画であり、その腕は作中でも高い評価を受けていることが分かります。
そうは言っても「あなたにしか出来ない仕事をお願いしたい」「あなただからこそお願いしたい」という表現を腕が確かな人に、それも普段一緒の仕事場にいる人に伝えることは誰にでもできることでしょうか?
またその飾り気のないセリフに宮森の誠実さがよく現れていると思います。
しかもこれが1年目というのはもうマネジメント向きの人間性を備え付け過ぎです。
こんな言葉を貰ってみたいものですね。宮森に「この仕事はデブにしか出来ないと思います。」と言われたらめっちゃ頑張ると思います。
「でも絶対戻せないってことじゃないですから!」
22話です。
瀬川さんからの信頼を一度失ってしまった宮森。矢野先輩の言葉を受けてのセリフなのですが、見方によっては、信頼を失うことについて宮森が甘く見ているのではないかと先輩から釘を差されたとも言えるでしょう。
このセリフですが、その精神力もさることながら、瀬川さんの指摘が「感情」ではなく「仕事とその責任感」から来たものであることを理解していないとこの発言は出ません。
まあ太郎が喋っていたら「図々しい」と評されるのかもしれませんし、僕は思いますが。
余談ですが、このセリフでググるとヨリを戻したい人達の投稿がいっぱいでてくるので検索しない方がいいと思います。
先輩としての一面
2年目に入り後輩が入ってきたときの宮森。いい先輩になっています。
来年はこんなメンターになりたいですね、といいたいんですが当分機会がなさそうなので心の内に秘めておきます。
「新人の制作も入ったんです。裏道覚えたらどんどん間違った方法に頼るように・・・」
16話。「融通きかねえな新人は。原画進めておいて、作監作業で直せばいいだろ。これもぷるんぷるんするぞ」という平岡のセリフに対する返しです。
仕事・プロダクトに対する責任感や先輩としての責任感を見ることができますね。
宮森は目の前の仕事だけではなくその先を見ていて、間違った方法に頼ったとき将来的に評価等含めて困るのはまずその人、そしてその悪影響は波及し、この場合は一緒に働く人(特に作監)へと広がるところまできっちりと視野に入れています。
平岡から見ると柔軟性がないと捉えられている通り、個々人のボーダーが違うという点は当然です。だからこそ、その前提の上でしっかりと意見を主張できる点が素晴らしいですね。
「そのうっかりをちゃんと覚えておいてね。覚えておけば、次の失敗はないから。」
17話。新人が入ってきて、初歩的なミスをして落ち込んでいるときにしたアドバイスです。
ただの優しさのようにも見えますが、自分に対する言葉のようにも見えますし、またそこから今までの業務姿勢を見ることができます。
自分自身がその姿勢でいなければ、こんな一言は伝えられないでしょう。
まとめ
かわいい。一緒に仕事したい。餌付けしたい。
おまけ
制作デスクのお仕事についてはこちら。 制作デスクの仕事 | P.A.WORKS Blog
3rd party libraryとしてやってはいけないログ出力
問題 : 何も成功していないのに成功したといってしまう
I/art: Rejecting re-init on previously-failed class java.lang.Class<com.google.android.gms.common.api.Status> E/FirebaseApp: Firebase API initialization failure. java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at com.google.firebase.FirebaseApp.zza(Unknown Source) at com.google.firebase.FirebaseApp.initializeApp(Unknown Source) at com.google.firebase.FirebaseApp.initializeApp(Unknown Source) at com.google.firebase.FirebaseApp.zzek(Unknown Source) at com.google.firebase.provider.FirebaseInitProvider.onCreate(Unknown Source) at android.content.ContentProvider.attachInfo(ContentProvider.java:1748) at android.content.ContentProvider.attachInfo(ContentProvider.java:1723) at com.google.firebase.provider.FirebaseInitProvider.attachInfo(Unknown Source) at android.app.ActivityThread.installProvider(ActivityThread.java:5153) at android.app.ActivityThread.installContentProviders(ActivityThread.java:4748) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4688) at android.app.ActivityThread.-wrap1(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.NoClassDefFoundError: com.google.android.gms.common.api.Status at com.google.android.gms.internal.zzqf.<init>(Unknown Source) at com.google.android.gms.internal.zzqf.zzcb(Unknown Source) at com.google.android.gms.measurement.internal.zzn.zzwv(Unknown Source) at com.google.android.gms.measurement.internal.zzaa.initialize(Unknown Source) at com.google.android.gms.measurement.internal.zzx.<init>(Unknown Source) at com.google.android.gms.measurement.internal.zzab.zzbum(Unknown Source) at com.google.android.gms.measurement.internal.zzx.zzdo(Unknown Source) at com.google.android.gms.measurement.AppMeasurement.getInstance(Unknown Source) at java.lang.reflect.Method.invoke(Native Method) at com.google.firebase.FirebaseApp.zza(Unknown Source) at com.google.firebase.FirebaseApp.initializeApp(Unknown Source) at com.google.firebase.FirebaseApp.initializeApp(Unknown Source) at com.google.firebase.FirebaseApp.zzek(Unknown Source) at com.google.firebase.provider.FirebaseInitProvider.onCreate(Unknown Source) at android.content.ContentProvider.attachInfo(ContentProvider.java:1748) at android.content.ContentProvider.attachInfo(ContentProvider.java:1723) at com.google.firebase.provider.FirebaseInitProvider.attachInfo(Unknown Source) at android.app.ActivityThread.installProvider(ActivityThread.java:5153) at android.app.ActivityThread.installContentProviders(ActivityThread.java:4748) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4688) at android.app.ActivityThread.-wrap1(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) I/FirebaseInitProvider: FirebaseApp initialization successful
解決策 : 素直に失敗したことを認めましょう
`Error:Build-in class shrinker and multidex are not supported yet.`
色々と開発を進めていたところ、64K問題に引っかかってしまったので Multidexを有効にしたら以下のエラーに遭遇してしまった。
Error:Build-in class shrinker and multidex are not supported yet.
文字通り build-in class shrinker と multidex は同時使用できないよという話なんだけど、build-in class shrinkerを使うようにした覚えはない。
結果から言えば 「useProguard false
を明示的に呼ばない」だけで解決した。
proguard設定を作っていけば build-in class shrinker でもいいんだけれど、そうもいかない場合のために原因を一応探しておいたのでメモ。
まず、build-in class shrinkerを使うためには以下のAND条件を満たす必要があると思っていた。
- useProguard == false
- minifyEnabled == true
ところがそれは build-in class shrinkerによるcode minifyingを行わない状態になる、というだけであり、build-in class shrinker自体はavailableになるようだ。 このエラーはminifyする/しないを判定する以前に吐かれるらしいので、build-in class shrinkerがavailableなだけで駄目だったというわけ。
つまり「明示的にuseProguardをfalseに設定した時点で、minifyEnabledの値に関わらずbuild-in class shrinkerを利用していると認識される」ことが原因だった。
Support LibraryのPreferenceFragmentCompatでPreferenceScreenによる遷移を有効にする
TL;DR
- AppCompatActivityはもちろん、PreferenceActivityに載せても動かない
- 自前でハンドリングする必要があり、以下のいずれかの手法を取る必要がある。
- ActivityにOnPreferenceStartScreenCallback や OnPreferenceStartFragmentCallback を実装させる (Activity起動 or View使い回し)
- PreferenceFragmentCompat#onNavigateToScreen(PreferenceScreen) をoverrideする (上記をPreferenceFragmentCompat上で処理する用)
- boolean PreferenceFragmentCompat#onPreferenceTreeClick(Preference) をoverrideする (Fragment起動用)
PreferenceFragmentCompat
Support Library v23から導入された android.support.v4.Fragment をベースにしたPreferenceFragment。
3rd party ライブラリを使って凌いでいた人も多かったはず。
そして僕が気付いたのはv24.2.0なので今更感がある。
PreferenceScreenによる遷移が自動では処理されない問題
今までのPreferenceと同様、xmlによる構築が可能。
xml内にルートでないPreferenceScreenがある場合、そのPreferenceScreenをクリックすると新しい画面が開かれる仕様となっている。
公式リファレンスを見るとxmlにPreferenceScreenが書かれており、その子要素の注釈として、Next screenで表示されるものを記述できるぞ!と書いてある。
ということで、PreferenceFragmentCompatでもやってみたが、画面が開かれない・・・
でもIntentを記述するとちゃんと起動するので、click処理は諸々走っている様子。
A PreferenceScreen object should be at the top of the preference hierarchy. Furthermore, subsequent PreferenceScreen in the hierarchy denote a screen break -- that is the preferences contained within subsequent PreferenceScreen should be shown on another screen. The preference framework handles this by calling onNavigateToScreen(PreferenceScreen).
こうも書いてあるけど、これで「自分でハンドリングして」と読むのはちょっと厳しくない・・・?
とりあえず onNavigateToScreen はいつ呼ばれるのかというと、PreferenceScreen#onClick()
で処理されていた。
@Override protected void onClick() { if (getIntent() != null || getFragment() != null || getPreferenceCount() == 0) { return; } final PreferenceManager.OnNavigateToScreenListener listener = getPreferenceManager().getOnNavigateToScreenListener(); if (listener != null) { listener.onNavigateToScreen(this); } }
ちなみに PreferenceManager#getOnNavigateToScreenListener()
はPreferenceFragmentCompat自身を返し、それは OnNavigateToScreenListener
を実装している。
うーん、いやしかし、これを見ると中のListenerを呼ぶ条件は満たしている。
とりあえず、Intentは別の部分で処理されていると考えて良さそうで、分けて考えて良さそう。
一個一個自分でclick listenerをbindしてもいいけど・・・それは根本解決ではないし、今後困ってしまうので探してみる。
まずPreferenceScreenをクリックしたときに呼ばれる上述のlistenerの中身は以下のようになっている.(v24.2.0)
// in PreferenceFragmentCompat.java /** * Called by * {@link android.support.v7.preference.PreferenceScreen#onClick()} in order to navigate to a * new screen of preferences. Calls * {@link PreferenceFragmentCompat.OnPreferenceStartScreenCallback#onPreferenceStartScreen} * if the target fragment or containing activity implements * {@link PreferenceFragmentCompat.OnPreferenceStartScreenCallback}. * @param preferenceScreen The {@link android.support.v7.preference.PreferenceScreen} to * navigate to. */ @Override public void onNavigateToScreen(PreferenceScreen preferenceScreen) { boolean handled = false; if (getCallbackFragment() instanceof OnPreferenceStartScreenCallback) { handled = ((OnPreferenceStartScreenCallback) getCallbackFragment()) .onPreferenceStartScreen(this, preferenceScreen); } if (!handled && getActivity() instanceof OnPreferenceStartScreenCallback) { ((OnPreferenceStartScreenCallback) getActivity()) .onPreferenceStartScreen(this, preferenceScreen); } }
つまり以下の条件のうち一方を満たす必要がある。
- PreferenceFragmentCompat#callbackFragment is an instance of
OnPreferenceStartScreenCallback
- PreferenceFragmentCompat#activity is an instance of
OnPreferenceStartScreenCallback
で、じゃあそこらへんどうなってるんだっけ・・・っていうと
- PreferenceFragmentCompat#getCallbackFragment() は常にnullを返す
- Preference用のCompatActivityはないのでAppCompatActivityを使っていたが、当然実装してない
何もしてないやんけ。自前でハンドリングが必要だなぁ・・・。
とここまでやったところで記述を見つける。
・・・うぇい!
調べたら onPreferenceTreeClick と OnPreferenceStartFragmentCallback
周りも同じ感じだった。
実装方法の検討
じゃあどれが一番いいんだろう、と。
このdocによると、Activityに実装させる方法が正攻法っぽい。
他のやり方でもできそうなので色々調べてみる。
PreferenceFragmentCompat#getCallbackFragment()
のJavadocを見てみると
/** * Basically a wrapper for getParentFragment which is v17+. Used by the leanback preference lib. * @return Fragment to possibly use as a callback * @hide */
あー・・・なんか用途が違う。実現可能ではあるけれど、提供された目的と違う方法はあまり好ましくない。
なのでやるとしたら、まあ以下の通りになりそう。
- ActivityにOnPreferenceStartScreenCallback や OnPreferenceStartFragmentCallback を実装させる
- onNavigateToScreen(PreferenceScreen) をoverrideする
- boolean onPreferenceTreeClick(Preference) をoverrideする
- getCallbackFragment() をoverrideして、OnPreferenceStartScreenCallback や OnPreferenceStartFragmentCallback を実装したFragmentを返すようにする (本来の用途と違うのでやめた方がいい)
実装にあたって
気をつけないといけないことはいくつかあるが、PreferenceScreen
はParcelableでもなんでもないということを念頭に置く必要がある。
つまりそのPreferenceScreenをそのまま新しく作成するPreferenceFragmentCompatのインスタンスに渡して云々・・・は出来ない。
備忘録も兼ねて、いくつか思いついた実装を書いておく。
OnPreferenceStartScreenCallback
- Fragment, Intentが設定されておらず、そのPreferenceScreenは1個以上の子要素を持つことが保証されている。
xmlに書いたPreferenceScreen(子孫)に表示したい全ての要素が記述してあるとき
PreferenceFragmentCompatを再利用する
boolean onPreferenceStartScreen(caller: PreferenceFragmentCompat, pref: PreferenceScreen) { if (pref.getKey() == null) { return false; } caller.setPreferencesFromResource(R.xml.setting, pref.key); return true; }
どこからか、利用されているxmlのidを拾ってくる必要はあるが、PreferenceFragmentCompatの使い回しができる。
けどback処理が面倒くさそう。
PreferenceFragmentCompatを新しく作る
class HogeFragment extends PreferenceFragmentCompat { static PreferenceFragmentCompat newInstance(String rootKey) { PreferenceFragmentCompat fragment = new PreferenceFragmentCompat(); Bundle bundle = new Bundle(); bundle.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, rootKey); fragment.setArguments(bundle); return fragment; } void onCreatePreferences(Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.setting, rootKey) } } // ↓ Activityで実装する boolean onPreferenceStartScreen(caller: PreferenceFragmentCompat, pref: PreferenceScreen) { if (pref.getKey() == null) { return false; } getSupportFragmentManager().beginTransaction().replace(R.id.container, HogeFragment.newInstance(pref.key)).addToBackstack(null).commit(); return true; }
どんなFragmentで扱うかを知っている必要がある。Fragment attributeを設定してしまうと、ここが呼ばれないことを留意する必要がある。
PreferenceScreenのkeyとxmlのid名を対応させる
boolean onPreferenceStartScreen(caller: PreferenceFragmentCompat, pref: PreferenceScreen) { if (pref.getKey() == null) { return false; } int id = getResource().getIdentifier(pref.getKey(), "xml", getPackageName()); caller.addPreferencesFromResource(id); // lint抑制をする return true; }
ゴリ押し。PreferenceFragmentCompatの使い回しができる。けどやっぱりback処理が面倒くさそう。
試してないけど。
OnPreferenceStartFragmentCallback
- Fragmentが設定されていることが保証されている。
Fragment名から愚直に作成する
boolean onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference) { if (!(pref instanceof ScreenPreference)) { return false; } String fragmentName = pref.getFragment(); // name に合わせてFragmentを生成して色々する return true; }
普通っぽい。
Android上でANTLR4がこける問題。
GraphQLライブラリのgraphql-javaをAndroidで動かそうとしたらANTLR4周りでこけた。
dexOptions.preDexLibraries = false
で直るよ!とかあったけど試したらエラーが増えたし、これで直るならcleanでも直りそうなもんですよね・・・
結局ANTLR4のバージョンが低くてgui依存周りがこけてるだけだったので、ANTLR4を更新しておけば解決した。
ref: https://github.com/antlr/antlr4/issues/1160
compile('com.graphql-java:graphql-java:2.1.0') { exclude group: 'org.antlr' } compile group: 'org.antlr', name: 'antlr4-runtime', version: '4.5.3'
でも結局deserializeに利用できそうになく、とりあえず依存から廃した。 一応備忘録的な感じで残しておく。
compile('com.graphql-java:graphql-java:2.1.0')