Desvendando as ferramentas
     e serviços para o
  desenvolvedor Android
        João Bosco Monteiro
Quem sou


Sócio e desenvolvedor na

Desenvolvendo software há 10 anos

Ex-JavaEE
Autor do livro
Lado B
Por que utilizar frameworks?
Onde utilizar

   Interface Gráfica Utilitários

     Injeção de Dependências

   Persistência   Build   Testes

       Integração Contínua
Utilitários, UI e IoC
Ajax Callback      Manipulação de Imagens

  XML Parsing         Autenticação Twitter e
                            Facebook
Localização (beta)
public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

      final TextView textView =
              (TextView) findViewById(R.id.text);
      textView.setText("Clique no botão");
      Button button =
               (Button) findViewById(R.id.button);
      button.setText("clique aqui");
      button.setOnClickListener(
              new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
                       textView.setText("QCon 2012");
                     }
              });
}
public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

      aq = new AQuery(this);
      aq.id(R.id.text).text("Clique no botão");
      aq.id(R.id.button).text("clique aqui")
}

public void onClick(View v) {
       aq.id(R.id.text).text("QCon 2012");
}
public void async() {
       String url = "http://search.twitter.com/…";

       aq.ajax(url, JSONObject.class,
               this, "callback");
}

public void callback(String url,
                              JSONObject json,
                           AjaxStatus status) {
       if (json != null) {
               // successful ajax call
       }
}
String imageUrl =
         "http://qcon.com.br/images/infoq.gif";

//carregamento assíncrono, com cache
aq.id(R.id.image).image(imageUrl);

//carregamento assíncrono, com cache e fallback
aq.id(R.id.image).image(imageUrl, true, true, 0,
                      R.drawable.default_image);

//limita a largura da imagem em 200px
aq.id(R.id.image).image(imageUrl, true, true,
                              200, 0);
RoboGuice
Injeção de dependências
             Powered by Google Guice

É possível injectar views, recursos,
serviços do sistema...
class AndroidWay extends Activity {
   TextView name;
   ImageView thumb;
   LocationManager loc;
   Drawable icon;
   String myName;

   public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
     name = (TextView) findViewById(R.id.name);
     thumb = (ImageView)
findViewById(R.id.thumbnail);
     loc = (LocationManager)
       getSystemService(Activity.LOCATION_SERVICE);
     icon = getResources()
                        .getDrawable(R.drawable.icon);
     myName = getString(R.string.app_name);
     name.setText( "Hello, " + myName );
   }
}
class RoboWay extends RoboActivity {
   @InjectView(R.id.name) TextView name;
   @InjectView(R.id.thumbnail) ImageView thumbnail;
   @InjectResource(R.drawable.icon) Drawable icon;
   @InjectResource(R.string.app_name) String myName;
   @Inject LocationManager loc;

    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      name.setText( "Hello, " + myName );
    }
}
Android Annotations
Annotation Processing Tool para gerar boilerplate
code

Injeção de dependência em tempo de compilação

Threading e Event Handlig

REST Client (Spring Android Wrapper)
@EActivity(R.layout.my_activity)
public class MyActivity extends Activity {

  @ViewById
  EditText myEditText;

  @StringRes(R.string.hello)
  String helloFormat;

  @ColorRes
  int androidColor;

  @BooleanRes
  boolean someBoolean;

  @SystemService
  NotificationManager notificationManager;
@Rest("http://company.com/ajax/services")
public interface MyRestClient {
  @Get("/events")
  EventList getEvents();
}


@EActivity
public class MyActivity extends Activity {
       @RestService
       MyRestClient myRestClient;

