Json Leitura

Seguinte estou lendo um retorno php json e gravando em banco de dados.

Recebo via http, gera o objeto json e percorro o array o problema que 5.000 registros o processo ficou demorado leva cerca de 10 minutos.

Segue os códigos:

Alguma idéia de como posso melhorar o processo?

[java]

private void JSONFileTra(String url){
try{

    	ContentValues ctv = new ContentValues();
    	
    	PRI_TraImportados = 0;
        
    	 //Le a pagina
        GetHttp http = new GetHttp(url);
        // page contem a string json
        page = http.page;
        
        //nativo do SDK  da o parse da string json
        JSONObject object = (JSONObject) new JSONTokener(page).nextValue();
        
        // monta o array do retorno do json, lembrando que retorno é o PAI do json impresso em page.
        //{"retorno":[ {"campo1":"valor1"},{"campo2":"valor2"},{"campo3":"valor3"} ]}
        JSONArray message = object.getJSONArray("retorno");
                    
        //Abre a Conexão com o banco de dados
		SQLiteDatabase db = openOrCreateDatabase("StamDroid.db", Context.MODE_PRIVATE, null);
    	
    	//Exclui o cadastro de transportadoras somente depois de pegar o arquivo
		db.execSQL("DELETE FROM SA4010");
        
        for(int i=0;i<message.length();i++){
            JSONObject lines = (JSONObject) new JSONTokener(message.getString(i)).nextValue();
                            
            //Código da Transportadora                
        	ctv.put("A4_COD",lines.getString("A4_COD"));
        	
        	//NOME da Transportadora
        	ctv.put("A4_NOME", lines.getString("A4_NOME") );

        	//CGC da Transportadora
        	ctv.put("A4_CGC",lines.getString("A4_CGC"));
        	            	
        	//Pega a data e hora atual
        	ctv.put("DATAHORA", Funcoes.DataHoraAtual());
        	
        	try{
        		                    		
        		if	(db.insert("SA4010", "_id", ctv) > 0){
        			PRI_TraImportados = PRI_TraImportados + 1;
        		}
        	
        		
        	}catch (Exception e) {
        		 db.close();
        		PRI_OK = false;
			}
            
        }
        
        db.close();            
        PRI_OK = true;
    }catch (Exception e) {           
        PRI_OK = false;
    }
    
}

//Classe de apoio geralmente em outro arquivo .java
//Essa classe pode ser entendia mas a princípio não precisa-se mexer nela, ela funciona apenas coloquea no projeto.
//A função dela, basicamente é acessar a pagina que imprime a string json, ler essa string, e coloca-la em page.
class GetHttp {

    public String page = "";
    
    public GetHttp(String URL) throws Exception{
        BufferedReader bufferedReader = null;
        try{
        	//Permissão
			StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);
			
        	HttpClient client = new DefaultHttpClient();
            client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "android");
            
            HttpParams params = client.getParams();
            HttpConnectionParams.setConnectionTimeout(params, 20000);
            HttpConnectionParams.setSoTimeout(params, 15000);
            
            HttpGet request = new HttpGet();
            request.setHeader("Content-Type", "text/plain; charset=utf-8");
            request.setURI(new URI(URL));
            HttpResponse response = client.execute(request);
            bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            
            StringBuilder stringBuffer = new StringBuilder("");
            String line = "";
            String NL = System.getProperty("line.separator");
            
            while ((line = bufferedReader.readLine()) != null){
                stringBuffer.append(line + NL);
            }
            bufferedReader.close();
            
            page = stringBuffer.toString();
            
                            
        }catch (Exception e) {
            PRI_OK = false;
        }finally{
            if (bufferedReader != null){
                try{
                    bufferedReader.close();
                }catch (IOException e){
                }
            }
        }
    }
}

[/java]

A linha “JSONObject object = (JSONObject) new JSONTokener(page).nextValue();” demora mais de 50 segundos…

giliardabreu

Apenas análisando a performance do código, acredito que o problema esteja na linha

[quote]if (db.insert("SA4010", "_id", ctv) > 0){
PRI_TraImportados = PRI_TraImportados + 1;
} [/quote]

Ao invés de fazer um insert para cada ctv, você poderia criar um método que recebe um List<ContentValues> e programalo da seguinte maneira:

public int[] insert(ContentValues[] ctvs) {
	PreparedStatement stmt = cnn.prepareStatement("insert into tabela values (?,?,?,?)"); 
		
	for(ContentValues ctv : ctvs) {
		stmt.setString(1, ctvs[0])
		stmt.setString(1, ctvs[1])
		stmt.setString(2, ctvs[2])
		stmt.setString(3, ctvs[3])
		stmt.addBatch();
	}
	
	return stmt.executeBatch();
}

OBS: Estou apenas sugerindo uma melhora na execução. Não estou análisando a sua implementação e outros conceitos que poderiam ser melhorados.

já pensou em colocar alguns logs no meio dos processos afim de identificar onde está o gargalho ?

a cada 2 ou 3 linha tente imprimir o tempo atual…assim fica mais fácil descobrir onde melhorar

Poxa muito obrigado, sou iniciante. vou fazer os testes realmente demoro mesmo para gravar, gravando tudo no final deve ser mais rápido.

Uma outra linha que trava cerca de 50 segundos é essa:

//nativo do SDK da o parse da string json 
JSONObject object = (JSONObject) new JSONTokener(page).nextValue(); 

Na hora que vai atribuir para objeto, não teria como desativar o parse ou ele é mesmo necessário?

Outra coisa observe no código que primeiro faço um for para uma page do tipo string e depois atribuir no objeto e percorrer novamente não poderia já percorrer uma unica vez?
Obrigado

Só posso responder pelo “for”.

Sim pode sim.

Ao invés da fazer o método insert receber um List, cria um método Add


public class DB {

    private static final String SQL = "insert into tabela (campo1) values (?)";

    private PreparedStatement stmt;

    public DB() {
        stmt = cnn.preparedStatement(SQL);
    }

    public void addContentValues(ContentValues cv) {
        stmt.setString(1,cv.get());
        stmt.addBatch();
    }

    public int[] insert() {
        return stmt.executeBatch();
    }
}

Instancia essa classe antes do for.

No lugar da chamada, db.insert, faz a chamada, db.add

E depois do for, faz o db.insert().

Aí você faz um for no retorno do db.insert pra saber todos os inserts que funcionário.

O problema não serão esses for e sim o parse o insert no db.

Fiz o meu processo de sincronismo usando o formato json, faço uma requisição via http recebo um json percorro e gravo. A principio funcionou perfeitamente.

O sistema irá possui muitos registros só o cadastro de produto será mais de 10.000 registros no total serão importados em média 20.000 registros, nessse caso o processo está levando cerca de 8 a 10 minutos.

Fiz um teste gerando um banco (SQL LITE) via php, lendo mysql, logo depois de gerar o banco faço o download no android, o processo levou cerca de 2 minutos, que ficou bem mais rápido, então a minha pergunta é o que é melhorar usar, importar os dados diretamente via http por exemplo ou gerar o banco a parte e pega-lo no android?

Obrigado

Não tinha percebido que estava fazendo todo o processamento no Adnroid.

Com certeza, fazer o download do banco de dados no Android será mais rápido que querer realizar o processamento.

Mas o download da base irá servir para uma instalação mais rápida. Porém o sincronismo será em duas vias ou apenas uma?

Se o Android apenas irá baixar o banco, isso atende. Mas se for necessário subir os dados do Android também, será necessário subir os dados antes de baixar a base.