CA Tech Dojo(AndroidアプリKotlin編)という最高のインターンで最優秀賞をもらった話
題目の通り、CyberAgentのCA Tech Dojo(AndroidアプリKotlin編)に参加してきました。
そして、最優秀賞いただいちゃいました!
www.cyberagent.co.jp
運営からメンターさん、インターン生まで全てが本当に最高のインターンだったので、2週間を振り返りながら色々書いていきます。
機密に触れないのであれば、どんどん書いちゃってと言ってくださったので、どんどん書きます笑
来年以降、また開催されることがあれば、参加を検討している学生に参考になればと思います。
自己紹介
自分がどういうバックグラウンドを持っていて、どういう意図でこのインターンシップに参加したかをお話しします。
興味ないよって方は飛ばしてご覧ください。
プログラミング歴
2019/08/17現在のこのブログ自体のタイトルにもあるように、現在情報学部ではなく、趣味でプログラミングをやっています。
授業で少しCをかじっていた程度で、プログラミング自体を始めたのは実質2019/01くらいです。
始めはJavaから始め、他のサーバーサイドやフロントなどのWeb系は一切触っていませんでした。
子供達にプログラミングを教える長期インターンの関係で6ヶ月ほどAndroidをJavaで触っていましたが、Kotlin firstとなった今、ずっとKotlinで開発したいと思っていました。
android-developers.googleblog.com
参加の流れ
そんな中、実力的にも時期的にもちょうど良いtech dojoが開催されることを知り、即座に申し込みました。
グレーゾーンなので面接の内容とかはあんまり言及できないのですが、選考スピードもめちゃめちゃ早くて、
「ああ...これがサイバーエージェントか...!!」
って感動したのを覚えています。
参加が決まってから実際に当日を迎えるまでに約1ヶ月ほどありました。
このインターンシップのテーマが
プログラミング経験のある学生を対象に約2週間でAndroidアプリ開発の基礎スキルを身に着けていただくキャンプ形式のインターンです。
事前課題やハンズオン形式の学習で理解を深め、活躍する現場社員に質問しながら、課題に沿ったAndroidアプリを完成させることを目指していただきます。
「1人でアプリを開発しリリースできるようになる」というゴールを達成できるようなものを想定しています。
という養成型プログラムでした。
要約すると、
「Androidの経験はないけれど、サーバーサイドやiOSなどの開発をしてきた人たちが、2週間でAndroidアプリを1人で作れるようになる」
というコンセプトです。
とはいえ、自走力が必要なので、この1ヶ月の間にAndroidの基礎や、Kotlinの基礎を叩き込んでおくのは必要不可欠です。
インターン参加後に参加者達が口を揃えて
「もっと基礎を勉強していればよかった」
と言っていました。
せっかく現場の前線で活躍されているプロのAndroidエンジニアの方にメンターとしてついていただくのに、
基礎の基礎ばかりを聞いてしまっては時間がもったいないという意味です。
tech dojoに参加を検討している方は、少なからずKotlinに、Androidに興味を持っていると思うので、
そこを興味だけでなく行動に落とし込んで、事前学習してから参加することを強くお勧めします。
得られるものの大きさがだいぶ違うので。
参加するにあたって
自分は、Kotlinはあまり触ったことがなかったですが、Android開発経験はありました。
拙作ですが、プログラミングを始めてから約4ヶ月ほどでPlay Storeにアプリをリリースしたことがあります。
恋人用に作ったのであまり拡散はしていませんが...笑https://play.google.com/store/apps/details?id=com.kurus.kawakasuchan
そのため、ある程度の基礎や簡単な流れは分かっていました。
ですが、完全に独学で学んできたので、現場のプロであるメンターさんに質問できる環境に憧れてこのインターンシップに申し込みました。
(本当に申し込んで大正解でした)
せっかくの機会なので、ただ脳死で参加するだけではなく、目標を決めて参加しようと心がけ、インターンシップ期間中はこの目標を常に意識して取り組んでいました。
- 設計を意識した開発
- 要件を満たすだけなら簡単かもしれないけれど、実務を意識して初めから設計を取り入れ、メンターさんにアドバイスをもらいたかった。
- 大人数開発を見越したgitの扱い
- 基本的には単独で開発をするのですが、機能ごとにbranchをきってプルリクエストを投げたり...(自分で承認するけど笑)
- 質問の質
- エラーが出たからすぐ質問するという姿勢ではなく、自分で調べうる解決策をいくつか試した上で、自分の考えを持った上で質問する。
- そうすることでメンターさんも「何がわかっていて」「何を教えてもらいたいか」が明確にわかるので互いにWin-Winかなと。
- 繋がりを大事に
- 積極的に参加者や社員さんと話し、仲良くなる。
- 横のつながり:情報系学部じゃなかったし、学生のAndroidエンジニアが少なかったから友達欲しかった...
- 縦のつながり:つよつよエンジニアやバチイケな社員さんとお話ししてモチベーションあげたい
自己評価ですが、結果的にこれら全て大成功でした。
やっぱり目標もって取り組むことは大事だなと思いました。
というわけでここまでが自己紹介諸々でした。
次章からインターンシップの内容に言及します。
インターンシップ内容
上述したように、このインターンシップでは、2週間で、Androidアプリを「1人」で開発してリリースできるようになることが目標なので、基本的には与えられた課題を1人で開発します。
そして、わからないことや、躓いたところがあればSlackもしくは直接メンターさんに質問できるような内容です。
参加者は今回が16名で、4人組×4班に別れて、それぞれの班に1人メンターさんがつくような形です。
個人開発だけど班に別れる理由はおそらく、
- メンターさんが教えやすいため
- 参加者同士で教えあえるため
- 参加者の仲を深めるため
でしょうか。
実際、各班プログラミング歴長めの人であったり、Android経験者がうまい具合にバラけていたのでそんな感じだと思います。
本章では、開発に関してと、それ以外のランチや社内見学などを分けて記述していこうかと思います。
開発
ここまで読み進めていただいても、正直まだインターンのイメージを掴めていない人は多いと思います。
なので、実際にどういった課題だったかと、自分がどんな物を作ったかを簡単にご紹介します。
課題内容にも特に機密は含まれてないそうなので、ブログに書いちゃっていいそうです。
さすがです。
課題内容(プロフィール交換アプリ)
16名全員が同じ内容の課題にチャレンジします。以下の要件をクリアしていれば、他にどんな機能を付け足そうと、どんなUIにしようとそれは個人の自由となります。
そのため、コードにも見た目にもオリジナリティが生まれる内容となっています。
実際には、自身のプロフィールをQRコードを使って交換するアプリを作成します。 プロフィールに含む情報は以下のとおりです。
これらの情報を元にQRコードを生成し、これを他人に読み取ってもらうことで自分の情報を渡せるようにします。
読み取った側は、それらの情報を永続化した上でリスト表示できるようにします。
そして、交換した人のアカウント名をタッチするとそのWebページをアプリ内で見れるようにします。
要するに、インターン生同士でQRコードを読み取り合って自身のプロフィールを交換する、いわゆる名刺交換のようなアプリを作りました。
お互いにアプリが入っていないと機能しませんが笑
以下は自分の作品です。UIは最終日に徹夜で間に合わせたものなので、ところどころ残念ですけどご容赦ください。
fabとか色合いひどい...笑
要件以外での機能面のオリジナリティとしては、
ですかね。
機能よりも実装(コード)面で力を入れました。実装面で指定というか推奨されていたのは、SQLite、RecyclerView、WebView程度だったので、使ってみたいやつ全部使っちゃいました。
- Navigation/Jetpack(画面遷移)
- Databinding(MyProfile画面とか)
- Kotlin Coroutine(非同期処理)
- ViewModel/Jetpack(MVVM)
- Room(データベース)
- Glide(画像処理)
- Dagger2(DI)
- Retrofit/GSON(API)
設計の構造は以下の通りです。発表資料のくりぬきで。
よくあるMVVMのカタチですね。
これまでudemyとかで写経学習はしたことがあるのですが、MVVMを自分で1から実装するのは初めてだったので、責務の分離とか、Dagger周りがかなり難しかった...
理解しづらい概念もメンターさんに聞くと抜群にわかりやすい回答が返ってくるので、この機会にやって正解でした。
とはいえ、2週間で要件を満たす必要があるため、初めから上記のライブラリを全て使うのではなくて計画的導入するなどの工夫が必要でした。
はじめに定めた目標である、設計にこだわること、つまづいても色々試してみてからわからない点を言語化して質問することを意識しながら開発を進めていきました。
その結果、🏆最優秀賞🏆として選出していただきました。
めちゃめちゃ嬉しいです。いまだに余韻がすごい...。
もらったabemaくんのバンカーリング可愛い。
モダンなライブラリを計画的に使い、実装仕切ったところや、インターンシップの取り組み姿勢を評価していただいたそうです。
嬉しい。
まだプログラミングは始めてから半年ちょいですが、本業の材料系の研究そっちのけでAndroid開発にハマって毎日触ってきたのが報われた感があって興奮しています。
文面では伝わらないかもしれないですけど、しています。
実は、一度大阪に戻った時に休学届けを出してきました。東京でAndroidエンジニアとして経験を積みたいと思って。
大学院では、材料系の研究と経営学を学んでいるのですが、忙しすぎてどちらも中途半端になっていたので、この機会にと思い決意しました。
10月からはインターンが決まっていないので、どこかで長期インターンしたいなあ。
ということで、開発面はこれくらいにして次からは日常生活や雰囲気をお伝えできればと思います!
長いですけどもう少々お付き合いください。
開発以外
雰囲気とか
雰囲気は総じてめっちゃ良いです。本当に良かった。
良かったって言えとかいわれてないです。ほんとうに、よい。
とにかく社員さんの人柄が抜群によくて、
今回の運営責任者である、ななさん(@utsu_nana)をはじめとした人事のみなさんの暖かさであったり、
メンターさん4名だけでなく、業務中に遊びにきていただいて質問にも快く答えてくださった最強のAndroidエンジニアさん。
本当に全員が優しく、そして本気でこのインターンシップを良いものにしようという雰囲気が感じられました。
先生と生徒とか、社員と学生、みたいにガチガチな関係を強いられるのではなくて、学生も大人として扱っていただけるし、すごくフランクに話しかけてくださるので、伸び伸びと2週間が過ごせました。
そしてインターン生の仲の良さ。
これは自分で言うのもなんなんですけど、人との繋がりを大事にするっていう目標を意識して、ほぼ毎日チームビルディングもかねて退勤後にインターン生とご飯に行くっていう流れを作ったの最高に良くないですか??笑
蒙古タンメン行ったり焼肉行ったり、飲みに行ったりして毎日楽しかった。
その代わりお金がなくなったのと、太った感じするのが副作用。
業務中
社食連れて行ってもらったり、(人事のゴッティさん(@masagotty)の山盛りカレー)
社内見学行ったり
(社長室)
毎日お弁当とか、連れて行ってもらった渋谷ランチ美味しかったり
(写真撮るの忘れた...)
至れり尽くせりの毎日でした。
サポーターズの逆求人イベントに参加した話
こんにちは!ほりすです。
今回、東京で開催されるサポーターズさんの逆求人イベントに参加させていただいたので、イベント全体の流れと感想を話していこうと思います。
自分のレベル感としては、研究で少しC言語、Javaをかじっていました。
ですが、本格的にプログラミングを始めたのは割と最近です。
本格的にプログラミングを始めてからは5ヶ月目です。4回生でかじって年末からM1にかけてって感じですね。(遅い)
1つAndroidアプリをリリースしたので、戦える土俵には立てたのかなと思い今回応募しました。
つよつよエンジニアだけど、逆求人イベントには行ったことがない。
とか、
技術力に自信がないけど行っていいの?と迷われている方
を対象に書いています。
興味があれば是非読んでみてください!
申し込みの流れ
登録
まず、サポーターズに登録していない方は登録しましょう。(あたりまえ)
登録したら、プロフィールを埋めるよう促されますので、
を記入します。
ここをしっかり記入しないと、イベント募集メールが来なかったり、事前ヒアリングで選考に落ちてしまうので気を付けましょう。
応募
記入ができたら、僕の場合はサポーターズ側から「逆求人イベントに参加しませんか?」といったようなメールが届きました。
応募すると、プロフィール欄に沿った簡単な選抜をするための日程調整をメールでやり取りするフェーズに入ります。
選抜とはいえ、簡単なヒアリングをするだけなので気負わなくても大丈夫かと思います。
当日
企業プレゼン
まず、事前アンケートの記入や注意事項を聞き、
企業さんの全体プレゼンに移ります。
プレゼンは1企業さんにつき2分なので、インプットできる情報は限られてきます。
あらかじめ、どんな企業が来るのかを把握し、少しでもネットでチェックしておくと当日焦らなくてもよくなるのでお勧めですね。
今回は飛び入り参加企業さんも含めて15社いらっしゃったので、なかなか情報整理が大変でした。タイピングスキル大事だなー。
名刺交換会
「名刺なんてもってないよ!!」
という方もご安心を。
サポーターズ側で名刺は用意してくださっています。
企業の方と名刺交換する時間が1~2分×企業数ありますので、疲れますが笑顔を絶やさず乗り切りましょう。
ファーストインプレッション大事です。
この名刺交換会のメリットとして、初めは面談希望度が低かった企業さんも意外と良いかもって思えることです。
自分の場合はその会社で働く「人」も、会社選びの1つの重要要素なのでよく観察しました。
名刺交換会が終われば、学生と企業が、互いに匿名で面談希望度をアンケートに記入します。記入後、特別なアルゴリズムでマッチングされます。
面談開始
最初の5分の印象が大事です。
笑顔を絶やさず、視線を合わせてハキハキと話すことを意識していたら自然と会話が弾み、25分はあっという間でした。
自己紹介スライドではパワポを使用したのですが、笑いを引き起こすようなネタも入れたのですが、ちゃんとウケて安心です(笑)
「周りのつよつよエンジニアと比較すると、技術面では劣ってしまうのですが、今回は考え方をメインに知っていただければと思います。」
ということを冒頭に伝えていたため、フィードバックも考え方に関して共感頂けたり、アドバイスをいただいたりしました。
初回の企業さんにはパワポを褒めていただけたのでそれ以降のプレゼンは自信がもてました。
......
『乾かすちゃん』のプライバシーポリシー
『乾かすちゃん』のプライバシーポリシー
・マイク
→外部からの音を取得するために使用します。
以上。
【Android】 「Compilation failed; see the compiler error output for details.」の解決方法
今日も今日とてオリジナルアプリを作成していました。
珍しくすらすらコードが書けて、これ、いいじゃん!ってrunした際に見舞われた、自身を打ち砕いたエラーです。
吐き出されたエラーは、
「Compilation failed; see the compiler error output for details.」です。
コンパイラが調子悪いのか?でも具体的なエラー内容は書いてないし、Invalidate / Cashesや、Clean Projectしても直らない、、、と悩んでいました。
エラー箇所を明示してくれない、初心者殺しのエラーに同じく遭遇された方へ向けて自分がやった解決方法を記します。
お力になれたら幸いです。
解決方法
stackoverflow等で検索したところ、
①まず、settings -> Build,Execution,Deployment -> Debbuger ->Compiler
と移ります。
※settingsの検索windowでCompilerと打ったほうが速いです。
②そして、Command-line Optionsに --infoと打ち込み、Apply
③ツールバーでBuild ->Toggle viewとすると、エラー内容が分かりました。
以上、めげずに頑張りましょ~
【Android】FragmentでDialogFragmentを使う
自作アプリを作る際、Fragmentで購入ボタンを押したらダイアログを表示させたかったのですがうまくいかず、2~3時間ほど悩んでいたので、解決までに歩んだ道のりを備忘録として記したいと思います。
困っていたこと
購入ボタンを押したらダイアログは表示されるのですが、OKボタンを押すとdialogFragmentListener.onDialogPositiveButtonClicked()の行でClassCastExceptionが投げられる。
以下が変更前のコード。
public class MyDialogFragment extends DialogFragment { private DialogFragmentListener dialogFragmentListener; public interface DialogFragmentListener{ void onDialogPositiveButtonClicked(); } public MyDialogFragment newInstance(DialogFragmentListener dialogFragmentListener){ this.dialogFragmentListener = dialogFragmentListener; return new MyDialogFragment(); } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity()) .setTitle("購入") .setMessage("購入しますか?") .setPositiveButton("購入する", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialogFragmentListener.onDialogPositiveButtonClicked(); } }) .setNegativeButton("やめる", null); return dialogBuilder.create(); }
解決までの道のり
えっ、クラスキャストできてないの?とひたすらDialogFragmentについて調べていたら、どうやらActivityから使用するDialogFragmentと、Fragmentから使用するのとでは違うみたいでした。
@Override public void onAttach(Context context) { super.onAttach(context); Fragment targetFragment = this.getTargetFragment(); try{ if(targetFragment != null){ dialogFragmentListener = (DialogFragmentListener)targetFragment; } }catch (ClassCastException e){ throw new ClassCastException("DialogFragmentListenerをimplementしていません"); } }
上記のコードを追加し、Fragmentからも呼び出せるようにした、、つもりだったが、今度は同じ行でNullPointerExceptionが投げられた。
どこでぬるぽが起きているのかをDebugモードで見てみたところ、onAttach内のtargetFragmentがnullということが分かりました。
public MyDialogFragment newInstance(Fragment fragment){ MyDialogFragment instance = new MyDialogFragment(); instance.setTargetFragment(fragment, 0); return instance; }
を追加して解決しました。
TargetFragmentに呼び出し元のFragmentを渡してあげないといけなかったみたいですね。
ようやく解決したのでとりあえずはよかった...。
【Android】Manifest merger failedとかいうエラーの解消法
発生したエラー
以前udemyで作成したAndroidアプリのプロジェクトを開き、gradleのアップデートをしたところ、
Manifest merger failed : Attribute application@appComponentFactory value=(android.support.v4.app.CoreComponentFactory) from [com.android.support:support-compat:28.0.0] AndroidManifest.xml:22:18-91 is also present at [androidx.core:core:1.0.1] AndroidManifest.xml:22:18-86 value=(androidx.core.app.CoreComponentFactory). Suggestion: add 'tools:replace="android:appComponentFactory"' to <application> element at AndroidManifest.xml:5:5-30:19 to override.
とかいうエラーが出てきた。
本記事は、その解消法を備忘録として残したいと思います。
同じエラーで苦しんでいる方のお力になれれば幸いです。
解決方法
結論から先に言うと、
①【gradle.properties】に
android.useAndroidX=true android.enableJetifier=true
を記載。
②MainActivity等の、AppCompatActivityを継承しているファイルを開き、
import androidx.appcompat.app.AppCompatActivity
をインポートする。
③layoutファイルでConstraintLayout棟のサポートライブラリを使用している場合は、
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" > //省略 </androidx.constraintlayout.widget.ConstraintLayout>
と書き換える。
音を検知する【Android Studio】
はじめに
初めて開発中のオリジナルアプリで端末のマイクから音を検知し、さらに音量を取得する必要があったので、そのやり方を調べました。
自分の記憶を定着させるためのメモ程度に書きますのであしからず。
パーミッション
音量の感知にはRECORD_AUDIOのパーミッションが必要。
AndroidManifest.xmlに
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
を追加。
API16以降ではpermissionを記述しただけでは適用されず、端末の設定からマイクのpermissionをONにしなければなりません。
その他にもアプリ起動時にpermissionを求める記述もありますが、簡単のため今回はこの方法でやりたいと思います。
音の検知
AudioRecordクラスを使用することで、マイクからの入力を波形データとして取得可能とのこと。
リアルタイムで音声を扱うには、UIスレッドで行うのではなく、別のスレッドを立てるらしいです。
Androidの公式リファレンスより、AudioRecordクラスのコンストラクタは
public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)
とされていますが、何が何だかわからない。これはこういうものだ、とおまじないのように記述するのでも良いがせっかくなのでなんとなくでも意味を理解したい。
1つ目の引数は録音元。MediaRecorder#AudioSourceを充てる。今回はMicrophone audio surceであるAudioSource#MICを使用する。
2つ目の引数はサンプルレート。定数SAMPLE_RATEに予め8000(80kHz)を代入しておく。
3つ目の引数はオーディオチャンネルの設定。AudioFormat#CHANNEL_IN_MONOと、AudioFormat#CHANNEL_IN_STEREOがあるが、前者だとすべてのデバイスで動作することが保証されているため、ここではおとなしく前者を適用。
4つ目の引数はオーディオデータが返されるフォーマット。AudioFormat#ENCORDING_PCM_8BIT、AudioFormat#ENCORDING_PCM_16BIT、AudioFormat#ENCORDING_PCM_FLOATがある。16BITを選択。
5つ目の引数は録音中にオーディオデータが書き込まれるバッファの合計サイズ。AudioRecord#getBufferSizeで、AudioRecordのインスタンスを作成するための必要最低限のバッファサイズを決定する。
流れ
①AudioRecordのインスタンス化。
②AudioRecord#startRecordingで録音の開始。
③AudioRecord#readで端末からオーディオデータを読み込んでshort or float or byteの配列に記録する。
④AudioRecord#stopで録音停止。
⑤AudioRecord#releaseでAudioRecordリソースを開放。これ重要。
MainActivity.javaでの実装
アプリ内で複数のアクティビティがある場合は、アクティビティの切り替えに応じて録音を開始したり止めたりを考えます。
これについては、Androidのライフサイクルにおいて、他のアクティビティから戻ってきた際に呼ばれるonResumeメソッドと、他のアクティビティに移る際に呼ばれるonPauseメソッドを活用します。
onResume()内では、音を感知するクラスをインスタンス化し、Handler#post()で処理内容を書きます。
そして、Threadを立てて録音開始。
音を感知するためのSoundDetectionクラスと、OnVolumeListenerは自分で作成します。ここでは省略。
//他のアクティビティから帰ってきたときに呼ばれる @Override protected void onResume() { super.onResume(); soundDetection = new SoundDetection(); soundDetection.setOnVolumeListener(new SoundDetection.OnVolumeListener(){ //音を感知したら呼び出される public void onReachedVolume(short volume){ //別スレッドからUIスレッドに処理を投げる handler.post(new Runnable() { @Override public void run() { //なにかしらの処理 } }); } }); //別のスレッドとして録音開始 new Thread(soundDetection).start(); }
onPause()内では、録音を止めるために自作クラスのSoundDetectionクラスで作成したstop()メソッドを呼び出します。
//他のアクティビティに移ったときに呼ばれる @Override protected void onPause() { super.onPause(); //録音停止 soundDetection.stop(); }
今日はここまで。