Páginas

Pesquisar neste blog

Mostrando postagens com marcador Android. Mostrar todas as postagens
Mostrando postagens com marcador Android. Mostrar todas as postagens

2 de dezembro de 2015

Como Exibir Tabs Utilizando TabLayout e ViewPager no Android

A forma de programação para exibir Tabs no Android vem mudando em cada lançamento de uma nova versão do sistema operacional. A partir da API 22 do Android Lollipop surgiu uma nova forma de exibir telas com Tab, que possuem o efeito chamado de "Swipe". Este efeito permite visualizar cada Tab com um movimento horizontal na tela.

Mas e se quisermos utilizar a Tab no formato tradicional onde cada Tab é acessada clicando-se na aba. Ainda é possível montar este layout utilizando as classes TabLayout e ViewPager.

Para mostrar como podemos montar a tela com a apresentação tradicional de tabs, desenvolvi um projeto que exibe três Tabs de acordo com o apresentado na Figura 1.

Figura 1

O projeto é composto da tela principal MainActivity, das telas das Tabs a Tab1Fragment, Tab2Fragment e Tab3Fragment e da classe TabPagerAdapter utilizada para gerenciar os Fragments, neste caso as classes das Tabs.

O arquivo de layout da tela principal activity_main.xml deve ser composto de um TabLayout e de um ViewPager:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:padding="4dip"
    android:gravity="center_horizontal"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabMode="fixed"
        app:tabGravity="fill" />

    <android.support.v4.view.ViewPager 
xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v4.view.ViewPager>

</LinearLayout>

No widget TabLayout o atributo tabMode foi configurado como fixed, para que as Tabs fiquem fixadas e respondam ao clique na aba, ao invés do movimento de "swipe".

As telas de Tabs possuem cada uma somente um TextView para exibir um texto. Segue o código do arquivo xml que foi utilizado para construir a Tab1Fragment.


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="15dp"
    tools:context="br.com.romarconsultoria.tabexemplo.Tab1Fragment">

    <TextView android:layout_width="match_parent" 
android:layout_height="match_parent"
        android:text="Tela da Tab1"
        android:textSize="25sp"/>

</FrameLayout>

As classes Tab1Fragment, Tab2Fragment e Tab3Fragment são utilizadas para exibir o conteúdo de cada Tab. Segue o código da classe Tab1Fragment. As classes Tab2Fragment e Tab3Fragment são similares.


public class Tab1Fragment extends Fragment {

    public static Tab1Fragment newInstance() {
        Tab1Fragment fragment = new Tab1Fragment();
        return fragment;
    }

    public Tab1Fragment() {
        // Deve existir um construtor vazio
        // na classe que estende um Fragment
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_tab1, container, false);
    }

}

Para gerenciar as Tabs é necessário criar uma classe que estende a classe FragmentPagerAdapter responsável pela paginação das Tabs.  Criei a classe TabsPagerAdapter e implementei os métodos:

  • getItem(int): Retorna a tab que deve ser exibida de acordo com a posição selecionada.
  • getCount(): Retorna o número total de tabs.
  • getPageTitle(int): Retorna o título da tab de acordo com a posição selecionada. 

Os métodos getItem(int) e getCount() são obrigatórios na classe que estende a classe FragmentPagerAdapter.


public class TabsPagerAdapter extends FragmentPagerAdapter {
    private static final int NUM_TABS = 3;

    public TabsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        switch(position){
            case 0:
                return Tab1Fragment.newInstance();
            case 1:
                return Tab2Fragment.newInstance();
            default:
                return Tab3Fragment.newInstance();
        }
    }

    @Override
    public int getCount() {
        return NUM_TABS;
    }

    @Override
    public CharSequence getPageTitle(int position) {

        if (position == 0){
            return "Tab 1";
        }

        if (position == 1){
            return "Tab 2";
        }

        return "Tab 3";
    }
}
A classe MainActivity inicia o TabLayout, o ViewPager e configura o adaptador que as tabs devem utilizar.


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Tabs
        TabLayout tabs = (TabLayout) findViewById(R.id.tabs);
        ViewPager pager = (ViewPager) findViewById(R.id.pager);
        TabsPagerAdapter adapter = new TabsPagerAdapter(getSupportFragmentManager());

        pager.setAdapter(adapter);
        tabs.setupWithViewPager(pager);
    }
}
Pronto agora já é possível navegar nas tabs no formato fixo.

