daggerサンプルコードの最初から、メソッドなどの関係が分からなかったので、理解しようと頑張った

なんとなく勉強会などで説明を聞いていて
DIとかよりまず処理の流れがよく分かっていませんでした。。

@Moduleのついているクラス@Providesがついているメソッドを使うと@Injectのところに入れてくれるとかは聞いていた

public class MainActivity extends Activity{
    @Inject Test test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        ObjectGraph.create(new TestModule()).inject(this);
    }
}
@Module(injects = MainActivity.class)
public class TestModule {
    @Provides
    Test provideTest() {
        return new Test();
    }
}

こんなイメージだった

これだとMainActivity.testに入れる変数をTestModuleから提供される感じだった

そんな感じで公式のdaggerのサンプルを読もうとした

square/dagger · GitHub

サンプルコードの最初はこういう感じ

public class CoffeeApp implements Runnable {
  @Inject CoffeeMaker coffeeMaker;

  @Override public void run() {
    coffeeMaker.brew();
  }

  public static void main(String[] args) {
    ObjectGraph objectGraph = ObjectGraph.create(new DripCoffeeModule());
    CoffeeApp coffeeApp = objectGraph.get(CoffeeApp.class);
    coffeeApp.run();
  }
}

このmainを実行する
CoffeeMakerはこうなっている

class CoffeeMaker {
  @Inject Lazy<Heater> heater; // Don't want to create a possibly costly heater until we need it.
  @Inject Pump pump;

  public void brew() {
    heater.get().on();
    pump.pump();
    System.out.println(" [_]P coffee! [_]P ");
    heater.get().off();
  }
}

普通に考えるのがDripCoffeeModuleの中に、CoffeeApp.coffeeMakerに変数を入れる@Providesが書いてあるとか思うでしょう?

でも

@Module(
    injects = CoffeeApp.class,
    includes = PumpModule.class
)
public class DripCoffeeModule {
  @Provides @Singleton Heater provideHeater() {
    return new ElectricHeater();
  }
}

Heaterなどは提供してくれる処理があるけど、 PumpModuleなどをたどっていってもCoffeeMakerを提供してくれる処理はないです

daggerはInjectって書いてあるところのクラスを勝手にnewして入れてくれるっぽいです。
つまりdaggerはobjectGraph.getや@Providesが付いているメソッドの引数などでオブジェクトが必要になったタイミングで以下のように動くみたいです  

if @Moduleが付いているクラス and @Providerの付いている返り値がCoffeeAppのメソッドがある:    
  それを使って作る  
else if  CoffeeAppに@Injectが付いているコンストラクタがある:  
  それを使って作る  
else :
  new CoffeeApp();#(CoffeeAppのクラスの中には@Injectがついているメンバ変数を含んで、injects=CoffeeApp.classのModuleが必要)  

こんなイメージです

サンプルコード

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        ObjectGraph.create(new TestModule()).get(Test.class).hello();
    }
}

@Module(injects = Test.class)
public class TestModule {
    @Provides
    public SayHello provideSayHello() {
        return new SayHello();
    }
}

public class Test {
    public Test(){
        System.out.println("Test created");
    }
    @Inject
    SayHello sayHello;
    public void hello(){
        sayHello.hello();
    }
}

public class SayHello {
  void hello(){
      System.out.println("hello");
  }
}
Test created
hello

間違いなどがありましたらご指摘ください

AndroidWearかどうかを判定する

ライブラリを作っている時に、AndroidスマホかAndroidWearかどうしても判定したい時があって、

どうすればいいのかわからなかったので、考えました(いい方法があったら教えて下さい)

 

 

WebViewのパッケージがないことを思い出してそれを判定するとか考えたりしましたが、何か微妙なので、、、

 

adb shell cat system/build.prop

して

ro.build.characteristics=nosdcard,watch

を発見したので、watchが含まれていることを利用する方法でやることにしました

build.propの中を見るにはSystemPropertiesを利用する必要があり、そのためにはリフレクションが必要だったので、それを使う方法でやりました

 

Android Wearを判定する

 

