@Bind(R.id.first_name)
EditText firstName;@OnClick(R.id.button_continue)
public void continue(){}@Bind(R.id.first_name)
EditText firstName;@OnClick(R.id.button_continue)
public void continue(){}Publisher
Event
post()
EventBus
Event
Event
Subscriber
Subscriber
onEvent(Event e)
onEvent(Event e)
//Creación del modelo de datos
public class MessageEvent { /*Definición del modelo*/ }
//Registrar el componente que recibirá el mensaje
eventBus.register(this);
public void onEvent(MessageEvent event) {
/* Do something */
};
//Enviar el evento
eventBus.post(event);//Creación del modelo de datos
public class MessageEvent { /*Definición del modelo*/ }
//Registrar el componente que recibirá el mensaje
bus.register(this);
@Subscribe
public void answerAvailable(MessageEvent event) {
/* Do something */
};
//Enviar el evento
eventBus.post(event);Comunicación con el servidor
The Big Picture
Añadir Request al RequestQueue
Ejecutar el Request de manera asíncrona
Devolver la respuesta al hilo principal
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Manejo de la respuesta
parseArtistsResponse(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// Manejo de errores
error.printStackTrace();
}
});
// Añadir la petición a la cola de peticiones
Volley.newRequestQueue(this).add(stringRequest);The android rest client
ApiClient.Java
ApiService.Java
models
public interface GitHubService {
@GET("/users/{user}/repos")
void listRepos(@Path("user") String user, Callback<List<Repo>>);
}@GET("/users/{user}/repos")
@GET("/users/list?sort=desc")Las anotaciones de los métodos, de primera instancia, nos permiten manipular el tipo de método y la URL a la cuál haremos la petición.
@POST("/users/new")
void createUser(@Body User user, Callback<User> cb);Los argumentos que contenga el método de la petición definen por medio de anotaciones qué papel jugará ese argumento.
@GET("/group/{id}/users")
List<User> groupList(@Path("id") int groupId, @Query("sort") String sort);APP
Client
Server
public class ApiClient {
public static GithubApiService API_SERVICE;
public static GithubApiService getInstance() {
if(API_SERVICE == null){
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.setConverter(new GsonConverter(gson))
.build();
API_SERVICE = restAdapter.create(GithubApiService.class)
}
return API_SERVICE
}
}ApiClient.getInstance(this)
.listRepos("silmood", new Callback<List<Repo>>{
@Override
public void success(List<Repo> repos, Response response) {
adapter.addAll(repos);
}
@Override
public void failure(RetrofitError error) {
error.printStackTrace();
}
})Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)Glide.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.crossFade()
.into(myImageView);<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="20dp"
android:layout_height="20dp"
fresco:fadeDuration="300"
fresco:actualImageScaleType="focusCrop"
fresco:placeholderImage="@color/wait_color"
fresco:failureImage="@drawable/error"
fresco:retryImage="@drawable/retrying"
fresco:retryImageScaleType="centerCrop"
fresco:backgroundImage="@color/blue"
fresco:overlayImage="@drawable/watermark"
fresco:pressedStateOverlayImage="@color/red"
fresco:roundAsCircle="false" />mSimpleDraweeView.setImageURI(uri);//Creación de la base de datos
new DaoMaster.DevOpenHelper(this, "notes-db", null)
//Preparar los DAOs
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
noteDao = daoSession.getNoteDao();
//Insertando un elemento a la tabla
Note note = new Note(null, noteText, comment, new Date());
noteDao.insert(note);
//Creación del modelo
Schema schema = new Schema(1, "de.greenrobot.daoexample");
Entity note= schema.addEntity("Note");
note.addIdProperty();
note.addStringProperty("text").notNull();
note.addStringProperty("comment");
note.addDateProperty("date");
new DaoGenerator().generateAll(schema, "../DaoExample/src-gen");
//Creación de la base de datos
@Database(name = ColonyDatabase.NAME, version = ColonyDatabase.VERSION)
public class ColonyDatabase {
public static final String NAME = "Colonies";
public static final int VERSION = 1;
}
//Creación de una tabla
@Table(databaseName = ColonyDatabase.NAME)
public class Queen extends BaseModel {
@Column
@PrimaryKey(autoincrement = true)
long id;
@Column
String name;
}
//Métodos de escritura sobre la base de datos
TransactionManager.getInstance()
.addTransaction(new SaveModelTransaction<>(processModelInfo));
TransactionManager.getInstance()
.addTransaction(new UpdateModelListTransaction(processModelInfo));
TransactionManager.getInstance()
.addTransaction(new DeleteModelListTransaction(processModelInfo));
//Métodos de lectura
TransactionManager.getInstance().addTransaction(new SelectListTransaction<>(new TransactionListenerAdapter<TestModel.class>() {
@Override
public void onResultReceived(List<TestModel> testModels) {
// on the UI thread, do something here
}
}, TestModel.class, condition1, condition2,..);
//Clase modelo
public class User extends RealmObject {
@PrimaryKey
private String ame;
private int age;
@Ignore
private int sessionId;
// Standard getters & setters
}
//Métodos de escritura sobre la base de datos
Realm realm = Realm.getInstance(this);
realm.beginTransaction();
User user = realm.createObject(User.class); // Create a new object
user.setName("John");
user.setEmail("john@corporation.com");
realm.commitTransaction();
//Métodos de lectura
RealmQuery<User> query = realm.where(User.class);
query.equalTo("name", "John");
query.or().equalTo("name", "Peter");
RealmResults<User> result1 = query.findAll();
Observable<OnTextChangeEvent> userNameText =
WidgetObservable.text((EditText) findViewById(R.id.edtUserName));
userNameText.subscribe( e -> Log.d("[Rx]", e.text().toString()));@GET("/v1/search?type=artist")
Observable<ArtistSearchResponse> searchArtist(@Query("q") String query);public void performSearch(String query) {
apiService.searchArtist(query)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<ArtistSearchResponse>() {
@Override
public void call(ArtistSearchResponse artistSearchResponse) {
artistSearchResponse.getArtists();
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
}@GET("/v1/search?type=artist")
Observable<ArtistSearchResponse> searchArtist(@Query("q") String query);public void performSearch(String query) {
apiService.searchArtist(query)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
ArtistSearchResponse::getArtists,
Throwable::printStackTrace);
}apiService.searchArtist(query)
.observeOn(AndroidSchedulers.mainThread())
.flatMap(artistSearchResponse -> Observable.from(artistSearchResponse.getArtists()))
.first()
.subscribe(Artist::getName);apiService.searchArtist(query)
.observeOn(AndroidSchedulers.mainThread())
.flatMap(artistSearchResponse -> Observable.from(artistSearchResponse.getArtists()))
.last()
.subscribe(Artist::getName);@GET("/v1/artist")
Observable<Bio> getBio(@Query("name") String artistName);apiService.searchArtist(query)
.observeOn(AndroidSchedulers.mainThread())
.flatMap(artistSearchResponse -> Observable.from(artistSearchResponse.getArtists()))
.flatMap(artist -> apiService.getArtistBio(artist.getName()))
.subscribe(bio -> bio.getAutor());
Interactor
Presenter
ViewModel
Petición de datos
Notificar
Mostrar información
@Override
public void setupList() {
mArtistResultsList.setLayoutManager(new LinearLayoutManager(CONTEXT));
mArtistResultsList.setAdapter(mResultsAdapter);
}
@Override
public void setupAdapter() {
mResultsAdapter.setOnItemClickListener(mSearchPresenter);
}
@Override
public void setupSearchInput() {
mArtistSearchInput.setQueryListener(mSearchPresenter);
}
@Override
public void onQueyChange(String query){
mPresenter.searchArtists(query);
}
@Override
public void displayFoundArtists(ArrayList<Artist> artists) {
mResultsAdapter.replace(artists);
}
@Override
public void displayFailedSearch() {
Toast.makeText(CONTEXT, R.string.failed_search, Toast.LENGTH_SHORT).show();
}
@Override
public void displayNetworkError() {
Toast.makeText(CONTEXT, R.string.network_error, Toast.LENGTH_SHORT).show();
}
@Override
public void displayServerError() {
Toast.makeText(CONTEXT, R.string.server_error, Toast.LENGTH_SHORT).show();
} @Override
public void searchArtists(String query) {
searchInteractor.performSearch(query, this);
}
@Override
public void onArtistsFound(ArrayList<Artist> artists) {
searchView.displayFoundArtists(artists);
}
@Override
public void onFailedSearch() {
searchView.displayFailedSearch();
}
@Override
public void onNetworkError(RetrofitError error) {
error.printStackTrace();
searchView.displayNetworkError();
}
@Override
public void onServerError(RetrofitError error) {
error.printStackTrace();
searchView.displayServerError();
}@Override
public void performSearch(String query, final ArtistSearchServerCallback callback){
apiService.searchArtist(query, new Callback<ArtistSearchResponse>() {
@Override
public void success(ArtistSearchResponse artistSearchResponse, Response response) {
if(artistSearchResponse.getArtists().isEmpty())
callback.onFailedSearch();
else
callback.onArtistsFound(artistSearchResponse.getArtists());
}
@Override
public void failure(RetrofitError error) {
if (error.getKind() == RetrofitError.Kind.NETWORK)
callback.onNetworkError(error);
else
callback.onServerError(error);
}
});
}
Interactor
Presenter
ViewModel
Dependency
Dependency
public ArtistSearchPresenter(ArtistSearchView view, ArtistSearchInteractor interactor) {
searchView = view;
searchInteractor = interactor;
}Dependencia
Dependencia
Clases que crean instancias de los objetos para la inyección de dependencias
Constituyen una API interna a través de la cual obtenemos los objetos que necesitamos para resolver las dependencias
@module@component@inject
Inyecta una dependencia. Comunmente se usa como anotación para un atributo de una clase
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField 'String', 'HOST', '"http://192.168.1.34:8000"'
}
debug {
minifyEnabled false
buildConfigField 'String', 'HOST', '"http://192.168.1.34:3000"'
}
}
}
android {
productFlavors {
free {
packageName 'com.silmood.myapp'
resValue('color', 'primary' , '"#000"')
}
paid {
packageName 'com.silmood.myapp.paid'
resValue('color', 'primary' , '"#fff"')
}
}
}silmood
@silmood