20 de dezembro de 2012

Como Exibir Dados do SQLite no ExpandableList

Na documentação do Android existem alguns exemplos de utilização do ExpandableList que é similar ao ListView, com a diferença que o ExpandableList exibe uma lista que pode ser expandida em dois níveis. Os dados que são exibidos no ExpandableList podem ser fornecidos de várias fontes, como por exemplo arrays.

Este post vai utilizar como fonte de dados, para preencher o ExpandableList, uma base de dados SQLite, e para isso utiliza como base o mesmo projeto do post SQLite em Aplicações Android, que possui uma base de dados de livros armazenados em uma base SQLite. Esta versão exibe uma tela com o título do livro em um nível e o nome do autor, ano e genêro do livro em outro nível do ExpandableList.

device-2012-12-19-173925

Para exibir as informações do livro no ExpandableList é necessário inserir no projeto uma classe para exibir o ExpandableList (classe ExpandableActivity), um arquivo de layout para as informações que são exibidas no segundo nível (expandable_child.xml),  e uma classe Adapter (LivroAdapter) para expor os dados do livro no ExpandableList.

A classe ExpandableList herda da classe ExpandableListActivity e configura o Adapter que é utilizado para exibir as informações dos livros.

public class ExpandableActivity extends ExpandableListActivity {
    private LivroDb livroDb;
    
   @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        livroDb = new LivroDb(this);
        
        LivroAdapter livroAdapter = new LivroAdapter(livroDb.getCursor(),
                this);
        setListAdapter(livroAdapter);
   }
    
   @Override
   protected void onDestroy() {
        super.onDestroy();     
        // Fecha a base de dados
        livroDb.close();
   }
}


O layout para exibir os dados do segundo nível do ExpandableList pode ser customizado, neste caso foram utilizados somente TextView.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView 
        android:id="@+id/textAutor"
        android:layout_width="match_parent"
        android:layout_height="40dp"
     />

     <TextView 
        android:id="@+id/textAno"
        android:layout_width="match_parent"
        android:layout_height="40dp"
     />
        
    <TextView 
        android:id="@+id/textGenero"
        android:layout_width="match_parent"
        android:layout_height="40dp"
     />
</LinearLayout>

A classe LivroAdapter herda da classe CursorTreeAdapter que expõe dados utilizando um Cursor. Esta classe utiliza o Cursor fornecido pelo SQLite e os métodos que devem ser implementados são:

public class LivroAdapter extends CursorTreeAdapter {
      LayoutInflater layoutInflater;
      
      public LivroAdapter(Cursor cursor, Context context) {
            super(cursor, context);
            layoutInflater = LayoutInflater.from(context);
      }
 
      // Exibe as informações do segundo nível.
      @Override
      protected void bindChildView(View view, Context context, Cursor cursor,
                  boolean isLastChild) {
              TextView textAutor = (TextView)view.findViewById(R.id.textAutor);
              textAutor.setText(cursor.getString(cursor.getColumnIndex("autor")));
              TextView textAno = (TextView)view.findViewById(R.id.textAno);
              textAno.setText(cursor.getString(cursor.getColumnIndex("ano_publicacao")));
              TextView textGenero = (TextView)view.findViewById(R.id.textGenero);
              textGenero.setText(cursor.getString(cursor.getColumnIndex("genero")));              
      }
 
      // Exibe as informações do primeiro nível.
      @Override
      protected void bindGroupView(View view, Context context, Cursor cursor,
                  boolean isExpanded) {
            TextView textTitulo = (TextView)view.findViewById(android.R.id.text1);
            textTitulo.setText(cursor.getString(cursor.getColumnIndex("titulo")));
      }
 
      // Lê o Cursor da base SQLite.
      @Override
      protected Cursor getChildrenCursor(Cursor groupCursor) {
            int id = groupCursor.getInt(groupCursor.getColumnIndex("_id"));
            return Principal.livros.getCursorById(id);
      }
 
