投稿履歴: 未分類

DroidKaigiに参加してきました

先日4/25の土曜日に東京のサーバーエージェント様において

DroidKaigiというAndroidの技術者のためのカンファレンスに出席してきました

DroidKaigi

こちらにまとめがあります

で僕が参加したセッションの感想を少しだけ書きます。

●基調講演

・生あんざいさんを初めて見た。

・CustomViewはどちらかというと毛嫌いしていたけどActivity,Fragment,CustomViewの役割を聞くと、もっと分離させながら実装せなあかんなーと感じたしCustomView使おう!って感じた。

・Framgentのはまりどころメモメモ

・FramgentからのonActivityForResult結構意識せず使ってたので危険

 

開発を効率的に進めるられるまでの道程

・テスト必要だよ!

・自分で一人で開発するぶんにはあまりテスト書かないので、改めて書かないと!って感じました。はい。

 

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

・AsyncTaskは地震のアプリの中でModelで結構内部実装していて、基本メモリリークしないように考慮して位作っていたけど、ちょっと見直そうと思った。

・割とありきたりな部分もあったけど、いかにメモリをリークさせないか、投げっぱなしや掴みっぱなしにしてGCが回収できないオブジェクトを作らないか。などなど参考になる部分めっちゃあった

 

初学者に嬉しいAndroid開発環境

・ぜったい初学者向けじゃないw

・話はざざーって流れていったけど、ちょっとライブラリの考え方とか自分と違うとこあったかなーって感じ

Android学ぶ君へ。生き抜くためのナレッジ共有

・コマンド便利。コマンド必要。使うとAndroid楽しくなるよ!

・ソース読もうぜ。自分のアプリ使おうぜ。自分のアプリを疑え!ってめっちゃ共感できた。あんまFrameworkのソース読まないから読まんとなーと再認識

 

新言語KotlinでAndroidプログラミング

・これ今回僕のツボにめっちゃ入ったやつです。

・Null安全とか、レイアウトをインポートしたら自動的にフィールドに持ってくれるとか、プロパティの自動生成とか、超便利

・既存のコードの変換も素敵!

・一番最後のFiresideChatで残念だったのが、実績がまだないってとこがつらい。。。

・AndroidAnnotationは使えないらしい(まぁ使わないからいいけど)

・外部ライブラリとの連携は使ってみてどうかってことらしい

・聞き忘れたけどGo On Android と共存できるんやろか。あの子Javaのソース吐くで。

・たろーさん男前

 

ARTのメモリ管理

・Android使っててアプリ内でのメモリは意識するけど、実際GCがどう動いて、メモリ回収されてとか基本知らん子やったので、聞いてて楽しかったです

・DalvikよりARTの方がいい。がんばってるって話だった。

 

つかえるGradleプロジェクトの作り方

・ライブラリプロジェクトのMinSDKなどの値をさくっと統合できるの知らなかった。超便利

・build.gradleファイルは苦労したぶんだけ自分にそれ以上のメリットが返ってくる。色々と使ってみたくなった

 

アプリを公開する前に、最低限知っておきたいセキュリティ事項

・アプリ公開者なので当たり前の話が多かったけど、割と忘れていることもあったりしたので再認識できた感じでした

 

Material Designを取り入れたデザインリニューアル

・やっぱデザイナーさんすげー!(私デザイナーさんと仕事したことない)

・アプリのUI,UXの取り入れはスピードが大事

・これMaterialっぽいですよねーっていうのが面白かった。っぽいって!

 

・Fireside Chat

・もっと長くしたかったなー感ある

・BaseActivity,BaseFragmentに関する皆さんの考え方が結構参考になった

・まさかのあらきさんの質問びっくりした!

・Supportライブラリの対応中途半端な部分多いよねっていうのは確かに実感

・PreferenceFragmentのAppCompat版欲しいよ!

 

僕自身は開発者がメインのお仕事ではないので、やっぱり気が引けるなーっていう部分もあったし、周りの開発者の人たちがスーパーコーダーの人たちだったらどうしようみたい感じで大阪から参加しましたが、思ったより皆さん同じような問題でつまずいたりというような感じを受けました。

