Knight

František Gažo

to the Rescue...

MVP knižnica s Dependency Injection pre Android

Problém

Stavy

Špagetový kód

Ako na to?

MVP

Model

View

Presenter

  • Model zabezpečuje prístup k dátam a manipuláciu s nimi
  • View zobrazuje dáta (užívateľské rozhranie)
  • Presenter reaguje na udalosti od užívateľa a vykonáva zmeny v modeli alebo view

DI

  • Dependency Injection

  • odobrať triedam zodpovednosť za získavanie objektov, ktoré potebujú pre svoju činnosť (tzv. služieb)
  • poskytnúť pri vytvorení

Ale...

Ako

Knight?

Knight

  • knižnica poskytujúca MVP s DI
  • využíva:

Knight - Dagger2

Application Scope

Screen Scope

Activity Scope

  • konfiguračné triedy automaticky vytvárané (Component, Module)
  • vytvára 3 vrstvy (tzv. scopes)
  • každá môže poskytovať objekty
  • má dostupné objekty zo svojho a obaleného scopu

APT & Bytecode Weaving

Annotation Processing

ByteCode Weaving

  • vykonávané počas kompilácie
  • APT generuje triedy
  • Bytecode Weaving vkladá iba volania metód
  • plne debugovateľné
  • žiadna reflexia

APT & Bytecode Weaving

  • potrebný na spustenie Bytecode Weavingu
  • zjednodušuje použitie knižnice

Knight - Gradle Plugin

buildscript {
    dependencies {
        repositories {
            mavenCentral()
        }

        classpath 'com.android.tools.build:gradle:1.3.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'

        classpath 'eu.inloop.knight:knight-plugin:0.0.4'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

apply plugin: 'knight'

API

Inicializácia

@KnightApp
public class App extends Application {










}
@KnightApp
public class App extends Application {

    @Inject SomeUtil mUtil;

    @Override
    protected void onCreate() {
        super.onCreate();

        // Dostupne Injecty
    }

}
  • označiť Application ako @KnightApp
  • automaticky injectnuté

Activity

@KnightActivity
public class MyActivity extends Activity {

    @Inject SomeUtil mUtil;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Dostupne Injecty
    }

}
@KnightActivity
public class MyActivity extends Activity {










}
  • stačí označiť ako @KnightActivity
  • automaticky injectnuté

Fragment / Custom View

public class CustomView extends View {

    @Inject SomeUtil mUtil;

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);

        // Dostupne Injecty
    }
}
public class MyFragment extends Fragment {

    @Inject SomeUtil mUtil;

    @Override
    protected void onAttach() {
        super.onAttach();

        // Dostupne Injecty
    }
}
  • trieda sa neoznačuje anotáciou
  • automaticky injectnuté
@KnightActivity({
    MyFragment.class,
    CustomView.class   
})
public class MyActivity extends Activity {

    //...
}

Service

public class SomeService extends IntentService {

    @Inject SomeUtil mUtil;

    public SomeService() {
        super("SomeName");
        // Dostupne Injecty
    }    

    // ...

}
  • trieda sa neoznačuje anotáciou
  • automaticky injectnuté
@KnightApp(
    SomeService.class
)
public class App extends Application {

    //...

}

Ako poskytovať objekty?

public class SomeUtil {

    @AppProvided
    @Singleton
    public SomeUtil(Application app) {
        //...
    }

    // ...

}
  • 3 anotácie:
    • @AppProvided
    • @ScreenProvided
    • @ActivityProvided
public class UiUtil {

    @ActivityProvided({
        ExampleActivity.class
    })
    @Singleton
    public UiUtil(Activity activity) {
        //...
    }

    // ...

}

Ako poskytovať objekty?


@Module
public class MyModule {

    @Provides
    public SomeObject providesObject(/* args */) {
        return new SomeObject(/* args */);
    }

}
  • vlastný Dagger Module
  • tiež označiť s @App/Screen/ActivityProvided
  • používať príslušný scope:
    • @AppScope
    • @ScreenScope
    • @ActivityScope
@AppProvided
@Module
public class MyModule {

    @Provides
    public SomeObject providesObject(/* args */) {
        return new SomeObject(/* args */);
    }

}
@AppProvided
@Module
public class MyModule {

    @Provides
    @AppScope
    public SomeObject providesObject(/* args */) {
        return new SomeObject(/* args */);
    }

}

Kde je MVP?

Presenter

public class ContactPresenter extends BasePresenter<IContactView> {

    @ScreenProvided(ContactActivity.class)
    @Singleton
    public ContactPresenter(...) {...}

    @Override
    public void onCreate(@Nullable Bundle savedState) {...}

    @Override
    public void onSave(@NonNull Bundle outState) {...}

    @Override
    public void onRemove() {...}

    @Override
    public void onBindView(@NonNull V view) {...}

    @Override
    public void onReleaseView() {...}    
}
  • 2 možnosti vytvorenia:
    • extends BasePresenter<T extends IView>
    • implements IPresenter<T extends IView>

View

public interface IContactView 
        extends IView {

    void show(Contact c);
    void show(String msg);

}
public class ContactView extends View implements IContactView {

    @Inject ContactPresenter mPresenter;

    public ContactView(Context c, ...) {
        super(c, ...);


    }








    @Override 
    public void show(String msg) {...}

    @Override 
    public void show(Contact c) {...}

}
  • definovať rozhranie
  • implementovať
  • nastaviť view
  • uvoľniť view
public class ContactView extends View implements IContactView {

    @Inject ContactPresenter mPresenter;

    public ContactView(Context c, ...) {
        super(c, ...);
        // nastav view
        mPresenter.bindView(this);
    }








    @Override 
    public void show(String msg) {...}

    @Override 
    public void show(Contact c) {...}

}
public class ContactView extends View implements IContactView {

    @Inject ContactPresenter mPresenter;

    public ContactView(Context c, ...) {
        super(c, ...);
        // nastav view
        mPresenter.bindView(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        // uvolni view
        mPresenter.releaseView();
    }

    @Override 
    public void show(String msg) {...}

    @Override 
    public void show(Contact c) {...}

}

Extra

Extra

@KnightActivity
public class ContactActivity extends Activity {

    @Extra
    Contact mContact;

    //...
}
public class ContactListActivity extends Activity {

    public void showContact(Contact contact) {
        I.startContactActivity(this, contact);
    }

    // ...

}
  • trieda I pre navigáciu medzi Activitami

  • 2 metódy pre každú activity:

    • Intent forXActivity(Context c[, T extra, ...])

    • void startXActivity(Context c[, T extra, ...])

Čo ďalej?

Ciele

  • Optimalizovať vytvárané triedy
  • Podpora pre mockovanie
  • Podpora pre Assisted Injection
  • Testovať

Ďakujem za pozornosť

Q&A

Knight to the rescue

By František Gažo

Knight to the rescue

Kinght, MVP library with Dependency Injection for Android

  • 819