      // Monta o layout do segundo nível.
      @Override
      protected View newChildView(Context context, Cursor cursor,
                  boolean isLastChild, ViewGroup parent) {
              View view = layoutInflater.inflate(
                R.layout.expandable_child, null);
              TextView textAutor = (TextView)view.findViewById(R.id.textAutor);
              textAutor.setText(cursor.getString(cursor.getColumnIndex("autor")));
              TextView textAno = (TextView)view.findViewById(R.id.textAno);
              textAno.setText(cursor.getString(cursor.getColumnIndex("ano_publicacao")));
              TextView textGenero = (TextView)view.findViewById(R.id.textGenero);
              textGenero.setText(cursor.getString(cursor.getColumnIndex("genero")));              
              
            return view;
      }
 
      // Monta o layout do primeiro nível.
      @Override
      protected View newGroupView(Context context, Cursor cursor,
                  boolean isExpanded, ViewGroup parent) {
            View view = layoutInflater.inflate(
                        android.R.layout.simple_expandable_list_item_1, null);
            TextView textTitulo = (TextView)view.findViewById(android.R.id.text1);
            textTitulo.setText(cursor.getString(cursor.getColumnIndex("titulo")));
            return view;
      }
 
}

As informações dos livros são exibidas no ExpandableList da seguinte forma:
imagem

O código fonte do projeto pode ser obtido no link Download do Projeto.

O emulador Android utilizado foi configurado com a API 15 (Android 4.0.3 Ice Cream Sandwich).

16 de outubro de 2012

Como Usar SQLite em Aplicações Android

Este post utiliza o SQLite para demonstrar como manipular informações em um Banco de Dados no Android. Foi criado um projeto para armazenar as informações de livros, tais como titulo, autor, ano de publicação e gênero. O projeto permite visualizar os livros cadastrados, inserir, alterar e excluir livros.

O projeto é composto pelas seguintes classes:
  • Livro: Classe  onde estão definidos os parâmetros do livro.
  • SQLiteHelper: Classe utilizada na criação e atualização do banco de dados.
  • LivroDb: Classe utilizada nas operações de consulta, inclusão e exclusão de livros.
  • Principal: Classe responsável pela tela inicial da aplicação.
  • VisualizarActivity: Classe responsável pela tela que exibe a relação de livros cadastrados na base de dados.
  • AlterarActivity: Classe responsável pela tela de alteração dos dados dos livros.
  • InsertActivity: Classe responsável pela tela de inserção do livro na base dados.
A Classe Livro é utilizada para manipular os parâmetros dos livros. Esta classe possui como parâmetros as mesmas colunas definidas na base de dados e implementa a interface Serializable que permite a serialização e deserialização da classe. Esta funcionalidade é utilizada para passar o objeto lista de livros de um Intent para outro, necessário na classe Principal, quando é necessário navegar da tela principal para a tela de visualização de livros.

public class Livro implements Serializable {
    private static final long serialVersionUID = -8666122216249625117L;
    private int id;
    private String titulo;
    private String autor;
    private String anoPublicacao;
    private String genero;
    private String[] livrosColumns;
    
    public String[] getLivrosColumns() {
        livrosColumns = new String[] {"_id", "titulo", "autor",
                "ano_publicacao", "genero"                
        };
        return livrosColumns;
    }    
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getTitulo() {
        return titulo;
    }
    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }
    public String getAutor() {
        return autor;
    }
    public void setAutor(String autor) {
        this.autor = autor;
    }
    public String getAnoPublicacao() {
        return anoPublicacao;
    }
    public void setAnoPublicacao(String anoPublicacao) {
        this.anoPublicacao = anoPublicacao;
    }
    public String getGenero() {
        return genero;
    }
    public void setGenero(String genero) {
        this.genero = genero;
    }
}


A Classe SQLiteHelper herda  da classe SQLiteOpenHelper e possui os métodos OnCreate(SQLiteDatabase) que cria a base de dados juntamente com a tabela livros e o método OnUpgrade(SQLiteDatabase, int, int) que faz a atualização da base de dados SQLite no caso de uma alteração no metadata da base, por exemplo em uma situação de criação de uma nova coluna.

