Conceitos básicos para o desenvolvimento de uma aplicação para a plataforma Android

Nesse artigo, veremos os passos mais rudimentares para desenvolver uma aplicação android que tenha apenas o básico do básico de uma aplicação: entrada e saída de dados; desenvolveremos uma aplicação com apenas dois formulários, um para inserir os dados a serem salvos na aplicação e e outro, um ListView, para mostrar os dados inseridos.

Antes de continuar esse tutorial, você precisa configurar o seu ambiente de desenvolvimento com o Eclipse eu plug-in ADT. Para ver como fazer isso, leia esse artigo.

O primeiro passo em nossa empreitada é criar um novo projeto no Eclipse. Vá para File > New > Projetc… e, na caixa de dialogo que aparecerá, escolha Android Project e clique em Next, digite um nome para o projeto, clique em Next, escolha a plataforma alvo e na última tela informe um nome para o pacote que armazenará o código fonte de sua aplicação. Para finalizar clique em Finish.

Você obterá um novo projeto com uma estrutura similar a essa:

 

Nesse projeto, além do layout principal (main.xml), iremos criar mais dois (input.xml e output.xml). O layout main.xml terá como elemento raiz TabHost, que define um layout baseado em abas. No nosso caso, teremos duas abas, que serão definidas pelos layouts input.xml e output.xml.

Para criar um novo layout, clique com o botão direito no nome do projeto e selecione New > Other. Na caixa de dialogo que aparece, selecione a opção Android XML Layout File, e na próxima tela informe um nome para o arquivo e escolha uma das opções para o Root Element. No exemplo descrito aqui, os dois layouts que criaremos devem ter o elemento raiz configurado para TabHost.

O layout main.xml deve ter o seguinte conteúdo:

 

<?xml version="1.0" encoding="utf-8"?>

<TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="fill_parent" android:layout_height="fill_parent">

<FrameLayout android:orientation="vertical"

android:layout_width="fill_parent" android:layout_height="fill_parent">

<TabWidget android:id="@android:id/tabs" android:layout_width="fill_parent" android:layout_height="wrap_content">

</TabWidget>

<FrameLayout android:id="@android:id/tabcontent" android:layout_width="fill_parent" android:layout_height="fill_parent">

</FrameLayout>

</FrameLayout>

</TabHost>

 

Os layouts input.xml e output.xml devem ter, respectivamente, os seguintes conteúdos:

input.xml

Esse layout será composto de uma série de campos de formulário, dispostos em pares (um label com seu correspondente textfield ou um spinner, que é uma lista de opções que devem ser selecionadas. O spinner será preenchido com itens salvos no banco de dados. O arquivo input.xml deve ter o seguinte formato:

 

<?xml version="1.0" encoding="utf-8"?>

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent" >

<TableRow

android:id="@+id/tableRow1"

android:layout_width="wrap_content"

android:layout_height="wrap_content" >

<TextView

android:id="@+id/textView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Nome:"

android:textAppearance="?android:attr/textAppearanceLarge" />

<EditText

android:id="@+id/editText1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:ems="10" >

<requestFocus />

</EditText>

</TableRow>

<TableRow

android:id="@+id/tableRow2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center" >

<Button

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Ok" />

</TableRow>

</TableLayout>

 

output.xml

Esse layout será uma lista de itens que estarão salvos no banco de dados. Ao ser iniciado, portanto, a Activity associada a esse layout deve puxar a lista de itens que devem ser exibidos quando for iniciada. O arquivo terá o seguinte formato:

 

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical" >

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello" />

</LinearLayout>

 

Para cada layout da aplicação, iremos associar uma Activity para ela. Uma Activity é uma classe que possui uma entrada no arquivo de manifesto (AndroidManifest.xml) da aplicação. Para criar uma nova Activity, clique com o botão direito no nome do projeto e selecione New > Class. Na caixa de dialogo, que aparece, você precisa preencher os campos Name com o nome da classe. No nosso exemplo, criaremos mais dois Activity, que serão nomeados como InputActivity e OutputActivity; também criaremos uma classe chamada DataHelper, que não terá uma entrada no manifesto, apenas servirá para comunicação com o banco de dados.

A Activity associada ao layout output.xml deve seguir o seguinte formato:

 

public class HelloListViewActivity extends ListActivity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

String[] countries = getResources().getStringArray(R.array.countries_array);

setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, countries));

ListView lv = getListView();

lv.setTextFilterEnabled(true);

lv.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

// TODO Auto-generated method stub

Toast.makeText(getApplicationContext(), ((TextView) arg1).getText(), Toast.LENGTH_SHORT).show();

}

});

}

}

 

A parte importante do código acima reside nas seguintes linhas:

 

String[] countries = getResources().getStringArray(R.array.countries_array);

setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, countries));

 

Nesse exemplo, o código está utilizando uma lista salva em um arquivo xml localizado no diretório res/ do projeto; esse código deve ser substituído para ler os dados em uma banco de dados.

A Activity associada ao layout input.xml deve seguir o seguinte formato:

 

public class HelloAndroidActivity extends Activity {

/** Called when the activity is first created. */

private EditText input;

private Button okButton;

private TextView output;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

this.input = (EditText) this.findViewById(R.id.editText1);

this.okButton = (Button) this.findViewById(R.id.button1);

this.output = (TextView) this.findViewById(R.id.textView2);

this.okButton.setOnClickListener(new OnClickListener() {

public void onClick(final View v) {

output.setText("Hello" + input.getText());

}

});

}

}

 

A parte importante do código acima reside nas seguintes linhas:

 

