Как писать под Android программы, а не код

32
Как писать под Android программы, а не код Олег Годовых @0leGG

Transcript of Как писать под Android программы, а не код

Как писать под Android программы, а не код

Олег Годовых@0leGG

Bean

Bean

Bean, Java Bean

Java Bean→ Java Monster

Beanpublic class StoryTeller { private int imageId; private String name; public StoryTeller(int imageId, String name) { this.imageId = imageId; this.name = name; } public int getImageId() { return imageId; } public void setImageId(int imageId) { this.imageId = imageId; } public int getName() { return name; } public void setName(String name) { this.name = name; } }

Bean + Lombok

@AllArgsConstructor(suppressConstructorProperties = true) public class StoryTeller { @Getter @Setter private int imageId;

@Getter @Setter private String name; }

Bean + Lombok

@Data @AllArgsConstructor(suppressConstructorProperties = true) public class StoryTeller { private int imageId; private String name; }

Lombok

buildscript { dependencies { classpath 'com.jimdo.gradle:gradle-apt-plugin:0.5' ... } }

apply plugin: 'apt'

dependencies { provided "org.projectlombok:lombok:1.12.6" apt "org.projectlombok:lombok:1.12.6" ... }

Lombok

• toString()

• equals() и hashCode()

• value-классы

• throws

• log

Annotations

• JSON — Gson, Jackson, Jackson-jr

• XML — SimpleXml

• Database — ORMLite

Java 6

• Код нелаконичен• Очень много boilerplate

RxJava + Java 6articleSubscription.add(service.getNewsById(articleId) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .onErrorReturn(new Func1<Throwable, SingleNewsItem>() { @Override public SingleNewsItem call(final Throwable throwable) { LOGGER.error("Error while fetching the article with id = " + articleId); Toast.makeText(getActivity(), R.string.error, Toast.LENGTH_LONG).show(); hideProgressBar(); return null; } }) .subscribe(new Action1<SingleNewsItem>() { @Override public void call(final SingleNewsItem newsItem) { article = newsItem; articleView.loadData(article.getContent(); hideProgressBar(); } }));

RxJava + Java 6 + RetroLambda

articleSubscription.add(service.getNewsById(articleId) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .onErrorReturn(throwable -> { LOGGER.error("Error while fetching the article with id = " + articleId); Toast.makeText(getActivity(), R.string.error, Toast.LENGTH_LONG).show(); hideProgressBar(); return null; }) .subscribe(newsItem -> { article = newsItem; articleView.loadData(article.getContent()); hideProgressBar(); }));

Java 6 + RetroLambda

buildscript { dependencies { classpath 'me.tatarka:gradle-retrolambda:2.2.3' ... } }

apply plugin: 'retrolambda'

android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } ... }

RxJava

• Реактивное программирование — очень ок

• Экономит время на:• повторяющихся операциях• цепочках операций• группах параллельных операций• взаимодействиях потоков

Event Bus

• Делаем приложение слабо связным

• Развязываем руки как «производителям», так и «потребителям»

• Дешёвый аналог BroadcastListener

Otto — через аннотации

public class BaseFragment extends Fragment { protected Bus bus = MyApplication.getBus();

@Override public void onResume() { super.onResume(); bus.register(this); }

@Override public void onPause() { bus.unregister(this); super.onPause(); }

@Subscribe public void onResponse(WelcomeData data) { loadWelcome(data); } }

GreenDroid EventBus — по конвенции

public class BaseFragment extends Fragment { protected EventBus bus = EventBus.getDefault();

@Override public void onResume() { super.onResume(); bus.register(this); }

@Override public void onPause() { bus.unregister(this); super.onPause(); }

public void onEvent(WelcomeData data) { loadWelcome(data); } }

Layouts and Views

• findViewById — скучно и многословно.

• ButterKnife — аннотируем поля класса, устанавливаем автоматически.

• AndroidQuery — всё в одном, более лаконичные средства для простой работы со View

Layouts and Views

TextView view = (TextView)findViewById(R.id.text); view.setText("Hello");

// становится

new AQuery(this).id(R.id.text).text("Hello");

Layouts and Views

class ExampleActivity extends Activity { private TextView title; private TextView subtitle; private TextView footer;

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); title = (TextView)findViewById(R.id.title); subtitle = (TextView)findViewById(R.id.subtitle); footer = (TextView)findViewById(R.id.footer); }}

Layouts and Views

class ExampleActivity extends Activity { @InjectView(R.id.title) TextView title; @InjectView(R.id.subtitle) TextView subtitle; @InjectView(R.id.footer) TextView footer;

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ButterKnife.inject(this); } }

Dependency Injection• Связывать части приложения будет легче и удобнее.

• Стандарт де-факто — Dagger

• Части приложения (модули) — будут связаны за нас.

• Синглтоны — за нас.

• Легко подменять модули.• Легко делать mock-модули.

JVM-based языки

• Scala, Clojure, тысячи их.

• Главное — генерировать байткод Java 6.

• И не использовать те фишки, которые Android из Java 6 не взял.

Лучшее — враг хорошего

• При всех улучшениях и удобствах нужно контролировать bus factor.

• Все «нестандартные» компоненты могут со временем сломаться.

• Совместимость между ними не всегда хороша.

Спасибо за внимание!

Олег Годовых@0leGG