public class SQLiteHelper extends SQLiteOpenHelper {
    public static final String TAG = "SQLiteHelper";
    public static final String DATABASE_NAME = "livros";
    public static final int DATABASE_VERSION = 1;
    private String scriptSQLCreate;
    private String scriptSQLDelete;
    
    public SQLiteHelper(Context context, String databaseName, 
            int databaseVersion, String scriptSQLCreate, 
            String scriptSQLDelete){
        super(context, databaseName, null, databaseVersion);
        this.scriptSQLCreate = scriptSQLCreate;
        this.scriptSQLDelete = scriptSQLDelete;    
    }

    /**
     * Cria a base de dados.
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        try {
            db.execSQL(scriptSQLCreate);
        } catch (SQLException e) {
            Log.e(TAG, e.toString());            
        }
    }

    /**
     * Faz o upgrade da base de dados.
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, 
            int newVersion) {
        try {
            // Exclui a tabela anterior
            db.execSQL(scriptSQLDelete);
            // Cria a nova tabela
            onCreate(db);
        } catch (SQLException e) {
            Log.e(TAG, e.toString());
        }
    }
}


A classe LivroDb  é composta pelos métodos:
  • LivroDb(Context): Construtor da classe que cria ou abre a base de dados se a mesma já foi criada.
  • close(): Fecha a base de dados se estiver aberta.
  • selectLivros(): Faz um busca na tabela livros retornando uma lista dos livros existentes na base de dados.
  • contentLivro(Livro): Utiliza a classe ContentValues para associar a coluna da tabela livros com o seu respectivo valor.
  • insertLivro(Livro): Insere um livro na base de dados.
  • excluirLivro(Livro): Exclui um livro da base de dados.
  • alterarLivro(Livro): Altera os dados do livro na base de dados.
public class LivroDb{
    private static final String TAG = "LivroDb";
    private static final String SCRIPT_DELETE_DATABASE = 
        "DROP TABLE IF EXISTS livros";

    private static final String SCRIPT_CREATE_DATABASE =
        "CREATE TABLE livros (" +
        "_id INTEGER NOT NULL PRIMARY KEY," + 
        "titulo TEXT," + 
        "autor TEXT," + 
        "ano_publicacao TEXT," + 
        "genero TEXT)";
    private static final String TABLE_NAME = "livros";
    private SQLiteHelper dbHelper;
    private SQLiteDatabase db;
    private List<Livro> livros;    
    
    public LivroDb(Context ctx){
        try {
            dbHelper = new SQLiteHelper(ctx, SQLiteHelper.DATABASE_NAME,
                    SQLiteHelper.DATABASE_VERSION, 
                    LivroDb.SCRIPT_CREATE_DATABASE,
                    LivroDb.SCRIPT_DELETE_DATABASE);

            livros = new ArrayList<Livro>();
            
            // Cria ou abre a base de dados
            db = dbHelper.getWritableDatabase();
            
        } catch (SQLiteException e) {
            Log.e(TAG, e.toString());
        }

    }
    
    public void close(){
        if (db != null) {
            if (db.isOpen() == true) {
                db.close();
            }
        }
    }
    
    public List<Livro> selectLivros(){
        Cursor cursor = null;
        livros.clear();
        try {
            cursor = db.query(LivroDb.TABLE_NAME, new Livro().getLivrosColumns(), 
                    null, null, null, null, null);
            
            if (cursor.getCount() > 0) {
                while (cursor.moveToNext()) {
                    Livro livro = new Livro();
                    
                    if (!cursor.isNull(cursor.getColumnIndex("_id"))) {
                        livro.setId(cursor.getInt(cursor.getColumnIndex("_id")));
                    }
                    
                    if (!cursor.isNull(cursor.getColumnIndex("titulo"))) {
                        livro.setTitulo(cursor.getString(
                                cursor.getColumnIndex("titulo")));
                    }
                    
                    if (!cursor.isNull(cursor.getColumnIndex("autor"))) {
                        livro.setAutor(cursor.getString(
                                cursor.getColumnIndex("autor")));
                    }
                    
                    if (!cursor.isNull(cursor.getColumnIndex("ano_publicacao"))) {
                        livro.setAnoPublicacao(cursor.getString(
                                cursor.getColumnIndex("ano_publicacao")));
                    }
                    
                    if (!cursor.isNull(cursor.getColumnIndex("genero"))) {
                        livro.setGenero(cursor.getString(
                                cursor.getColumnIndex("genero")));
                    }
                    
                    livros.add(livro);
                }
            }
            
        } catch (SQLiteException e) {
            Log.e(TAG, e.toString());
        }
        finally{
            if (cursor != null) {
                if (!cursor.isClosed()) {
                    cursor.close();
                }
            }
        }        
        return livros;
    }
    
    
    private ContentValues contentLivro(Livro livro){
        ContentValues values = new ContentValues();
        values.put("titulo", livro.getTitulo());
        values.put("autor", livro.getAutor());
        values.put("ano_publicacao", livro.getAnoPublicacao());
        values.put("genero", livro.getGenero());
        return values;
    }
    
    /**
     * Insere um livro.
     * @param livro
     * @return Retorna o id do livro inserido ou -1 se ocorrer
     * erro na inserção do livro.
     */
    public long insertLivro(Livro livro){
        long id = 0;
        
        try {
            ContentValues values = contentLivro(livro);
            id = db.insert(TABLE_NAME, "", values);
            
        } catch (SQLiteException e) {
            Log.e(TAG, e.toString());
        }        
        return id;
    }
    
