Retrofit使ってて詰まったところとか

詰まったところを共有していこうかなって。

しょっぱながJsonArrayから始まってた

stackoverflow.com
Jsonがいきなり[]から始まる奴のパースの仕方。
Kくんも困ってたこの問題、自分はちゃんとこれで解決できた。
てか、普通に{}で始めてほしい...

MailAddressをPOSTする時

エンコードしろって怒られる。
@FormUrlEncoded
使うか、ちゃんとエンコードして渡せばいけた。

叩いたAPIがリダイレクトするのを無視したい

stackoverflow.com

final OkHttpClient client = new OkHttpClient();
client.setFollowRedirects(true);

これをRestAdapterにセットしてあげれば行ける。
ちょっと闇感じる。
てか、リダイレクトして帰ってきた奴はfailureに行くのかな?
ここら辺よくわかなんないけど、パス!

JsonのKeyが動的に変わる

stackoverflow.com
普通に変わるやつをMapで置けばいいだけだった。
Map#keysetか何かでKey一覧取れるし、Valueもちゃんととれていい感じ。
Map最強。
Gsonに少し詳しくなった。

GETの時のデフォルトのパラメータのセット

github.com

@GET(Const.API.NEW_LIST + "?order=new")
void getNewList(CallbackNewrList> callback);

GETの時はURLに含められるけど、POSTの時はどうすればいいんだろう。
前は@QueryParamみたいなのがあったらしい。
今はどうなんだろう。

パラメータにNull渡した時の挙動

POSTでもGETでもQueryやFieldにNull渡した時はRequestに含まれないらしい。
非常に便利。
必須パラメータだけ@NonNullアノテーションつけたら非常に良い運用ができそうな気がした。

最後に

RetrofitなしじゃAPIを叩けない体になった。
Retrofitマスターに俺はなる!!!!!

addViewしていったら追加したViewが横に並んでいき、横いっぱいになったら改行してくれるViewGroup

「addViewしていったら追加したViewが横に並んでいき、横いっぱいになったら改行してくれるViewGroup」
が必要になったからちょっと作ってみた。

gist.github.com
作ってて思ったんだけど、onLayout内の指定の仕方、なぜrightとbottomを基準にしたんだろう。
ま、これでやりたいこと出来てるからいいけど。

こういうViewGroup、なんだかんだ必要な時が多いから便利そう。

おわり

ScrollViewの中に入れても平気なListView

LinearLayoutにaddViewしただけのようなパフォーマンスを発揮するListView
Viewの再利用とは何だったのか
使い道がわからない

gist.github.com

stackoverflow.com
コレ、パクった

onMeasureでカラム数とViewのサイズとってsetMeasuredDimensionやってもうまく行かなかったけど、確かにLayoutParamに直接指定すればうまくいった。

アレだ、なんかのモック作ってる時に最初はListViewでやってたけど、注文が多くてScrollViewで囲わないといけなくなって、今更LinearLayoutに置き換えてaddViewするのめんどいって時に使える。
おすすめしないけど。

おわり

ADF2015に参加してた

参加してた

recruit-jinji.jp
これに参加してましたー。

いろいろ一回り二回りしたらスタッフ扱いになりイベントを少しだけ手伝う要因になりました。
ワタシ、ナイテイノタメニ、ガンバル

スタッフだったのであまり各セッションの内容を知らず、実はあまり書けることがないというのが...
Application Developer Festival 2015参加録 | でぶだるまは赤だるま
ココらへんとかに書いてくれてあります。

最終日のハッカソン

これだけはスタッフにも参加が許された唯一のものでした。

優勝しました
賞品もらいました
あざっす

https://fbcdn-sphotos-f-a.akamaihd.net/hphotos-ak-xfp1/v/t1.0-9/s720x720/17191_1584042065169358_7387450423242943936_n.jpg?oh=de5d6b8c990f5c5eac1986550ba11c9d&oe=55BE7B11&__gda__=1438362756_76d99e81be448f6bf5246411aa3a85fe
https://fbcdn-sphotos-d-a.akamaihd.net/hphotos-ak-xpf1/v/t1.0-9/s720x720/11041820_1584152888491609_4213592080690837939_n.jpg?oh=24a048e63615508ba76715c547c3df82&oe=55749215&__gda__=1436980670_b4309ba1cbd27018d0c779f5767d15bf


