如何处理来自webservice的过多数据? OOM

时间:2014-07-21 13:21:09

标签: android out-of-memory

我正在开发一个将在没有互联网连接的情况下使用的应用程序。用户必须在转到该字段之前导入将由城市使用的数据。该应用程序第一次带来了来自城市的所有数据。这是问题,我应该如何处理?一些城市的数据太多,有时超过4000个生产者,每个生产者都有超过40个领域。

这是我的处理程序类:

package emater.gin.webservice;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

/*
 * Classe: ServiceHandler
 * Usada para leitura e envio de JSON.
 */
public class ServiceHandler 
{

    //Resposta
    private String response = null;

    //Recebe do servidor.
    public final static int GET = 1;

    //Envia para o servidor.
    public final static int POST = 2;

    //Construtor vazio.
    public ServiceHandler() {}

    //Faz a chamada para o servidor.
    public String makeServiceCall( String url, int method )
    {

        return this.makeServiceCall( url, method, null );

    }

    //Faz a chamada para o servidor.
    public String makeServiceCall( String url, int method, List<NameValuePair> params )
    {

        try
        {

            //HTTP Client.
            DefaultHttpClient httpClient = new DefaultHttpClient();

            //Entidade que pode ser enviada ou recebida.
            HttpEntity httpEntity = null;

            //Resposta HTTP.
            HttpResponse httpResponse = null;

            //Checa o tipo de request que vai ser feito.
            if( method == POST )
            {

                //Cria o HttpPost para enviar uma entidade.
                HttpPost httpPost = new HttpPost( url );

                //Adicona os parametros ao post.
                if( params != null )
                {

                    //Seta a entidade de respostas no httppost com os parametros passados.
                    httpPost.setEntity( new UrlEncodedFormEntity( params ) );

                }

                //Pega a resposta do servidor a partida da enviada.
                httpResponse = httpClient.execute( httpPost );

            }else if( method == GET )
            {

                //Adiciona os parametros e gera a URL.
                if( params != null )
                {

                    String paramString = URLEncodedUtils.format( params, "utf-8" );

                    url += "?" + paramString;

                }

                HttpGet httpGet = new HttpGet( url );

                //Envia a URL e pega a resposta.
                httpResponse = httpClient.execute( httpGet );

            }

            //Liberar memoria.
            httpClient = null;

            //Pega a resposta e bota em uma nova entidade para ser usada.
            httpEntity = httpResponse.getEntity();

            //Liberar memoria.
            httpResponse = null;

            response = EntityUtils.toString( httpEntity );

            //Liberar memoria.
            httpEntity = null;

        }catch( UnsupportedEncodingException e ) 
        {

            e.printStackTrace();

        }catch( ClientProtocolException e ) 
        {

            e.printStackTrace();

        }catch( IOException e )
        {

            e.printStackTrace();

        }

        return response;

    }

}

当我从webservice获取所有字符串时,我在响应行处获得了OOM。 这是我调用服务器的代码:

// Instancia para adicionar os parâmetros.
List<NameValuePair> params = new ArrayList<NameValuePair>();

// Adiciona os parametros a serem passados para o webservice.
params.add(new BasicNameValuePair(
            MunicipioUsuarioController.COLUMN_MUNICIPIO_ID, municipioId));

params.add(new BasicNameValuePair("numeroserie", Secure.getString(
            getApplicationContext().getContentResolver(),
            Secure.ANDROID_ID)));

// Instancia quem vai lidar com o webservice.
ServiceHandler serviceHandler = new ServiceHandler();

// Faz um request a URL e pega a resposta.
String JSONString = serviceHandler.makeServiceCall(
            HTTP_URL_DADOS_MUNICIPIO, ServiceHandler.POST, params);

我使用AsyncTask来进行调用。我使用MAT并且JSONString占用了我的应用程序所具有的大部分内存。我应该如何处理这个问题?一次只导入一些数据?

1 个答案:

答案 0 :(得分:2)

您需要采取几种方法来解决这个问题。

首先,正如评论中所建议的那样,尝试让您的服务器返回更少的数据。这似乎是一个明显的解决方案,但它需要在连接的两端进行工作。

其次,解析来自stream的数据:

您目前正在做的是将响应转换为String,然后传回String,然后将其解析为JSON。这里更好的方法是从http实体处理JSON解析,如下所示(仅显示相关代码)。

public Object makeServiceCall( String url, int method, List<NameValuePair> params ) {
    ....    
        httpEntity = httpResponse.getEntity();
        httpResponse = null;

        JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE);
        response = parser.parse( httpEntity.getContent() );

显然,你需要捕获解析异常等等,但这就是它的要点。我用HttpUrlConnection做了这个,并且能够为静态负载处理几个兆字节的响应。

据我所知,主要问题不是整体内存使用量,而是容纳响应所需的最大内存块大小。在直接解析InputStream时,这不是问题,因为它创建了许多不需要连续堆的较小对象。