导出数据时出现内存不足

时间:2013-02-13 17:48:27

标签: android web-services sqlite

我有一个应用程序,它使用Web服务从SQL Server获取数据并将其导出到平板电脑中的SQLite数据库。问题是,该表有大约25,000条记录。当我将其限制为100条记录时,代码工作得很好。但是在导出所有数据时出现以下错误:

02-13 13:36:31.734: E/AndroidRuntime(12821): FATAL EXCEPTION: AsyncTask #1
02-13 13:36:31.734: E/AndroidRuntime(12821): java.lang.RuntimeException: An error occured while executing doInBackground()
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.os.AsyncTask$3.done(AsyncTask.java:299)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.util.concurrent.FutureTask.run(FutureTask.java:239)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.lang.Thread.run(Thread.java:856)
02-13 13:36:31.734: E/AndroidRuntime(12821): Caused by: java.lang.OutOfMemoryError
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.lang.ThreadLocal$Values.initializeTable(ThreadLocal.java:244)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.lang.ThreadLocal$Values.rehash(ThreadLocal.java:325)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.lang.ThreadLocal$Values.cleanUp(ThreadLocal.java:254)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.lang.ThreadLocal$Values.getAfterMiss(ThreadLocal.java:438)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.lang.ThreadLocal.get(ThreadLocal.java:65)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.sqlite.SQLiteDatabase.getThreadSession(SQLiteDatabase.java:359)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:992)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:799)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.sqlite.SQLiteDatabase.getVersion(SQLiteDatabase.java:862)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:242)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at com.example.shvalidation.DatabaseHandler.InsertBook(DatabaseHandler.java:75)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at com.example.shvalidation.MainMenuScreen$TestThread.doInBackground(MainMenuScreen.java:79)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at com.example.shvalidation.MainMenuScreen$TestThread.doInBackground(MainMenuScreen.java:1)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
02-13 13:36:31.734: E/AndroidRuntime(12821):    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
02-13 13:36:31.734: E/AndroidRuntime(12821):    ... 4 more
02-13 13:36:32.804: E/WindowManager(12821): Activity com.example.shvalidation.MainMenuScreen has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{412636d8 V.E..... R......D 0,0-772,216} that was originally added here
02-13 13:36:32.804: E/WindowManager(12821): android.view.WindowLeaked: Activity com.example.shvalidation.MainMenuScreen has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{412636d8 V.E..... R......D 0,0-772,216} that was originally added here
02-13 13:36:32.804: E/WindowManager(12821):     at android.view.ViewRootImpl.<init>(ViewRootImpl.java:354)
02-13 13:36:32.804: E/WindowManager(12821):     at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:216)
02-13 13:36:32.804: E/WindowManager(12821):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.Dialog.show(Dialog.java:281)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ProgressDialog.show(ProgressDialog.java:116)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ProgressDialog.show(ProgressDialog.java:99)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ProgressDialog.show(ProgressDialog.java:94)
02-13 13:36:32.804: E/WindowManager(12821):     at com.example.shvalidation.MainMenuScreen$TestThread.onPreExecute(MainMenuScreen.java:49)
02-13 13:36:32.804: E/WindowManager(12821):     at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:586)
02-13 13:36:32.804: E/WindowManager(12821):     at android.os.AsyncTask.execute(AsyncTask.java:534)
02-13 13:36:32.804: E/WindowManager(12821):     at com.example.shvalidation.MainMenuScreen.onCreate(MainMenuScreen.java:30)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.Activity.performCreate(Activity.java:5104)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ActivityThread.access$600(ActivityThread.java:141)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
02-13 13:36:32.804: E/WindowManager(12821):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-13 13:36:32.804: E/WindowManager(12821):     at android.os.Looper.loop(Looper.java:137)
02-13 13:36:32.804: E/WindowManager(12821):     at android.app.ActivityThread.main(ActivityThread.java:5039)
02-13 13:36:32.804: E/WindowManager(12821):     at java.lang.reflect.Method.invokeNative(Native Method)
02-13 13:36:32.804: E/WindowManager(12821):     at java.lang.reflect.Method.invoke(Method.java:511)
02-13 13:36:32.804: E/WindowManager(12821):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
02-13 13:36:32.804: E/WindowManager(12821):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
02-13 13:36:32.804: E/WindowManager(12821):     at dalvik.system.NativeStart.main(Native Method)

我想知道是否有人知道我可以导出这些记录。是的,我知道向SQLite输出超过25,000条记录是荒谬的,但不幸的是,这是我被分配的项目。因此,我必须找到一种方法来实现它。

编辑:添加使用Web服务的代码并保存到SQLite。

package com.example.shvalidation;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;