発表スライドがこちら

www.slideshare.net
GoogIe(ぐーぎぃ)というサービスっぽい何かを作った感じです。
iWatchという卑猥なデバイスを作り、iTurnという卑猥なデバイスを作り。
多分近々動画も出てくるのではないかなと思うのでそのうち紹介しますー

最後に

ま、なんというか、リクルート主催のイベントなんですが、リクルートという単語をあまり聞かず、そういう就活イベントみたいな感じではない所、かなり良かったです。
あと、公式サイトに書いてあった内容は達成出来てると思いますねー。
強いAndroiderに出会えました!!!!!

成功するか絶妙なラインで攻めてたあたり"第一回"という感じがして面白かったです。
エンジニアのことを少しわかって、色んな所からうまく手を回している人事の努力が一番成功に近づいた要因だと思いますね! (ナイテイクダサイ)
春の長期インターンの時(ナイテイクダサイ)や今回のイベントの前日に見た目のクマから(ナイテイクダサイ)色々と心配なところや(ナイテイクダサイ)遅くまで(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)(ナイテイクダサイ)

楽しかった、ありがとう、リクルート
仕方ないから留年して来年もイベントに参加しようと思います!!!!!!!

ではではー

追記

www.gizmodo.jp

Android TVアプリ開発について(╬ ꒪⌓꒪)

書いた

AndroidTVアプリの開発事情 | リクルートライフスタイル開発者ブログ

これ、書いたんですが、もう少しだけ噛み砕いた言葉で色々と書きたい!!!!
とりあえず、


Android TV入門 - Qiita

amyu/androidtv-Leanback at createRecommendationContentProvider · GitHub

この2つ読めば開発できるかなーって。
色々ごちゃごちゃ書いたんですが、一番良かったのがサンプルを読むことだったという。
で、一番注意して欲しいRecommendation CardにFocusが当たった時の処理はContentProvider作成して、取り出さないと表示されないという点ぐらいです。
凝ったことをしない、ゲームを作らないぐらいだったらサクッと実装できるかなって思います。

激おこな点

Youtube API使用できないっぽいんですよー。
激おこ。
Android TVなのに!!!!

Issue 4585 - gdata-issues - YouTube Android Player API INTERNAL_ERROR on Google TV - Server-side issues and feature requests - Google Project Hosting
GoogleTVに来てたIssueなんですが、追加でAndroidTVも無理だよ的な雰囲気なことが書いてあって...
はー。

(╬ ꒪⌓꒪)

最後に

Google TV化しなければいいね!!!!!!

追記

YouTube Player API Reference for iframe Embeds - YouTube — Google Developers
コレ使えば行ける。
(実装したくない)

ListViewの子要素をTouch座標から求めるやつ

つくった

https://camo.githubusercontent.com/b6b4851e8127062a34071eeeb9a39292765baab7/687474703a2f2f692e6779617a6f2e636f6d2f38373263343165613566663265643135313638393263373063613530616263622e676966
コレ結局Dragしてる最中のTouch座標でListViewの子要素の位置を特定して、取得した子要素の大きさで緑色のViewをその位置にaddViewしてる感じなんです。

ま、具体的なpositionを求めるなら、

int position = hogeList.getTouchChildIndex(x, y) + hogeList.getFirstVisiblePosition();

こんな感じっすね。

最後に

終わり

Recruit Holdings Winter Internshipに参加してた

インターンに参加した


RECRUIT HOLDINGS-リクルートホールディングス-|インターンシップサイト
コレっす。
参加して15万もらえて、優勝したら100万もらえる超良いインターン
優勝こそは出来なかったものの夏のインターンと比べると非常に良かったのでそこら辺をつらつらと。

選考

