Help (listview + ArrayAdapter + banco de dados)

Pessoal, boa tarde.

Ao certo já estou procurando a mais de uma semana antes de vir aqui colocar mais um post, e o mais próximo que cheguei em relação a minha pergunta foi utilização do cursorLoader.

Cenário.

Android 2.3 ou superior.

Caso:

Banco de dados com queries de insert e delet - OK

Classe ArrayAdapter - OK

Problema:

Tenho que fazer um listview, com forme imagem, que quando clique em adicionar a lista seja atualizada automaticamente assim como para o delet que é o meu problema.
Como meu insert fica na classe que chama a minha Activity e constroi meu adapter e listview, o que eu fiz foi separar dentro de um método, a parte que monta o meu adapter colocando dentro desde a parte que chama no banco de dados até a construção da minha listviwer logo, quando faço meu insert eu chamo esse método, meio gambiarra mais funciona.
O meu problema esta o delet, como eu faço a construção da minha listview dentro do ArrayAdapter, e é lá que insiro o botao de delete, como na imagem, nao estou conseguindo fazer esta gambiarra logo atualizar minha lista.

Pessoal preciso realmente disso, apesar de bobo, levo isso em conta para quem já tem experiência, acredito que e uma “baita” base pois todo o programinha que pretendo construir terá este mesmo fundamento.

Desde jà deixo meu sinceros agradecimentos a você que se deu o trabalho de ler o que escrevi.

Abraço.
Classe ArrayAdapter:

Classe Activity:

Layout:

Fala Felipe!

Cara eu não entendi direito a sua dúvida…

Você não consegue criar o item da lista também com o botão delete? Ou você consegue criar o item com o botão delete, mas quando vc clica a lista não é atualizada?

Se for o segundo caso, aplique um invalidateViews(); depois do getLista…

Se não for isso, explique um pouco melhor a situação…

Boa sorte!

[quote=ARATHORN]Fala Felipe!

Cara eu não entendi direito a sua dúvida…

Você não consegue criar o item da lista também com o botão delete? Ou você consegue criar o item com o botão delete, mas quando vc clica a lista não é atualizada?

Se for o segundo caso, aplique um invalidateViews(); depois do getLista…

Se não for isso, explique um pouco melhor a situação…

Boa sorte![/quote]

ARATHORN desde já agradeço.

O que eu preciso é que após um insert ou um delet está minha listview, que recebe os dados de um SQLite, seja atualizada, isso é o que eu preciso.

Como o meu insert fica dentro da minha classe que monta a minha ListView, consegui fazer uma gambiarra para reconstruir a minha listview após o insert porém, na hora do delete, por eu utilizar uma ArrayAdapter para montar o meu listview personalizado e conseguentemente o meu botão de delete fica dentro do meu ArrayAdapter eu não consigo fazer essa gabiarra do refresh, ele funciona normal deletando os dados do SQL mas para ver as modificações tenho que sair e entrar em minha Activity.

ARATHORN no final é, não tenho a certeza de estar fazendo correto.

Mais uma vez obrigado.

Pessoalmente prefiro criar uma interface para notificar a classe pai que foi clicado no botão, mas vamos do seu jeito:

[code]//Classe Adater
//Ao declarar o botão adicione como tag o “employee” que ele é referente
//Sou meio ruim de explicação, mas em geral é porque não é possível segurar a referencia do objeto employee chamando o dentro do onClick no metodo getView.