ちょっとは自分がやってきたことって間違ってなかったかなぁと再認識しながらも、もっと頑張らないと足らない部分が多いよっていうのも感じました。

あとKotlin for Android本当にGoogleIOとかで来て各種ライブラリとか使えたらどんなにまた楽しくなるだろうっていうのも感じました。

 

だらだらーと書いてしまいましたが、僕自身にはすごく刺激のある時間でしたし楽しい時間でした。

運営の人や発表の人たちの準備はすごく大変な時間だっと思います。このような場を設けていただいた運営の方などに改めてお礼を申し上げます。次はDroidCon Toko!!

 

 

 

Floating Action Bar with Progressを更新しました

処理が終了した際に、ProgressRingが満タンになり、チェックマークなどの別のDrawableに変更できるようにしました

 

https://github.com/katsuki-nakatani/FabProgress

Quick電話帳がAndroidWearAppとして承認されました

朝起きたらメール来てました。

 

This is a notification that your app, Quick Contact, with package name com.miruker.qcontact, is accepted as an Android Wear app on Google Play.

Your application complies with our guidelines for creating apps for Android Wear. Please refer to the following developer page for details: Wear App Quality – Developer Guidelines

The Google Play Team

 

アプリケーションがガイドラインに準拠しているので承認したよ!ってことだそうです。

DeveloperConsole側でも更新されていました。

スクリーンショット 2014-12-18 7.34.55

さてこれどうなるんでしょうか。

 

GDG京都さんでLTしてきました

AndroidでGeoFencingを利用するときの話です。

 

AndroidでGeoFenceを使って見る from 克紀 中谷

Google PlayでWearAppを内包しているかどうかを指定できるようになったようです

Google Play Developer ConsoleよりリリースしているアプリがWearAppを内包しているかどうかを指定できるようになったようです。(WEARのカテゴリに表示される?)

アプリを配信しますにチェックを入れて保存するだけですが、どうやら審査があるようです。

WearApp審査

 

また審査の結果が返って来てNGなら対応しようと思っています。

AndroidWearで円形デバイスだけViewが表示されない

Android Wear Appを作る際にレイアウトを円形と四角でレイアウトを変えたい場合があります。
Android Studioでウィザード形式でActivityを作成すると、下記のファイルができるはずです。

今回はactivity_actionという名前で作成しました

すると3ファイル作成されますよね。

activity_action.xml

 <?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.WatchViewStub
 xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/watch_view_stub"
android:layout_width="match_parent" android:layout_height="match_parent"
app:rectLayout="@layout/rect_activity_action" app:roundLayout="@layout/round_activity_action"
tools:context="com.miruker.qcontact.ActionActivity"
tools:deviceIds="wear"></android.support.wearable.view.WatchViewStub>
rect_activity_action.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
 android:layout_height="match_parent" android:orientation="vertical"
 tools:context="com.miruker.qcontact.ActionActivity" tools:deviceIds="wear_square">

 <android.support.wearable.view.GridViewPager
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/indicatorSize"
 android:visibility="visible"
 android:id="@+id/gridViewPager" />

 <LinearLayout
 android:id="@+id/page_dots_container"
 android:orientation="horizontal"
 android:layout_gravity="bottom|center_horizontal"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

</FrameLayout>
 

round_activity_action.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
 android:layout_height="match_parent" tools:context="com.miruker.qcontact.ActionActivity"
 tools:deviceIds="wear_round">

 <android.support.wearable.view.GridViewPager
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:visibility="visible"
 android:paddingBottom="40dp"
 android:id="@+id/gridViewPager" />

 <LinearLayout
 android:id="@+id/page_dots_container"
 android:orientation="horizontal"
 android:layout_gravity="bottom|center_horizontal"
 android:layout_marginBottom="28dp"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>
</FrameLayout>
でJavaファイルがこちら (一部割愛)

ActionActivity.java
@Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_action);

 //前の画面からデータをもらっています
 mActionType = getIntent().getIntExtra(Global.PARAM.ACTION_TYPE, -1);
 List<String> values = getIntent().getStringArrayListExtra(Global.PARAM.VALUE_LIST);
 List<String> labels = getIntent().getStringArrayListExtra(Global.PARAM.LABEL_LIST);

