Alguns smartphones com Android possuem botões físicos. Um deles dispara um evento que o Android trata como uma solicitação de busca. Se a aplicação não tratar esse tipo de evento o sistema operacional irá tratá-la da forma que estiver configurado, na maioria dos casos um navegador de internet irá abrir com um textfield para inserir alguma informação para ser buscada.
O que eu quero mostrar neste artigo é uma forma da aplicação que você estiver desenvolvedor tratar esse evento de busca ao clicar no botão físico de busca.
Iremos criar um novo método em nossa classe LinguagemDataSource que recebe um string. Essa string servirá de filtro para o nome das linguagens cadastradas no banco.
Arquivo: LinguagemDataSource.java
package com.diegorubin.search_list;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class LinguagemDataSource {
private SQLiteDatabase db;
private DatabaseHelper helper;
public LinguagemDataSource(Context context) {
helper = new DatabaseHelper(context);
db = helper.getDatabase();
}
/**
* Filtrando as linguagens cadastradas no banco.
* Este método será utilizado ao pressionar o botão de busca.
*/
public List<JSONObject> filterByNome(String nome) {
List<JSONObject> result = new ArrayList<JSONObject>();
Cursor cursor =
db.query("linguagens", new String[]{"nome", "descricao"},
"nome like '%" + nome + "%'",
null, null, null, "nome ASC" /*ordenando pelo nome*/);
cursor.moveToFirst();
while(!cursor.isAfterLast()) {
result.add(readRow(cursor));
cursor.moveToNext();
}
cursor.close();
return result;
}
/**
* Recuperando todas a linguagens cadastradas no nosso
* banco de dados.
* Iremos retorná-los em List<JSONObject>, pois é o
* formato que o nosso adapter espera.
*/
public List<JSONObject> allLinguagens() {
List<JSONObject> result = new ArrayList<JSONObject>();
// Iremos buscar todas as linguagens cadastradas no banco
// As colunas que iremos selecionar serão nome e descricao
// O objeto de retorno contém a referencias das linhas retornadas
Cursor cursor =
db.query("linguagens", new String[]{"nome", "descricao"},
null, /* buscaremos todas, nao precisamos de nenhuma condicao*/
null, null, null, "nome ASC" /*ordenando pelo nome*/);
cursor.moveToFirst();
while(!cursor.isAfterLast()) {
result.add(readRow(cursor));
cursor.moveToNext();
}
cursor.close();
return result;
}
/**
* Método auxiliar para ler resultado da query
*/
private JSONObject readRow(Cursor cursor) {
JSONObject obj = new JSONObject();
try{
// As colunas são recuperadas na ordem que foram selecionadas
obj.put("nome", cursor.getString(0));
obj.put("descricao",cursor.getString(1));
}catch (JSONException e) {
}
return obj;
}
}
Temos que alterar a classe SearchListActivity. Agora iremos checar se foi chamado após o callback de busca ou não. Se ele atender o primeiro caso, usaremos a String que foi usada como entrada no dialogo de busca para filtrar os nossos dados.
Arquivo: SearchListActivity.java
package com.diegorubin.search_list;
import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Toast;
public class SearchListActivity extends Activity {
private ListView lstLinguagens;
private List<JSONObject> linguagens;
private LinguagemArrayAdapter adapter;
private LinguagemDataSource source;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Buscando o elemento Listview da nossa interface principal interface
lstLinguagens = (ListView) findViewById(R.id.lstLinguagens);
source = new LinguagemDataSource(getApplicationContext());
//Verifica se a activity foi chamada através do callback de busca
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
// Recupera do banco as informações filtradas
linguagens = source.filterByNome(query);
} else {
// Recupera do banco as informações que serão utilizados em nosso adapter
linguagens = source.allLinguagens();
}
// Passamos a lista de exemplo para gerar nosso adpater
adapter = new LinguagemArrayAdapter(getApplicationContext(), R.layout.linguagem, linguagens);
// Setando o adapter em nossa ListView
lstLinguagens.setAdapter(adapter);
// Setando callback ao selecionar um item da lista
lstLinguagens.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
try{
JSONObject linguagem = linguagens.get(position);
String descricao = linguagem.getString("descricao");
Toast.makeText(getApplicationContext(), descricao, 10000).show();
}catch (JSONException e) {
}
}
});
}
}
Um novo arquivo deve ser criado em res/xml chamado searchconfig.xml, bom, esse nome não é obrigatório, mas acredito que seja um bom nome para ele. O conteúdo dele esta logo abaixo, com as configurações do dialogo de busca da nossa aplicação.
Arquivo: searchconf.xml
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_name"
android:searchMode="showSearchLabelAsBadge"
android:hint="Filtrar" >
</searchable>
Agora é necessário fazer algumas alterações no arquivo AndroidManifest.xml
Arquivo: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.diegorubin.search_list"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="7" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".SearchListActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- Avisa que nossa activity pode ser utilizada na busca -->
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<!-- Setando esta activity para ser utilizada como callback da busca -->
<meta-data android:name="android.app.default_searchable"
android:value=".SearchListActivity" />
<!-- configuração do dialogo de busca -->
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchconf"/>
</activity>
</application>
</manifest>
O elemento meta-data com o atributo android:name igual a android.app.default_searchable deve ser setada em todas as activity’s que irão tratar o evento do botão fisico de busca.
Agora, ao pressionar o botão de busca, nossa aplicação tratará o evento e não o sistema. Não será aberto, por exemplo, o navegador, mas sim um dialogo para entrada de dados e esses dados repassado a nossa Activity.
Este foi o último arquivo da série sobre desenvolvimento para Android no CarnAndroid. Brincadeiras a parte, acredito que tenha alcançado meu objetivo.
Nosso projeto chegou a versão final, e estará no repositório do blog no github. Qualquer dúvida ou sugestão, por favor, utilizem o sistema de comentário do site.
Agradeço as pessoas que acompanharam os posts e em breve espero escrever mais sobre o desenvolvimento de aplicações para Android.
[]’s