this.okButton.setOnClickListener(new OnClickListener() {

public void onClick(final View v) {

output.setText("Hello" + input.getText());

}

});

 

No exemplo, a saída é mostrada em uma campo de texto do formulário; esse código deve ser substituído para salvar os dados no banco de dados.

O último Activity, main.xml, definirá o comportamento da tela principal da aplicação, e deve seguir o seguinte formato:

 

public class CustomTab extends TabActivity {

private TabHost mTabHost;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

mTabHost = (TabHost) findViewById(android.R.id.tabhost);

setupTab(new TextView(this), "Tab 1");

setupTab(new TextView(this), "Tab 2");

setupTab(new TextView(this), "Tab 3");

setupTab(new TextView(this), "Tab 4");

}

 

Repare que no nosso exemplo, estamos usando duas funções auxiliares, setupTab e createTabView. O formato dessas funções é o seguinte:

setupTab(…)

 

private void setupTab(final View view, final String tag) {

View tabview = createTabView(mTabHost.getContext(), tag);

TabSpec setContent = mTabHost.newTabSpec(tag).setIndicator(tabview).setContent(new TabContentFactory() {

public View createTabContent(String tag) {return view;}

});

mTabHost.addTab(setContent);

}

 

 

createTabView(…)

 

 

private static View createTabView(final Context context, final String text) {

View view = LayoutInflater.from(context).inflate(R.layout.tabs_bg, null);

TextView tv = (TextView) view.findViewById(R.id.tabsText);

tv.setText(text);

return view;

}

 

 

Para criar as abas usadas em nosso exemplo, alguns arquivos extras são necessários. São eles:

 

drawable/tab_bg_selected.xml

 

 

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle">

<gradient android:startColor="#A8A8A8" android:centerColor="#7F7F7F"

android:endColor="#696969" android:angle="-90" />

</shape>

 

 

drawable/tab_bg_unselected.xml

 

 

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android"

android:shape="rectangle">

<gradient android:startColor="#5C5C5C" android:centerColor="#424242"

android:endColor="#222222" android:angle="-90" />

</shape>

 

 

drawable/tab_bg_selector.xml

 

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<!-- Active tab -->

<item android:state_selected="true" android:state_focused="false"

android:state_pressed="false" android:drawable="@drawable/tab_bg_selected" />

<!-- Inactive tab -->

<item android:state_selected="false" android:state_focused="false"

android:state_pressed="false" android:drawable="@drawable/tab_bg_unselected" />

<!-- Pressed tab -->

<item android:state_pressed="true" android:drawable="@android:color/transparent" />

<!-- Selected tab (using d-pad) -->

<item android:state_focused="true" android:state_selected="true"

android:state_pressed="false" android:drawable="@android:color/transparent" />

</selector>

 

 

drawable/tab_text_selector.xml

 

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_selected="true" android:color="@android:color/white" />

<item android:state_focused="true" android:color="@android:color/white" />

<item android:state_pressed="true" android:color="@android:color/white" />

<item android:color="#f8f8f8" />

</selector>

 

layout/tabs_bg.xml

 

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/tabsLayout" android:layout_width="fill_parent"

android:layout_height="fill_parent" android:background="@drawable/tab_bg_selector"

android:padding="10dip" android:gravity="center" android:orientation="vertical">

<TextView android:id="@+id/tabsText" android:layout_width="wrap_content"

android:layout_height="wrap_content" android:text="Title"

android:textSize="15dip" android:textColor="@drawable/tab_text_selector" />

</LinearLayout>

 

 

No caso especifico do Activity, depois de cria-la, precisamos adicionar uma entrada no arquivo de manifesto relacionada a ele. Essa entrada tem o seguinte formato:

 

<activity

android:name=".HelloListViewActivity"

android:label="@string/app_name" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

 

Os campos android:name e android:label devem ser únicos, e os elementos intent-filter definem características da Activity. Para obter mais informações sobre os intent-filter, veja esse artigo.

Por fim, devemos criar uma classe DataHelper.java que fará a comunicação com o banco de dados, lendo e escrevendo dados nele. Essa classe seguirá o seguinte formato:

 

public class DataHelper {

private static final String DATABASE_NAME = "example.db";

private static final int DATABASE_VERSION = 1;

private static final String TABLE_NAME = "table1";

private Context context;

private SQLiteDatabase db;

private SQLiteStatement insertStmt;

private static final String INSERT = "insert into " + TABLE_NAME + "(name) values (?)";

public DataHelper(Context context) {

this.context = context;

OpenHelper openHelper = new OpenHelper(this.context);

this.db = openHelper.getWritableDatabase();

this.insertStmt = this.db.compileStatement(INSERT);

}

public SQLiteDatabase getDb() {

return this.db;

}

public long insert(String name) {

this.insertStmt.bindString(1, name);

return this.insertStmt.executeInsert();

}

public void deleteAll() {

this.db.delete(TABLE_NAME, null, null);

}

public List<String> selectAll() {

List<String> list = new ArrayList<String>();

Cursor cursor = this.db.query(TABLE_NAME, new String[] { "name" }, null, null, null, null, "name desc");

if (cursor.moveToFirst()) {

do {

list.add(cursor.getString(0));

} while (cursor.moveToNext());

}

if (cursor != null && !cursor.isClosed()) {

cursor.close();

}

return list;

}

private static class OpenHelper extends SQLiteOpenHelper {

OpenHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION);

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL("CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY, name TEXT)");

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

Log.w("Example", "Upgrading database, this will drop tables and recreate.");

db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);

onCreate(db);

}

}

}