//リストデータの構築
 for (int i = 0; i < values.size(); i++) {
 mItems.add(new WearContactItem(0, 0, mActionType, labels.get(i), values.get(i), ""));
 }
 mListView = ButterKnife.findById(this,R.id.gridViewPager);
 mIndicator = ButterKnife.findById(this,R.id.page_dots_container);
 mListView.setOnPageChangeListener(new GridViewPager.OnPageChangeListener() {
 @Override
 public void onPageScrolled(int i, int i2, float v, float v2, int i3, int i4) {

 }

 @Override
 public void onPageSelected(int row, int column) {
 setIndicator(column);
 }

 @Override
 public void onPageScrollStateChanged(int i) {

 }
 });

 //GridViewPagerにアダプターをセット
 ActionListAdapter adapter = new ActionListAdapter(getFragmentManager(), mItems, ActionActivity.this, mActionType);
 mListView.setAdapter(adapter);

 //インジケータViewを作成
 mIndicator.removeAllViews();
 for (int i = 0; i < adapter.getColumnCount(0); i++) {
 ImageView v = new ImageView(getApplicationContext());
 v.setImageResource(R.drawable.black_circle);
 mIndicatorList.add(v);
 mIndicator.addView(v);
 }
 インジケータの初期値
 setIndicator(0);

 mGoogleApiClient = new GoogleApiClient
 .Builder(this)
 .addConnectionCallbacks(this)
 .addApi(Wearable.API)
 .build();

 }
まぁちょっと色々端折っているのですが、単純に画面中央にはGridViewPagerがあります。

その下にはインジケータ用にLinearLayout(Horizontal)のViewがあるような感じですね。

GridViewPagerはFragmntを返すようになっています。

期待する動作としてはそのようなもんで、私の所持している G watchでも正常に表示されていましたがどうやら円形デバイスで表示されないという不具合報告を受けました。

その際に表示されている画面はインジケータは表示されているがそれ以外は何も表示されていない。

要はGridViewPagerのFragmentが表示されていないということなんですね。

StackOverFlowにありました。

 

http://stackoverflow.com/questions/25808229/fragment-in-round-wear-watch-turning-black-in-emulator-watch

英語があんまり読めないので大体の解釈なのですが、RoundDeviceだとInflateする際の動きがSquareと少し違うようで、GridViewPagerで内部で管理しているタグが整合性が合わなくなるみたいなのです。

結局シンプルな解決策として、Stubを使わないようにしました。

Android wearエミュレータ(Round)表示がおかしい件

Mac OS X Yosemite?(前から?)AndroidWearのRound形式でエミュレータ作ると残念なことになります。

スクリーンショット 2014-10-31 7.41.53

いやいや。こういうの期待してないです。

期待している表示はこっちのはずです。
スクリーンショット 2014-10-31 7.42.19

解消方法ですがエミュレータ作成時に、デフォルトチェックされているUse Host GPUのチェックを外しましょう。
スクリーンショット 2014-10-31 7.45.40

YosemiteにしたらAndroid emulatorのx86が起動しない

missing HAXMと言われ起動しなくなりました。

https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager

こちらから最新のHAXMをインストールすることで解消します

Android 5.0のRippleEffectを4.4以下で同じような動きで作ってみた

使う場合はいろいろなものを適正読み替えてくださいー。



public class RippleLinearLayout extends LinearLayoutCompat {

private static final int DURATION = 2000;
private static final int RIPPLE_ALPHA = 150;
private static final int TOUCH_ALPHA = 50;
private static final int ACTIVATE_ALPHA = 150;

@Setter
private float mDownX;
@Setter
private float mDownY;

private float mRadius;

private Paint mPaint;
private boolean mIsActivatedAnimate = false;
private int mColor = Color.BLACK;
private int mActivateAlpha = ACTIVATE_ALPHA;
private int mDuration = DURATION;
private int mRippleAlpha = RIPPLE_ALPHA;

private boolean mPressed = false;
private boolean mActivated = false;
private AnimatorSet mAnimator;


private void init(Context context, AttributeSet attrs) {
mPaint = new Paint();
mPaint.setAlpha(mRippleAlpha);

mColor = getResources().getColor(R.color.ColorGray);

if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RippleView);
mRippleAlpha = a.getInteger(R.styleable.RippleView_rippleAlpha, RIPPLE_ALPHA);
mIsActivatedAnimate = a.getBoolean(R.styleable.RippleView_isActivateAnimate,false);
mDuration = a.getInteger(R.styleable.RippleView_rippleDuration, DURATION);
a.recycle();
}

}