public class MainMenuScreen extends Activity {
    //JSON Variables
    JSONParser jsonParser = new JSONParser();
    String pid;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_menu_layout);
        new TestThread().execute();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main_menu_layout, menu);
        return true;
    }

    public void PlantToDome(View view) {
        Intent intent = new Intent(this, SelectLocationScreen.class);
        startActivity(intent);
    }

    //Código del Web Service
    public class TestThread extends AsyncTask<Void, Void, Void> {
        ProgressDialog dialog;
        protected void onPreExecute() {
            dialog = ProgressDialog.show(MainMenuScreen.this, "Loading", "Loading data, please wait..");
        }

        protected Void doInBackground(Void...args0) {
            int success;
            Book book = new Book();
            DatabaseHandler handler = new DatabaseHandler(MainMenuScreen.this);
            try {
                // Building Parameters
                List<NameValuePair> params = new ArrayList<NameValuePair>();
                params.add(new BasicNameValuePair("pid", pid));

                // getting product details by making HTTP request
                // Note that product details url will use GET request
                JSONObject json = jsonParser.makeHttpRequest(
                        "http://192.168.1.102:8080/WSBook.php", "GET", params);

                // check your log for json response

                // json success tag
                success = json.getInt("success");
                if (success == 1) {
                    // successfully received product details
                    JSONArray productObj = json.getJSONArray("record"); // JSON Array

                    // get first product object from JSON Array
//                    JSONObject product = productObj.getJSONObject(1);
                    for (int i = 0; i < productObj.length(); i++) {
                        JSONObject record = productObj.getJSONObject(i);
                        book.setAoiName(record.getString("aoi_name"));
                        book.setExptName(record.getString("expt_name"));
                        book.setEuID(record.getInt("eu_id"));
                        book.setX(record.getInt("x"));
                        book.setY(record.getInt("y"));
                        book.setZ(record.getInt("z"));
                        book.setRaplo(record.getString("raplo"));
//                      Book book = new Book(record.getString("aoi_name"), record.getString("expt_name"), record.getInt("eu_id"), 
//                              record.getInt("x"), record.getInt("y"), record.getInt("z"), record.getString("raplo"));
                        handler.InsertBook(book);
                    }
                }
            } catch (Exception e) {
                Log.e("error", e.toString());
            }
            return null;
        }

        protected void onPostExecute(Void unused) {
            dialog.dismiss();
        }
    }
}

编辑#2:我的JSON Parser类。

package com.example.shvalidation;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

public class JSONParser {

    static InputStream is = null;
    static JSONObject jObj = null;
    static String json = "";

    // constructor
    public JSONParser() {

    }

    // function get json from url
    // by making HTTP POST or GET method
    public JSONObject makeHttpRequest(String url, String method,
            List<NameValuePair> params) {

        // Making HTTP request
        try {

            // check for request method
            if(method == "POST"){
                // request method is POST
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpPost httpPost = new HttpPost(url);
                httpPost.setEntity(new UrlEncodedFormEntity(params));

                HttpResponse httpResponse = httpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();
                is = httpEntity.getContent();

            }else if(method == "GET"){
                // request method is GET
                DefaultHttpClient httpClient = new DefaultHttpClient();
                String paramString = URLEncodedUtils.format(params, "utf-8");
                url += "?" + paramString;
                HttpGet httpGet = new HttpGet(url);

                HttpResponse httpResponse = httpClient.execute(httpGet);
                HttpEntity httpEntity = httpResponse.getEntity();
                is = httpEntity.getContent();
            }           

        } catch (UnsupportedEncodingException e) {
            Log.e("Unsupported Encoding", Log.getStackTraceString(e));
        } catch (ClientProtocolException e) {
            Log.e("Client Protocol", Log.getStackTraceString(e));
        } catch (IOException e) {
            Log.e("IO Exception", Log.getStackTraceString(e));
        }

        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            json = sb.toString();
        } catch (Exception e) {
            Log.e("Buffer Error", "Error converting result " + e.toString());
        }

        // try parse the string to a JSON object
        try {
            jObj = new JSONObject(json);
        } catch (JSONException e) {
            Log.e("JSON Parser", "Error parsing data " + e.toString());
            Log.e("JSON Parser", json);
        }

        // return JSON String
        return jObj;

    }
}

1 个答案:

答案 0 :(得分:2)

看起来你试图先将所有25,000行的数据拉入内存,然后将它们写入SQLite(这是猜测,因为你没有显示任何代码,但我敢打赌这是一个很好的猜测)。您必须将其限制为,例如,一次100行。也就是说,从Web服务中读取100行,然后将它们写入SQLite,然后再读取100行等等。您可以通过线程获得更好的功能,但这样可以让您走上正确的道路。

修改:感谢您添加代码。看起来罪魁祸首就是这条线:

JSONObject json = jsonParser.makeHttpRequest(
    "http://192.168.1.102:8080/WSBook.php", "GET", params);

尝试从Web服务中读取整个表的文本并将其插入JSONObject,您的手机没有足够的内存来处理。

我看到两个解决方案:

  1. 如果您可以为定义行范围的http get请求添加参数,您可以使用几乎现有的一些代码循环获取行0-99,将它们写入db,100-199等。
  2. 如果您无法定义行范围,或者数据库经常更改以便您不能依赖于为您提供一致的数据,那么您将不得不将http请求中的响应分解为块。不幸的是,我并不精通所有的json库,所以我不能说哪个可能有助于这个过程。