    /**
     * Exclui um livro.
     * @param titulo Titulo do livro a ser excluído
     * @return
     */
    public boolean excluirLivro(String titulo){
        boolean resultado = false;
        try {
            String where = "titulo=?";
            String[] args = new String[]{titulo};
            
            int num = db.delete(TABLE_NAME, where, args);
            
            // Verifica se o livro foi excluída
            if (num == 1) {
                resultado = true;
            }            
        } catch (SQLiteException e) {
            Log.e(TAG, e.toString());
        }
        
        return resultado;
    }
    
    public boolean alterarLivro(Livro livro){
        boolean resultado = false;
        try {
            
            String where = "_id=?";
            String[] args = new String[]{String.valueOf(livro.getId())};
            
            int num = db.update(TABLE_NAME, contentLivro(livro), where, args);
            
            // Verifica se o livro foi alterado
            if (num == 1) {
                resultado = true;
            }            
        } catch (SQLiteException e) {
            Log.e(TAG, e.toString());
        }
        
        return resultado;
    }    
}


A classe Principal exibe o menu da aplicação em um ListView com os itens Visualizar, Inserir, Alterar,  Excluir. Esta classe é composta pelos métodos:
  • onCreate(Bundle): Inicializa a base de dados e monta o menu.
  • onDestroy(): Fecha a base de dados quando a aplicação é finalizada.
  • onItemClick(AdapterView, View, int, int): Herda da classe ListActivity e trata o evento click do ListView chamando o Intent apropriado de acordo com o item clicado no menu.
public class Principal extends ListActivity implements OnItemClickListener {
    public static LivroDb livros;
    
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // Cria ou abre a base de dados se já existe
        livros = new LivroDb(this);
        String[] menu = new String[] {"Visualizar", "Inserir",
                "Alterar", "Excluir"};
        
        ListView listView = getListView();
        listView.setAdapter(new ArrayAdapter<String>(this, 
                android.R.layout.simple_list_item_1, menu));
        listView.setOnItemClickListener(this);
        
    }
    
    @Override
    protected void onDestroy() {
         super.onDestroy();     
         // Fecha a base de dados
         livros.close();
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Serializable listLivros = (Serializable)livros.selectLivros();
        
        switch (position) {
        case 0: // Visualizar 
            Intent intentVisualizar = new Intent(this, VisualizarActivity.class);
            intentVisualizar.putExtra("livros", listLivros);
            intentVisualizar.putExtra("tipo", "visualizar");
            startActivity(intentVisualizar);
            break;

        case 1: // Inserir
            startActivity(new Intent(this, InsertActivity.class));
            break;
        
        case 2: // Alterar
            Intent intentAlterar = new Intent(this, VisualizarActivity.class);
            intentAlterar.putExtra("livros", listLivros);
            intentAlterar.putExtra("tipo", "alterar");
            startActivity(intentAlterar);
            break;
            
        case 3: // Excluir
            Intent intentExcluir = new Intent(this, VisualizarActivity.class);
            intentExcluir.putExtra("livros", listLivros);
            intentExcluir.putExtra("tipo", "excluir");
            startActivity(intentExcluir);
            break;
            
        default:
            break;
        }
    }
}