/**
* コンストラクタ
*
* @param context コンテキスト
*/
public RippleLinearLayout(Context context) {
this(context, null);
setBackgroundResource(R.color.Transparent);
setOnTouchListener(new ontouchListener());
init(context, null);
}

/**
* コンストラクタ2
*
* @param context コンテキスト
* @param attrs アトリビュート
*/
public RippleLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {
setBackgroundResource(R.color.Transparent);
setOnTouchListener(new ontouchListener());
init(context, attrs);
}
}

private class ontouchListener implements OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
case MotionEvent.ACTION_UP:
break;
}
return false;
}
}

/**
* コンストラクタ3
*
* @param context コンテキスト
* @param attrs アトリビュート
*/
public RippleLinearLayout(Context context, AttributeSet attrs, int Defstyle) {
super(context, attrs, Defstyle);
setBackgroundResource(R.color.Transparent);
setOnTouchListener(new ontouchListener());
}

public void setRadius(final float radius) {
mRadius = radius;
if (mRadius > 0) {
RadialGradient radialGradient = new RadialGradient(
mDownX,
mDownY,
mRadius * 3,
mColor,
mColor,
Shader.TileMode.MIRROR
);
mPaint.setAlpha(mRippleAlpha);
mPaint.setShader(radialGradient);
}
invalidate();
}

@Override
public void setPressed(boolean pressed) {

if (pressed != mPressed) {
mPressed = pressed;
if (mPressed) {
mAnimator = new AnimatorSet();
ObjectAnimator animator1 = ObjectAnimator.ofFloat(RippleLinearLayout.this, “radius”, getWidth() / 10.0f, getWidth() * 3.0f);
animator1.setInterpolator(new AccelerateDecelerateInterpolator());
animator1.setDuration(mDuration);
mAnimator.playTogether(animator1);
mAnimator.start();
setBackgroundColor(Color.argb(TOUCH_ALPHA, Color.red(mColor), Color.green(mColor), Color.blue(mColor)));
} else {
if (mAnimator != null)
mAnimator.cancel();
setRadius(0);
// if(!mIsActivatedAnimate && !isActivated())
setBackgroundColor(getResources().getColor(R.color.Transparent));
}
}
if (!pressed) {

}

super.setPressed(pressed);
}

@Override
public void setActivated(boolean activated) {
super.setActivated(activated);

if (mActivated != activated) {
mActivated = activated;
if (activated) {
if (mIsActivatedAnimate)
setBackgroundColor(Color.argb(mActivateAlpha, Color.red(mColor), Color.green(mColor), Color.blue(mColor)));
} else {
setBackgroundColor(getResources().getColor(R.color.Transparent));
}
}
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

canvas.drawCircle(mDownX, mDownY, mRadius, mPaint);

}


}

Android WearでPhoneとWearを通信させるときに注意する事

メモ程度に。

 Android WearとPhone側との通信の為には
MessageAPIで通信する
  http://developer.android.com/reference/com/google/android/gms/wearable/MessageApi.html

  DataAPIで通信する
   http://developer.android.com/reference/com/google/android/gms/wearable/DataApi.html

だと思うのですが、ここでテストで作ったパッケージからうまく行かなかった点を書いておきます。

 全く通信が出来ていないように思える。
  Wearアプリのパッケージ名とPhoneアプリのパッケージ名は同一にしましょう。(署名一緒でも良い?)
  これ忘れてたら通信が全く出来ません。

 通信は出来ているようなのだが、onDataChangedイベントが発火されない
  DataAPIは通常DataApi.DataListenerのonDataChangedイベントで通知を受け取ります。
 
 でもなぜかこない。。。
  DataAPIは内容をキャッシュしており、変更があった場合に通知されます。
  ですので内容を変えないとイベントが発火されないのです。
 
結構はまったのでもし同じような人がいて参考になれば幸い

1 / 3123