そもそも15万出るわけですから、選考もAndroidエンジニアコースの方はかなり適切な選考方法でした。
プロコン優秀者がアプリエンジニアに簡単にクラスチェンジできるわけでなく、プログラミングテストの他に各分野ごとでテストを行って、選考させてたのは非常に良かったです。
で、Androidは4人しか通らず、全10~14?チーム中2チームしかいなかったのは、まぁまぁ予想できた感。

お題

5つぐらいある中から好きなのをお題にして作れといった感じで、これも夏と比べると良いかなーって。
インターンでやるなら全部自由にというよりこういったほうが適切だなと感じました。
別にアイデアソンをやってるわけではなく、技術力とかとかをアピールしやすい環境でしたねー。

こんなん作った

f:id:amyu_dev:20150227193031p:plain

recomesi - YouTube

内部の処理もSquare様〜って感じなライブラリ構成になっていて、
・ButterKnife
・Retrofit
Picasso
などなど。
基本的にViewは全部手作りで、唯一と言っていいぐらいで使ったのがHorizontalなListViewでした。
いや、ホント結構自作View作りまくって...

一応5.0を対象に作っているんですが、4系でもレイアウトが崩れないようちゃんと2種類に分けてdrawable構成もしていたりとなかなか頑張りが伺えます。
共有のページもURLをクリック後、アプリが入ってる場合はアプリへ、ソレ以外だったらブラウザで表示といったイケイケな感じになってます。
素晴らしい!!!!

個人的にTagを付ける部分の画面が少し気合が入ってたり。
かなり気持ちいいUIを目指してDrag処理を書いてたりするので色々と満足してます。
開発途中はこんな感じだった
https://camo.githubusercontent.com/b6b4851e8127062a34071eeeb9a39292765baab7/687474703a2f2f692e6779617a6f2e636f6d2f38373263343165613566663265643135313638393263373063613530616263622e676966
https://camo.githubusercontent.com/ac056111b15410d5daadbce99c56bf40af880664/687474703a2f2f692e6779617a6f2e636f6d2f62356130313432656432353466653532336137316435323665653939646364342e676966
https://camo.githubusercontent.com/4f46b8dc4f477496cfc9db0d979b106478f48b93/687474703a2f2f692e6779617a6f2e636f6d2f62623635373235393830396235386636343463323637306661616430383836302e676966

投稿する画面、実はDelete処理もできるんですよーーー!
開発途中だった時のGifですが...
https://camo.githubusercontent.com/a2989ba659e9b393b357940c005700f4261f55da/687474703a2f2f692e6779617a6f2e636f6d2f35343732393564313630646232646332313531303762346234636164653339392e676966
https://camo.githubusercontent.com/2af4995517f725aacf1adb0941372c73ab325149/687474703a2f2f692e6779617a6f2e636f6d2f63313561643533616438386137616438653836666535326563303465383565362e676966


今回作ったアプリの切り出せる部分のViewは適当に切り出してギッパブに上げようかなーって思ってます。
他にも隠れた部分に色々とこだわってたりしてなかななか書き起こせない感じ。
動画中にない画面が実は3画面ぐらいあったりするんですよー。

さらに見て欲しいのがアイコン。
GoogleMapのパクリだと思ってもらっても構わないんですが、ちゃんと強調したい部分に微妙に影がついてたりするんですよ!
よく出来てますよね、1時間半ぐらいで作ってくれました。

ネットワーク通信周りはもう一人のチームメンバーに作ってもらってました。
かなり良い設計をしてくれたおかげで、超絶楽に済んだかんじです。
で、サーバ側、APIを作ってくれたチームメンバーも優秀で叩きやすいAPI設計になっていて超良かったです。
はー良いメンバーでよかった。

ま、要望としては、Webとスマホを同じ基準では評価できないから分けて評価して欲しかったなーって感じっすね、

参加してみて

やはりWebすごいなーというのが第一印象。
優勝したチームのフロントサイドの出来の良さにかなり感動しました。
できることの幅広さ、世に出てる知見の数が圧倒的に違うなーという。