visualizar

A classe VisualizarActivity cria a tela de visualização da relação de livros cadastrados na base de dados. Esta tela além de exibir os livros cadastrados na base de dados, também é utilizada para permitir que o usuário selecione um livro para fazer alteração dos dados ou exclua o livro selecionado. Possui os métodos:
  • onCreate(Bundle): Inicializa as variáveis.
  • onResume(): Exibe a relação de livros.
  • onItemClick(AdapterView, View, int, long): Exibe a tela para alterar ou exclui o livro selecionado.
  • onDestroy(): Fecha a base de dados.
public class VisualizarActivity extends ListActivity implements OnItemClickListener {
    private ListView listView;
    private String tipo; // tipo de activity a ser chamada
    private LivroDb livroDb;
    List<Livro> livros;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        livroDb = new LivroDb(this);        
        listView = getListView();
        listView.setOnItemClickListener(this);
    
    }
    
    @SuppressWarnings("unchecked")
    @Override
    protected void onResume() {
        super.onResume();        
        
        String[] titulos = null;
        
        Intent intent = getIntent();
        
        if (intent != null) {
            livros = (ArrayList<Livro>) intent.getSerializableExtra("livros");
            
            titulos = new String[livros.size()];
            int i = 0;
            for (Livro livro : livros) {
                titulos[i] = livro.getTitulo();
                i++;
            }
            
            setListAdapter(new ArrayAdapter<String>(this,
                    android.R.layout.simple_list_item_1, titulos));

            // Define o tipo de Activity a ser chamada
            tipo = intent.getStringExtra("tipo");
            
            if (tipo.equals("alterar")) {
                setTitle("Selecione o livro para alterar");
            }else if (tipo.equals("excluir")) {
                setTitle("Selecione o livro para excluir");
            }
        }
    }
    
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        
        if (tipo.equals("alterar")) {
            
            // Armazena as informações do livro selecionado
            Livro livro = livros.get(position);
            // Chama a tela de Alterar passando as informações do livro
            // como parâmetro
            Intent intent = new Intent(this, AlterarActivity.class);
            intent.putExtra("livro", livro);
            startActivity(intent);
        }
        
        if (tipo.equals("excluir")) {
            String titulo = (String) listView.getItemAtPosition(position);
            boolean excluiuLivro = livroDb.excluirLivro(titulo);
            
            if (excluiuLivro) {
                Toast.makeText(this, "O livro " + titulo + " foi excluído com sucesso",
                        Toast.LENGTH_SHORT).show();
            }else{
                Toast.makeText(this, "O livro " + titulo + " não foi excluído com sucesso",
                        Toast.LENGTH_SHORT).show();
            }
        }
        finish();
    }
        
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (livroDb != null) {
            livroDb.close();
        }
    }

}
visualizar

A classe InsertActivity cria a tela utilizada para inserir o livro. Possui os métodos:
  • onCreate(Bundle): Monta a tela de inserção dos dados do livro.
  • onClick(View): Insere os dados do livro no base de dados. Método chamado quando o botão Inserir é clicado.
  • onDestroy(): Fecha a base de dados.