こんなかんじです

 

他にいい方法があればお教え下さい

Androidライブラリプロジェクト(aar)のファイルを直接読み込む

mavencentralにいつかは公開したいけど、まだそこまで行っていないライブラリのファイル(aar)ってありますよね?

そんなときに直接読み込む方法がわからなかったので

 

ライブラリの方のbuild.gradleはapply plugin: 'com.android.application'をapply plugin: 'android-library'に変えたらなんとかなったけど、

 

アプリの方は、、

こんなかんじです

 

 

Androidライブラリプロジェクト(aar)のファイルを直接読み込む

 

これで重要なのは

repositories {
mavenCentral()
flatDir {
dirs '../../WearHttp/mobile/build/outputs/aar'
}
}

ここのdirでaarがあるフォルダを指定して、

 

  compile(name:'mobile', ext:'aar')

で実際に読み込んでいます

Androidアプリで初回だけ○○したいというのを簡潔に実装したい

普通に実装すると

初回起動時だけ○○する普通版

 

 

こんなかんじになると思う

 だけどこういうのを機能を追加するたびに書いていたら苦しい

とりあえずクラスに分けたりすればそれは若干よくなるが、それでも微妙

 

なので

 

FirstTimePreferenceというクラスを使って初回だけ○○したいを実現する

 

こんなかんじでかけたらいい感じなんじゃないだろうか

(Javaの無名クラスの書き方は微妙だが)

 

ということで作った

初回のみ○○したいを実現するクラス

 

Android Wearでスマホからアプリ起動時に、Wearでアプリを起動する方法

Android Wearのアプリってなんなの?Android内にあるアプリとの関係は? - tmenのブログのmobileでリリースビルドにしている必要があります

 

 ソースコード

Wear対応アプリをスマホでアプリ起動時に、WearでActivityを開始する

 

解説

mobile/MainActiivty.java

ノード一覧を取得(つながっているデバイス一覧?)

そして、それぞれのノードに対して、Wearable.MessageApi.sendMessageします。

 

するとwear/AndroidManifest.xmlにACTIONがBIND_LISTENERで宣言されている、WearableListenerServiceを継承したクラスのonMessageRecievedが呼ばれるので、そこでWearのActivityを起動してあげましょう! 

Android Wearのアプリってなんなの?Android内にあるアプリとの関係は?

よく分かっていなかったのですが、少しずつ分かってきました

 

Android StudioAndroid Wear向けのアプリを作ろうとすると

MobileとWearディレクトリが作られます。

そして、Android Studioで普通にデバッグビルドしているとそれぞれ片方のみのapkが作られます

MobileならMobile用で、Wear向けのアプリを含みません(本当に合ってるかわからないですが、入っていかない?)

WearむけならWear向けのみです。

 

しかし Mobile向けのbuild.gradleに以下の設定を追加して、

dependencies {
   compile
'com.google.android.gms:play-services:5.0.+@aar'
   compile
'com.android.support:support-v4:20.0.+''
   
wearApp project(':wearable')
}

 

Mobileをリリースビルドして、携帯端末にインストールすると、、、

 Wear端末にアプリがインストールされます!!!

 

つまりリリースビルドされたMobile向けのapkにはWear向けのアプリが含まれているようです!!

 

これで前回の記事

Android Wear向けのアプリがリリースできない!!と思ったらできる!? - tmenのブログ

を解決して、リリースできました!!

Android Wear向けのアプリがリリースできない!!と思ったらできる!?

 

f:id:tmen:20140712022412p:plain

アップロードできませんでした

バージョン番号が 19 以下の SDK を使用する必要があります。

 

 

 だそうです。。。

そしてminSDKを19にするとこう怒られる

Error:Execution failed for task ':wear:processDebugManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 19 cannot be smaller than version 20 declared in library com.google.android.support:wearable:1.0.0 

自分が1日で作ったアプリがリリースできない。。。

 無念。。。

 

 

と思っていたのですが、

 

https://developer.android.com/training/wearables/apps/packaging.html

を読んだら、、という話