ここ最近つらつらと感じている、「Androidは最終的にWebになるのかなー」というのを再び考えさせられるほどでした。
結局、現状WebViewオンリーなWebアプリ移植がイケてない理由って
iOSとデザインガイドライン、操作方法違うのに統一できるわけがない
・カクつく
とかだと思うんですよ。
この2点も結局、Android用にWebで作られたアプリなら上に書いた奴はクリアできるし、「カクつく」も最終的にはハードやブラウザがクリアしてくるんじゃないかなと。
すると、世に出てる数多くのWebアプリの知識群やライブラリ群にネイティブなAndroid開発が対抗できるのかなーって考えちゃうんです。

話し変わるんですが、つい先日「Google for モバイルアプリ ~ Googleと切り開くアプリビジネスの未来」というGoogleのイベントに参加してきたんです。
その時に聞いた話、あまり書けないので残念なのですが、ホントにWebが変わろうとしてるんだなーというのをヒシヒシ感じました。
そういうのを聞いたり見たりしているとJavaでのAndroid開発がいつまで持つのか、というのが非常に気になってくるところで。

ゲームUnity分野以外にフロントWebもやらないとまずいなーって感じました まる

最後に

間違えなくうちのチームが一番良かった!!!!!!!!!!

DragShadowBuilder使った時にonDragで取れる座標について

30分悩んで解決できたことの共有
あまりスマートじゃないのでもっと良い方法があったら教えて下さいー

onDragで取れる座標

onDragから帰ってくるDragEventではgetXとgetYの座標をとれるメソッドがあります。
しかしこのDragEvent、startDragしたView内の座標しか取れないんです(たぶん) ちがった追記に有り

f:id:amyu_dev:20150209012448p:plain
例えば、この赤枠にあるListView内の子ViewでstartDragした場合、この赤枠内だけの座標しか取れませんでした。

で、今回のViewでやりたかったのがこんな感じ。
http://i.gyazo.com/73a443b0e016621123d08cae69fca08b.gif


例えば、Dragした状態で右方向にずらすとTouchが追えなくなり、DragEventが帰ってこなくなります。
するとy座標で判定していた部分が機能しなくなり...
悩ましかったです。

全部渡せばいいじゃん!

"DragEvent、startDragしたView内の座標しか取れない"
と書いたとおり、渡した部分のView内の座標しか取れないので...
ということは、親Viewを渡して、DragShadowBuilder#onDrawShadowで子Viewをdrawして上げればいいじゃないか!
というふうになったわけです。

するとこんな感じ。

private class DragShadow extends View.DragShadowBuilder {

    View childView;

    public DragShadow(View parent, View child) {
        super(parent);
        childView = child;
    }

    @Override
    public void onDrawShadow(@NonNull Canvas canvas) {
        childView.draw(canvas);
    }

    @Override
    public void onProvideShadowMetrics(@NonNull Point shadowSize, @NonNull Point shadowTouchPoint) {
        int height = childView.getHeight();
        int width = childView.getWidth();
        shadowSize.set(width, height);
        shadowTouchPoint.set(width / 2, height / 2);
        }
    }

こうすることにより、子Viewを保持しているでっかなViewに対して座標を取得することが出来るようになりました。
パチパチー

最後に

ほーよく出来てる。

追記

あああああああああああああ、これえええええええええ。
Listenerを親Viewに対してつければそりゃ中で動いてるものをとれるうううう...
startDragしたやつしかOnDragListenerをセットできないという謎の迷信に囚われてた...

はああああああああ。
無駄な30分を過ごした。


ありがたきGistはこちら


ほんとありがとうございました

RegionとPathを用いた特定の部分のTouchEventの取り方

前回書いたViewの記事の補足を少し。
なんか日本語の記事が見つからなかったので書いちゃう。

TouchEventの制御

そもそもViewのonTouchEventが呼ばれる時はpaddingやTouchDelegateをしない限り四角いViewを触った時に呼ばれるはずです。

f:id:amyu_dev:20150204162935p:plain
例えば、上のようなViewがあるとして、望まれる挙動は空白の白い部分にはClickListenerを付けず、六角形の内部のみClickListenerを付けイベントを飛ばしたいと考えると思います。
そんな時役に立つのがRegionでした。