employeeWrapper.delete.setTag(employee);
employeeWrapper.delete.setOnClickListener(new …

    @Override
    public void onClick(View v){

       Employee employee = (Employee) v.getTag();
       //resto do seu código.
    }

[/code]

[quote=fabriciov]Pessoalmente prefiro criar uma interface para notificar a classe pai que foi clicado no botão, mas vamos do seu jeito:

[code]//Classe Adater
//Ao declarar o botão adicione como tag o “employee” que ele é referente
//Sou meio ruim de explicação, mas em geral é porque não é possível segurar a referencia do objeto employee chamando o dentro do onClick no metodo getView.

employeeWrapper.delete.setTag(employee);
employeeWrapper.delete.setOnClickListener(new …

    @Override
    public void onClick(View v){

       Employee employee = (Employee) v.getTag();
       //resto do seu código.
    }

[/code]

[/quote]

fabriciov desculpa a demora, mas o projeto acabou envolvendo muitas coisas além dessa e preferir atacar as tais, com tudo mais tranquilo decidi pesquisar novamente essa parte.

Primeiramente o que fiz, em meu desespero, foi confirma em uma nova Activity, a exclusão do usuário logo, passo para ela o ID para que seja excluído colocando no OnPause da activity, que apresento a Listview, o close() dela logo, quando confirmo a exclusão ou cancelo carrego a Activity assim como minha listview do 0(zero). Funcionou mas achei gambiarra a o que eu fiz.

Acabei implementando o código que você citou, mas na parte do onClick não consegui compreender o que faço assim como notificar a minha listview que ela foi modificada.
Poderia, sem querer abusar, colocar mais detalhes.

Quem puder ajudar com uma outra forma de fazer, também agradeço. Abraços.

Para entender o funcionamento da Tag de um componente, imagine um armário cheio de gavetas iguais, para diferenciar você coloca um pequeno papel com algo escrito para que seja fácil a identificação de cada.
Nesse caso, quando o metodo do adapter getView é chamado é criado um botão (igual todos os outros) e para saber que ao clicar nesse botão é para “trabalhar” com um tal objeto, você tem a opção de guarda-lo como uma tag dentro do objeto desse botão.

Assim, quando você clica no botão é chamado o listener de click, dentro deste listener há a uma callback (onClick(View)) que avisa que foi clicado e como parâmetro você recebe uma View, esta view é o objeto em que o listener foi setado (o botão).

Como ao clicar no botão você recebe o objeto do Botão, é possível extrair sua Tag, ou seja, extrair o Employee em que aquele botão representa.

Corrigindo seu código:

[code]
@Override
public void onClick(View v){

   Employee emp = (Employee ) v.getTag(); //chamando a View (o Botão delete) recebida e recuperando a tag armazenada.
   Bundle params = new Bundle();
   params.putSerializable("position", Integer.toString(emp.getPosition()));  
   //reto do código

}[/code]

Obs1: Você pode adicionar qualquer variavel nativa diretamente ao bundle (int utiliza putInt, long utiliza putLong)
Obs2. String não precisa utilizar Serialized, putString é o mais aconselhável, deixando o putSerialized para objetos que implementam Serialized
Obs3. Em vez de chamar uma activity creio que criar uma Dialog traria uma experiencia melhor ao usuário.

Edit:
Sobre atualizar a lista…

Provavelmente no seu BaseAdapter tem uma lista de Employee que é utilizada para criar cada item da lista, ao receber a notificação para deletar o objeto, remova-o desta lista e chama o metodo notifyDataSetChanged();
a ListView automaticamente sera recriada com os novos dados.

[quote=fabriciov]Para entender o funcionamento da Tag de um componente, imagine um armário cheio de gavetas iguais, para diferenciar você coloca um pequeno papel com algo escrito para que seja fácil a identificação de cada.
Nesse caso, quando o metodo do adapter getView é chamado é criado um botão (igual todos os outros) e para saber que ao clicar nesse botão é para “trabalhar” com um tal objeto, você tem a opção de guarda-lo como uma tag dentro do objeto desse botão.

Assim, quando você clica no botão é chamado o listener de click, dentro deste listener há a uma callback (onClick(View)) que avisa que foi clicado e como parâmetro você recebe uma View, esta view é o objeto em que o listener foi setado (o botão).

Como ao clicar no botão você recebe o objeto do Botão, é possível extrair sua Tag, ou seja, extrair o Employee em que aquele botão representa.

Corrigindo seu código:

[code]
@Override
public void onClick(View v){

   Employee emp = (Employee ) v.getTag(); //chamando a View (o Botão delete) recebida e recuperando a tag armazenada.
   Bundle params = new Bundle();
   params.putSerializable("position", Integer.toString(emp.getPosition()));  
   //reto do código

}[/code]

Obs1: Você pode adicionar qualquer variavel nativa diretamente ao bundle (int utiliza putInt, long utiliza putLong)
Obs2. String não precisa utilizar Serialized, putString é o mais aconselhável, deixando o putSerialized para objetos que implementam Serialized
Obs3. Em vez de chamar uma activity creio que criar uma Dialog traria uma experiencia melhor ao usuário.

Edit:
Sobre atualizar a lista…

Provavelmente no seu BaseAdapter tem uma lista de Employee que é utilizada para criar cada item da lista, ao receber a notificação para deletar o objeto, remova-o desta lista e chama o metodo notifyDataSetChanged();
a ListView automaticamente sera recriada com os novos dados.[/quote]

fabriciov se você fala que e ruim de explicação, não queria nem vê se fosse bom rssss…
Primeiramente meu muito obrigado pela explicação, só como questionamento para entender a parte de recriar a lista,

Primeiro:

Tenho que fazer “3 coisas”,

1º excluir do meu banco de dados.
2º excluir da minha list Adapter
3º chamar notifyDataSetChanged();

É isso?

Segundo

Quando você fala que “Provavelmente no seu BaseAdapter tem uma lista de Employee que é utilizada para criar cada item da lista, ao receber a notificação para deletar o objeto, remova-o desta lista e chama o metodo notifyDataSetChanged();

Essa minha lista de Employee está sendo criada dentro da minha Main você aconselha criar essa lista separada para que seja possível acessa-lá de qualquer classe ou Activicty assim como modifica-lá?, conforme citado anteriormente na primeira resposta!?

Mais uma vez obrigado.

Mesmo sendo criada na Main você passa essa lista para a classe do BaseAdapter, então, é so remover do banco, se foi bem sucedido apenas fale para remover o objeto em questão e notifique o adapter.

Achei mais fácil fazer um exemplo, o código ja tem alguns comentários… veja se consegue entender.]

[code]
//outro arquivo (interface)
public interface ISqlListener {

	public void onRemove(Employee emp);

	public void onError(Employee emp, Exception e);
}[/code]

[code] //outro arquivo
public static class SqlUtil {

		//Como acesso ao banco de dados é uma tarefa bloqueante, não é aconselhável executa-la na thread principal
		//Esse metodo inicia uma AsyncTask e utiliza de um listener(interface) para notificar quem a chamou se a remoção 
		//foi um sucesso ou deu erro.
		public static void remove(final Employee employee, final ISqlListener listener) {

			AsyncTask at = new AsyncTask<Void, Void, Void>() {

				@Override
				protected Void doInBackground(Void... arg0) {

					try {
						//Código para remover
						listener.onRemove(employee);	 //se foi um sucesso, notificar que removeu					
					} catch (Exception e) {
						listener.onError(employee, e);  //se deu erro, notificar que não foi
					}
					return null;
				};
			};
			at.execute();
		}
	}[/code]

[code]
public class MyAdapter extends BaseAdapter{

//Lista de Employees
private ArrayList<Employee> mEmployeeList = null;


//Quando a tarefa de remover do banco terminar (bem ou mal) o respetivo metodo vai receber o evento
//fazendo com que remova da lista de employee e notificando o adapter para atualizar.
private ISqlListener mSqlListener = new ISqlListener(){

	@Override
	public void onRemove(Employee emp) {
		mEmployeeList.remove(emp);
		notifyDataSetChanged();			
	}

	@Override
	public void onError(Employee emp, Exception e) {
		Log.e("MyAdapter", e.getMessage());
	}
	
};

public MyAdapter(ArrayList<Employee> employeeList) {
	mEmployeeList = employeeList;
}

@Override
public int getCount() {
	return mEmployeeList.size();
}

@Override
public Object getItem(int arg0) {
	return mEmployeeList.get(arg0);
}

@Override
public long getItemId(int arg0) {
	return 0;
}

@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {

	Employee employee = mEmployeeList.get(arg0);

	Button button = new Button(null); // apenas para o exemplo
	button.setTag(employee);

	button.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {
			Employee emp = (Employee) v.getTag();
			 //envia o employee a ser removido juntamente com o listener
			SqlUtil.remove(emp, mSqlListener); 
		}
	});

	return null;
}

}[/code]