public class InsertActivity extends Activity implements OnClickListener {
    private EditText editTitulo;
    private EditText editAutor;
    private EditText editAno;
    private EditText editGenero;
    private Button buttonInserir;
    private LivroDb livroDb;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.insere_altera);
        setTitle("Inserir Livro");
        editTitulo = (EditText)findViewById(R.id.editTitulo);
        editAutor = (EditText)findViewById(R.id.editAutor);
        editAno = (EditText)findViewById(R.id.editAno);
        editGenero = (EditText)findViewById(R.id.editGenero);
        buttonInserir = (Button)findViewById(R.id.buttonInserirAlterar);
        buttonInserir.setText("Inserir");
        
        buttonInserir.setOnClickListener(this);
        
    }

    @Override
    public void onClick(View arg0) {
        Livro livro = new Livro();
        livroDb = new LivroDb(this);
        long id = 0;
        
        livro.setTitulo(editTitulo.getText().toString());
        livro.setAutor(editAutor.getText().toString());
        livro.setAnoPublicacao(editAno.getText().toString());
        livro.setGenero(editGenero.getText().toString());
        
        id = livroDb.insertLivro(livro);
        
        if (id != -1) {
            Toast.makeText(this, "O livro foi inserido com sucesso.", Toast.LENGTH_LONG).show();
        }
        
        livroDb.close();
        
        finish();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (livroDb != null) {
            livroDb.close();
        }
    }
inserir

A classe AlterarActivity altera os dados do livro já cadastrado na base de dados. Possui os métodos:
  • onCreate(Bundle): Monta a tela com os dados do livro cadastrados na base de dados, permitindo que o usuário faça as alterações necessárias e salve na base de dados.
  • onClick(View): Faz a alteração das informações do livro na base de dados.
  • onDestroy(): Fecha a base de dados.
public class AlterarActivity extends Activity implements OnClickListener {
    private EditText editTitulo;
    private EditText editAutor;
    private EditText editAno;
    private EditText editGenero;
    private Button buttonAlterar;
    private LivroDb livroDb;
    private Livro livro;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.insere_altera);
        setTitle("Alterar livro");
        editTitulo = (EditText)findViewById(R.id.editTitulo);
        editAutor = (EditText)findViewById(R.id.editAutor);
        editAno = (EditText)findViewById(R.id.editAno);
        editGenero = (EditText)findViewById(R.id.editGenero);
        buttonAlterar = (Button)findViewById(R.id.buttonInserirAlterar);
        buttonAlterar.setText("Alterar");
        buttonAlterar.setOnClickListener(this);
        
        Intent intent = getIntent();
        if (intent != null) {
            livro = (Livro) intent.getSerializableExtra("livro");
            // Exibe as informações do livro selecionado
            editTitulo.setText(livro.getTitulo());
            editAutor.setText(livro.getAutor());
            editAno.setText(livro.getAnoPublicacao());
            editGenero.setText(livro.getGenero());
        }
    }

    @Override
    public void onClick(View v) {
        livroDb = new LivroDb(this);
        boolean resultado = false;
        
        Livro livroAlterado = new Livro();
        // O id do livro com os dados alterados permanece o mesmo
        livroAlterado.setId(livro.getId());
        livroAlterado.setTitulo(editTitulo.getText().toString());
        livroAlterado.setAutor(editAutor.getText().toString());
        livroAlterado.setAnoPublicacao(editAno.getText().toString());
        livroAlterado.setGenero(editGenero.getText().toString());
        
        resultado = livroDb.alterarLivro(livroAlterado);
        
        if (resultado == true) {
            Toast.makeText(this, "O livro foi alterado com sucesso.", Toast.LENGTH_LONG).show();
        }
        
        livroDb.close();
        
        finish();        
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (livroDb != null) {
            livroDb.close();
        }
    }
}

alterar2

O arquivo da base de dados livros, pode ser obtido no diretório data/data/br.com.exemplo.sqlite/database através do emulador do Android no Eclipse.

diretorio

As classes não detalhadas no post bem como o projeto podem ser obtidos aqui
O projeto foi desenvolvido com a API 8 do Android e testado no emulador com Android versão 2.2.

Post Relacionado:

23 de novembro de 2011

Como Usar HttpURLConnection para Receber Dados no Android



No Android existem duas formas de enviar e receber dados usando HTTP. Uma é através do Apache HTTP e a outra através de HttpURLConnection.

No post Como Receber Dados de um WebService no Android demonstrei como receber dados de um webservice utilizando o Apache HTTP (DefaultHttpClient).