IngressAchievements/AchievementView.java at develop · amyu/IngressAchievements · GitHub
このViewを見てもらえればさくっと伝わるんですが、

/**
 * Pathを引きながらRegionにいろいろとセットする処理
 */
for (int i = 0; i < VERTEX_NUM + 1; i++) {
    double cos = Math.cos(Math.toRadians(60 * i + 30));    
    double sin = Math.sin(Math.toRadians(60 * i + 30));

    double innerX = centerX + radius * cos;
    double innerY = centerY + radius * sin;
    mInnerPath.lineTo((float) innerX, (float) innerY);
}

mRectF.setEmpty();

//RectFに対してPathの外枠の座標をセットする
mInnerPath.computeBounds(mRectF, true);

mRegion.setEmpty();

mClipRegion.setEmpty();

//ClipとなるRegionに外枠の座標をセットしたRectFをセットする
mClipRegion.set((int) mRectF.left, (int) mRectF.top, (int) mRectF.right, (int) mRectF.bottom);

//Regionに対してPathとClipとなるRegionをセットする
mRegion.setPath(mInnerPath, mClipRegion);

と言った感じでRegionをセットしていきます。

続いてonTouchEvent内での処理。

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //Regionに触られた部分の座標が含まれているか
            if (mRegion.contains((int) event.getX(), (int) event.getY())) {
                if (mOnClickListener == null) {
                    return true;
                }
                //何事もなかったらイベントを飛ばしてあげる
                mOnClickListener.onClick(this);
            }
            break;
    }
    return false;
}

と言った感じで実装できます。

最後に

Unityに浮気したい。
ではではー

IngressAchievementsっていうView作った

IngressAchievements


amyu/IngressAchievements · GitHub
コレ作ったはいいんですけど、ライブラリ化するのとか作ってる最中にめんどくさくなってきて。
そのうち暇になったらまた進化させます。

六角形の部分のTouchEvent


Regionに六角形のPathをセットして、ViewのonTouchEventでRegionの範囲内の時にListenerを叩くといった感じ。

で、上の画像のView構成は、AchievementViewというView拡張したViewをIngressListViewで表示してる感じなんです。
その時に、Viewの重なった部分のTouchEventが被るため、onInterceptTouchEventを常にfalseを返してViewにTouchEventがいくようにしるんですよー。

ViewGroup#addViewの時の処理

ViewGroupのコード読んだら

public void addView(View child, int index, LayoutParams params){
//...
}

の処理でaddViewが終わっていた。
なので、色々と変えたいんだったらこんな感じかな?

@Override
public void addView(View child, int index, LayoutParams params) {
    if (!(child instanceof AchievementView)) {
        throw new IllegalArgumentException("AchievementView以外が来てるよーーーーー");
    }
    ((AchievementView) (child)).setOnClickListener(mOnClickListener);
    super.addView(child, index, params);
}

これだけ書いておけば、addView(View child)でも勝手にいい感じになりますね。

AttributeSetを始めてちゃんと使った

ライブラリ化した時に使う側とファイル名が被らないようにしないといけないっぽい。
今は
View名_attrs.xml
にしてるけどちゃんとした命名規則があるんだったら知りたいな。

六角形の描画

60度ずつの変化のため、sinとcosの値を定数で持っておけばよかったと後悔。
のちのちに汎用性を持たせたかったと言い訳を...

それぞれの絶妙な計算

IngressListViewで並べるときやAchievementViewリサイズするときになんだかんだ結構計算してるですよー。
ほんと理系でよかった。

できてない所

AchievementViewに画像をセットすることが出来るんですけど、これバグの塊で。
onSizeChangedでセットする画像のBitmapのリサイズ処理が走るんですけど、IngressListViewでたくさんAchievementViewが入ってる時、すべてのAchievementViewでリサイズで処理が走りOOMで落ちるという。
ココらへんちゃんとImageViewとかのコードよんだほうがいいっすね。
はー。

最後に

使い道がないViewがまた世に生まれてしまった...
ではではー