[quote=fabriciov]Mesmo sendo criada na Main você passa essa lista para a classe do BaseAdapter, então, é so remover do banco, se foi bem sucedido apenas fale para remover o objeto em questão e notifique o adapter.

Achei mais fácil fazer um exemplo, o código ja tem alguns comentários… veja se consegue entender.]

[code]
//outro arquivo (interface)
public interface ISqlListener {

	public void onRemove(Employee emp);

	public void onError(Employee emp, Exception e);
}[/code]

[code] //outro arquivo
public static class SqlUtil {

		//Como acesso ao banco de dados é uma tarefa bloqueante, não é aconselhável executa-la na thread principal
		//Esse metodo inicia uma AsyncTask e utiliza de um listener(interface) para notificar quem a chamou se a remoção 
		//foi um sucesso ou deu erro.
		public static void remove(final Employee employee, final ISqlListener listener) {

			AsyncTask at = new AsyncTask<Void, Void, Void>() {

				@Override
				protected Void doInBackground(Void... arg0) {

					try {
						//Código para remover
						listener.onRemove(employee);	 //se foi um sucesso, notificar que removeu					
					} catch (Exception e) {
						listener.onError(employee, e);  //se deu erro, notificar que não foi
					}
					return null;
				};
			};
			at.execute();
		}
	}[/code]

