Problemas performance ListView carregado com cursor

1 resposta
aboult

Boa tarde pessoal.

Estou tendo problemas com a performance de um ListView, quando comecei o desenvolvimento encontrei um tutorial na internet que ensinava a carregá-lo desta maneira que implementei e havia ficado bem veloz pois eram poucos dados, mas após o aumento do número de dados começou a ficar muito lento para carregar.

Gostaria de saber como posso contornar este problema ou se há alguma outra maneira de modificar o carregamento do ListView.

Minha estrutura esta assim:

- Estou executando este processo dentro do doInBackground de uma AsyncTask:

cliente = new Cliente();
				cursorClientes = cliente.CarregaTodos();
				
				if(cursorClientes!=null){
					
					if(cursorClientes.getCount() > 0){
						
						cursorClientes.moveToFirst();
				                while (!cursorClientes.isAfterLast()) {
				        	       cliente = new Cliente(cursorClientes.getInt(0));
				        	       arrClientes.add(cliente);
				        	       cursorClientes.moveToNext();
				                }
					}
				}

E no meu onPostExecute eu carrego o meu adapter:

@Override
		protected void onPostExecute(List<Cliente> result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			progressDialog.dismiss();
			if(!(arrClientes.size()>0)){
				Toast.makeText(getBaseContext(), "Você não possui Clientes Cadastrados!", Toast.LENGTH_LONG).show();
			}else{
				setListAdapter(new ClienteAdapter(Singleton.getContextoAplicacao(), result));
			}
		}

Na minha classe Cliente eu tenho o meu método: CarregaTodos() que sobrescreve o método da minha classe de Persistência:

Classe Cliente:

@Override
	public Cursor CarregaTodos(){
		
		//this.Status = eStatus.CarregaTodos;
		this.setTabela(this.getClass().getSimpleName());
		this.setTabelaOrderBy("Identificacao");

		return super.CarregaTodos();
	}

Classe Persistencia:

public Cursor CarregaTodos(){

		DataBase = new DadosBD(this.getContexto());
		RsAtual = DataBase.ExecSelect(Tabela, TabelaColunaComposta, TabelaSelecao, TabelaSelecaoArgumentos, TabelaGroupBy, TabelaHaving, TabelaOrderBy);
		
		if(RsAtual.moveToNext()){
			
			if(DataBase!=null){
				DataBase.fecharBanco();
			}
			return RsAtual;
			
		} else{
			
			if(DataBase!=null){
				DataBase.fecharBanco();
			}
			if(RsAtual!=null){
				RsAtual.close();
			}
			return null;
		}
	}
E no loop em cima do cursor com todos os clientes, a cada código do Cliente passado eu carrego o objeto e gravo em um ArrayList que depois será utilizado para inflar meu ListView.

Teria como eu fazer de alguma outra forma, mantendo mais ou menos a estrutura ou retornando algo diferente para meu ListView trabalhar? Li depois em alguns lugares que o ideal não era trabalhar com Cursores no ListView.

Obrigado desde já.

1 Resposta

doug

Olá aboult,

Acho que o problema seu está no Adapter do seu ListView…
Tem um jeito que faz um inflate somente… Veja o exemplo:

public class Adapter extends ArrayAdapter&lt;User&gt; {

	private Context context;

	private ListHolder holder;

	public Adapter(Context context, List&lt;User&gt; users) {
		super(context, R.layout.&lt;custom_listagem&gt;, users);
		this.context = context;
	}

	public View getView(int position, View view, ViewGroup parent) {

		if (view == null) {

			LayoutInflater inflater = (LayoutInflater) this.context
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			view = inflater.inflate(R.layout.&lt;custom_listagem&gt;, parent, false);

			holder.avatar = (ImageView)view.findViewById(R.id.&lt;avatar&gt;);
			holder.profileName = (TextView)view.findViewById(R.id.&lt;profile&gt;);
			holder.name = (TextView)view.findViewById(R.id.&lt;name&gt;);
			view.setTag(this.holder);

		} else {
			this.holder = ((ListHolder) view.getTag());
		}
		
		User user = getItem(position);
		
		holder.avatar.setImageURI(user.getAvatar());
		holder.profileName.setText(user.getProfile());
		holder.name.setText(user.getName());
		return view;
	}

	// ///////////////////////////////////
	// /// Internal class
	// ///////////////////////////////////

	private static class ListHolder {
		ImageView avatar;
		TextView profileName, name;
	}
}

O grande lance está no ListHolder, ele guarda a instancia dos objetos view, dai uma vez instanciado nunca mais vai precisar montar novamente,
somente preencher o objeto com os valores.

if(....) {
    ....  
    view.setTag(this.holder);
} else {
     this.holder = ((ListHolder) view.getTag());
}

Creio que isso custe para o processador do mobile, inflar toda vez…

Espero ter ajudado,

Criado 21 de março de 2013
Ultima resposta 25 de mar. de 2013
Respostas 1
Participantes 2