       @AfterViews
       void afterViews() {
              myRestClient.getEvents();
       }
}
@Click
void anotherButton() {}

@Background
void someBackgroundWork(String param) {}

@UiThread
void doInUiThread(String param) {}

@Transactional
void doSomeDbWork(SQLiteDatabase db) {}
Spring Android
Rest Client

OAuth
public <T> T getForObject(URI url,
                          Class<T> responseType);

public <T> T postForObject(URI url,
                        Object request,
                        Class<T> rType);

public void put(String url,
                      Object request,
                      Object... variables);

public void delete(String url,
                        Object... urlVariables);
final String url =
"https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q
={query}";

RestTemplate restTemplate = new RestTemplate();

GoogleSearch response =
       restTemplate.getForObject(url,
                        GoogleSearch.class,
                        "Google Android");
ORM Lite
ORM já existente

Configuração via anotações

Generic DAO e ActiveRecord

QueryBuilders
Generic DAO
queryForAll()
queryForId(ID id)
queryForFieldValues(Map<String, Object> fieldValues)
queryRaw(String query)

create(T object)
createOrUpdate(T object)
update(T object)
delete(T object)

countOf()
projetoDao = getHelper().getProjetoDao();

QueryBuilder<Projeto, Integer> queryBuilder;
queryBuilder = projetoDao.queryBuilder();

List<Projeto> projetos = queryBuilder.where()
                        .eq("nome", "QCon")
                        .and()
            .eq("cid", 1)
            .query();
GreenDroid

Widgets e Layouts

Estilos e temas

Custom ActionBar
ActionBarSherlock

ActionBar para todos!
Testes
Robolectric
Roda os testes diretamente na JVM

Mocking não é necessário

Shadow Objects
@RunWith(RobolectricTestRunner.class)
public class HomeActivityTest {
  private HomeActivity activity;
  private Button pressMeButton;

    @Before
    public void setUp() throws Exception {
      activity = new HomeActivity();
      activity.onCreate(null);
      pressMeButton = (Button)
                   activity.findViewById(R.id.press_me_button);
    }

    @Test
    public void shouldHaveAButtonThatSaysPressMe()
                                                 throws Exception {
      assertThat((String) pressMeButton.getText(),
                                        equalTo("Tests Rock!"));
    }
}
Tests run: 86, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 15.875s
[INFO] Finished at: Sun Jul 29 15:54:58 GMT-04:00 2012
[INFO] Final Memory: 14M/81M
[INFO] ------------------------------------------------------------------------
Robotium
Testes caixa-preta

Legibilidade dos casos de testes é melhor do
que os de instrumentação

Integração com Maven
Maven

mvn archetype:generate 
 -DarchetypeArtifactId=android-with-test
 -DarchetypeGroupId=de.akquinet.android.archetypes
 -DarchetypeVersion=1.0.6
 -DgroupId=com.foo.bar
 -DartifactId=my-android-project
 -Dpackage=com.foo.bar.android
Serviços




PushLink
Discussões
Obrigado!

   João Bosco Monteiro
joaobmonteiro@gmail.com
     @joaobmonteiro

Desvendando as ferramentas e serviços para o desenvolvedor Android