[code]
public class MyAdapter extends BaseAdapter{

//Lista de Employees
private ArrayList<Employee> mEmployeeList = null;


//Quando a tarefa de remover do banco terminar (bem ou mal) o respetivo metodo vai receber o evento
//fazendo com que remova da lista de employee e notificando o adapter para atualizar.
private ISqlListener mSqlListener = new ISqlListener(){

	@Override
	public void onRemove(Employee emp) {
		mEmployeeList.remove(emp);
		notifyDataSetChanged();			
	}

	@Override
	public void onError(Employee emp, Exception e) {
		Log.e("MyAdapter", e.getMessage());
	}
	
};

public MyAdapter(ArrayList<Employee> employeeList) {
	mEmployeeList = employeeList;
}

@Override
public int getCount() {
	return mEmployeeList.size();
}

@Override
public Object getItem(int arg0) {
	return mEmployeeList.get(arg0);
}

@Override
public long getItemId(int arg0) {
	return 0;
}

@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {

	Employee employee = mEmployeeList.get(arg0);

	Button button = new Button(null); // apenas para o exemplo
	button.setTag(employee);

	button.setOnClickListener(new OnClickListener() {

		@Override
		public void onClick(View v) {
			Employee emp = (Employee) v.getTag();
			 //envia o employee a ser removido juntamente com o listener
			SqlUtil.remove(emp, mSqlListener); 
		}
	});

	return null;
}

}[/code]
[/quote]

fabriciov, vou testar esse final de semana e durante a mesma coloco a resposta e até mesmo, caso consiga, a lógica do código.

Acabei de pegar uma serviço de WS na empresa novamente tenho que congelar esse :D.

Obrigado!

Pessoal,

Para enriquecimento do forum, abaixo colocarei a solução encontrada por mim, para resolução do problema em questão.

Devemos considerar que estamos trabalhando com um ArrayAdapter<OBJETO_CRIADO>

Dentro do meu código, eu crio um objeto ArrayList<OBJETO_CRIADO> que recebe esse meus views logo, quando quiser modificar essa minha lista que será implementado no meu listview, bata eu remover o objeto de sua ArrayList e depois notificar, conforme código abaixo:

[code]
//Pegando o identificador do item que foi clicado
Employee emp = (Employee) v.getTag();

//Passando para o meu método static dentro da minha classe do banco de dados o ID que desejo excluir.
helper.setDeleteEmployee(Integer.toString(employee.getPosition()));
//Removendo o Objeto de meu employees(Que é um objeto em ArrayList<OBJETO_CRIADO>
employees.remove(emp);
//Notificando a alteração para update.
notifyDataSetChanged();
//Comunicando que foi encerrado.
Toast.makeText(FluidPontoConstant.currentActivity, “O funcionário “+employee.getName()+” foi removido com sucesso!”, Toast.LENGTH_SHORT).show();[/code]

Qualquer coisa estamos as ordens e agradeço d+ a todos q ajudaram no desenvolvimento assim como desenrolar do tópico.