Recentemente foi publicado no blog do google Android´s HTTP Clients um post informando que a API do Apache HTTP não está mais sendo atualizada, por ser muito grande e difícil de implementar melhorias sem quebrar as compatibilidades. Por esse motivo eles estão trabalhando na API HttpURLConnection.

A API HttpURLConnection é de uso geral, leve, de um tamanho pequeno e atende a maioria das aplicações.

Em dispositivos com a versão 2.2 (Froyo) ou anteriores a API HttpURLConnection tinha alguns bugs. Da versão 2.3 (Gingerbread) para frente esta API é melhor para o Android porque reduz o uso da rede, melhora a velocidade e economiza bateria.

Resumindo até a versão 2.2 (Froyo) é melhor utilizar o Apache HTTP, para as versões 2.3 (Gingerbread) para frente é melhor utilizar a API HttpURLConnection.

Neste post vou utilizar o mesmo webservice e o mesmo projeto do post Como Receber Dados de um webService no Android alterando somente a forma de receber os dados. Ao invés de utilizar a classe DefaultHttpClient vou utilizar a classe HttpURLConnection, portanto substituir a classe WebService.java do post Como Receber Dados de um webService no Android por:
Listagem 1:
public class WebService {
    private static final int TAM_MAX_BUFFER = 10240; // 10Kbytes
    private String urlWebService;
    
    public WebService(String url) {
        this.urlWebService = url;
    }
    
    public String getEstados(){
        String resultado = "";
        HttpURLConnection urlConnection = null;
        
        try {
          URL url = new URL(urlWebService);
          
          urlConnection = (HttpURLConnection) url.openConnection();
          urlConnection.setDoOutput(true);
          urlConnection.setRequestMethod("POST");
          urlConnection.setRequestProperty("Content-Type", 
                  "text/xml; charset=utf-8");
          urlConnection.setRequestProperty("SOAPAction", 
                  "http://tempuri.org/GetEstados");
                    
          String request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
              "<soap:Envelope " + 
                  "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
                  "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
                  "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
              "<soap:Body>" +
              "<GetEstadosResponse xmlns=\"http://tempuri.org/\">" +
              "<GetEstadosResult>string</GetEstadosResult>" +
              "</GetEstadosResponse>" +
              "</soap:Body>" +
              "</soap:Envelope>";
          
          OutputStream out = urlConnection.getOutputStream();
          out.write(request.getBytes());
          
          // Verifica se a resposta está ok antes de solicitar os dados
          if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
              InputStream in = new BufferedInputStream(
                      urlConnection.getInputStream());    
              
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(in,
                                "UTF-8"), TAM_MAX_BUFFER);
                
                StringBuilder builder = new StringBuilder();
                
                for (String line = null ; (line = reader.readLine())!= null;) {
                    builder.append(line).append("\n");
                }
                
                resultado = builder.toString();
                
                // Retira a string <?xml version="1.0" encoding="utf-8" ?> 
                // <string xmlns="http://tempuri.org/"> e a tag </GetEstadosResult> 
                // para obter o resultado em Json, já que o webservice está
                // retornando uma string
                Integer firstTagString = resultado.indexOf("<GetEstadosResult");
                Integer posXml = resultado.indexOf(">", firstTagString);
                Integer posTagString = resultado.indexOf("</GetEstadosResult>");
                resultado = resultado.substring(posXml + 1, posTagString + 1);
          }
          else{
              Log.e("WebService", 
                      "ResponseCode: " + urlConnection.getResponseMessage());
          }

        }
        catch(IOException e){
            Log.e("WebService", e.toString());
        }
        finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
       }
        
        return resultado;
    }
}

No método getEstados() é utilizada a classe HttpURLConnection para obter os dados do webservice. Para utilizar esta classe é necessário configurar os métodos setDoOutput(Boolean) que informa se este HttpURLConnection permite output, no nosso caso deve ser setado como true, no método setRequestMethod(String), e setRequestProperty(String) deve ser passado como parâmetro as informações do webservice. Depois é necessário montar a requisição do webservice e através da classe OutputStream escrever os dados no HttpURLConnection.

Antes de ler os dados verificar através do método getResponseCode() se a resposta do HttpURLConnection está OK.