  • 1.
    Desvendando as ferramentas e serviços para o desenvolvedor Android João Bosco Monteiro
  • 2.
    Quem sou Sócio edesenvolvedor na Desenvolvendo software há 10 anos Ex-JavaEE
  • 3.
  • 4.
  • 5.
    Por que utilizarframeworks?
  • 6.
    Onde utilizar Interface Gráfica Utilitários Injeção de Dependências Persistência Build Testes Integração Contínua
  • 7.
  • 8.
    Ajax Callback Manipulação de Imagens XML Parsing Autenticação Twitter e Facebook Localização (beta)
  • 10.
    public void onCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final TextView textView = (TextView) findViewById(R.id.text); textView.setText("Clique no botão"); Button button = (Button) findViewById(R.id.button); button.setText("clique aqui"); button.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { textView.setText("QCon 2012"); } }); }
  • 11.
    public void onCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); aq = new AQuery(this); aq.id(R.id.text).text("Clique no botão"); aq.id(R.id.button).text("clique aqui") } public void onClick(View v) { aq.id(R.id.text).text("QCon 2012"); }
  • 12.
    public void async(){ String url = "http://search.twitter.com/…"; aq.ajax(url, JSONObject.class, this, "callback"); } public void callback(String url, JSONObject json, AjaxStatus status) { if (json != null) { // successful ajax call } }
  • 13.
    String imageUrl = "http://qcon.com.br/images/infoq.gif"; //carregamento assíncrono, com cache aq.id(R.id.image).image(imageUrl); //carregamento assíncrono, com cache e fallback aq.id(R.id.image).image(imageUrl, true, true, 0, R.drawable.default_image); //limita a largura da imagem em 200px aq.id(R.id.image).image(imageUrl, true, true, 200, 0);
  • 14.
    RoboGuice Injeção de dependências Powered by Google Guice É possível injectar views, recursos, serviços do sistema...
  • 15.
    class AndroidWay extendsActivity { TextView name; ImageView thumb; LocationManager loc; Drawable icon; String myName; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); name = (TextView) findViewById(R.id.name); thumb = (ImageView) findViewById(R.id.thumbnail); loc = (LocationManager) getSystemService(Activity.LOCATION_SERVICE); icon = getResources() .getDrawable(R.drawable.icon); myName = getString(R.string.app_name); name.setText( "Hello, " + myName ); } }
  • 16.
    class RoboWay extendsRoboActivity { @InjectView(R.id.name) TextView name; @InjectView(R.id.thumbnail) ImageView thumbnail; @InjectResource(R.drawable.icon) Drawable icon; @InjectResource(R.string.app_name) String myName; @Inject LocationManager loc; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); name.setText( "Hello, " + myName ); } }
  • 17.
    Android Annotations Annotation ProcessingTool para gerar boilerplate code Injeção de dependência em tempo de compilação Threading e Event Handlig REST Client (Spring Android Wrapper)
  • 18.
    @EActivity(R.layout.my_activity) public class MyActivityextends Activity { @ViewById EditText myEditText; @StringRes(R.string.hello) String helloFormat; @ColorRes int androidColor; @BooleanRes boolean someBoolean; @SystemService NotificationManager notificationManager;
  • 19.
    @Rest("http://company.com/ajax/services") public interface MyRestClient{ @Get("/events") EventList getEvents(); } @EActivity public class MyActivity extends Activity { @RestService MyRestClient myRestClient; @AfterViews void afterViews() { myRestClient.getEvents(); } }
  • 20.
    @Click void anotherButton() {} @Background voidsomeBackgroundWork(String param) {} @UiThread void doInUiThread(String param) {} @Transactional void doSomeDbWork(SQLiteDatabase db) {}
  • 21.
  • 22.
    public <T> TgetForObject(URI url, Class<T> responseType); public <T> T postForObject(URI url, Object request, Class<T> rType); public void put(String url, Object request, Object... variables); public void delete(String url, Object... urlVariables);
  • 23.
    final String url= "https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q ={query}"; RestTemplate restTemplate = new RestTemplate(); GoogleSearch response = restTemplate.getForObject(url, GoogleSearch.class, "Google Android");
  • 24.
    ORM Lite ORM jáexistente Configuração via anotações Generic DAO e ActiveRecord QueryBuilders
  • 26.
    Generic DAO queryForAll() queryForId(ID id) queryForFieldValues(Map<String,Object> fieldValues) queryRaw(String query) create(T object) createOrUpdate(T object) update(T object) delete(T object) countOf()
  • 27.
    projetoDao = getHelper().getProjetoDao(); QueryBuilder<Projeto,Integer> queryBuilder; queryBuilder = projetoDao.queryBuilder(); List<Projeto> projetos = queryBuilder.where() .eq("nome", "QCon") .and() .eq("cid", 1) .query();
  • 28.
    GreenDroid Widgets e Layouts Estilose temas Custom ActionBar
  • 31.
  • 35.
  • 36.
    Robolectric Roda os testesdiretamente na JVM Mocking não é necessário Shadow Objects
  • 37.
    @RunWith(RobolectricTestRunner.class) public class HomeActivityTest{ private HomeActivity activity; private Button pressMeButton; @Before public void setUp() throws Exception { activity = new HomeActivity(); activity.onCreate(null); pressMeButton = (Button) activity.findViewById(R.id.press_me_button); } @Test public void shouldHaveAButtonThatSaysPressMe() throws Exception { assertThat((String) pressMeButton.getText(), equalTo("Tests Rock!")); } }
  • 38.
    Tests run: 86,Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 15.875s [INFO] Finished at: Sun Jul 29 15:54:58 GMT-04:00 2012 [INFO] Final Memory: 14M/81M [INFO] ------------------------------------------------------------------------
  • 39.
    Robotium Testes caixa-preta Legibilidade doscasos de testes é melhor do que os de instrumentação Integração com Maven
  • 41.
    Maven mvn archetype:generate -DarchetypeArtifactId=android-with-test -DarchetypeGroupId=de.akquinet.android.archetypes -DarchetypeVersion=1.0.6 -DgroupId=com.foo.bar -DartifactId=my-android-project -Dpackage=com.foo.bar.android
  • 43.
  • 51.
  • 52.
    Obrigado! João Bosco Monteiro joaobmonteiro@gmail.com @joaobmonteiro