Android - 如何处理 1000 条记录 SQLite [重复]

Posted

技术标签:

【中文标题】Android - 如何处理 1000 条记录 SQLite [重复]【英文标题】:Android - How to handle 1000 records SQLite [duplicate] 【发布时间】:2015-05-30 07:59:53 【问题描述】:

我试图在开始时在我的 SQLite 上添加 1000 条记录,但问题是当我启动 APP 时它会变成白屏,然后是黑屏直到它崩溃,当我放 5 条记录时,它仍然在做与白屏和黑屏相同,但是当添加记录时,它会向我展示所有记录的祝酒词,所以它可以工作...... 这是我的SQLiteBaseAdapter

public class ClientsSQL extends SQLiteOpenHelper 
// Declaramos la sentencia para crear la tabla
String sqlCreate = "CREATE TABLE Clients(NIF text,cognom1 text,cognom2 text,nom text)";



 public ClientsSQL(Context context, String name, SQLiteDatabase.CursorFactory factory,
                          int version) 
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    
    @Override
    public void onCreate(SQLiteDatabase db) 

        db.execSQL(sqlCreate);
        db.execSQL("INSERT INTO Clients VALUES ('39410028B', 'hola1', 'Hola2', 'Jonathan')");
        Log.v("INFO1", "creating db");


    

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
        // TODO Auto-generated method stub
        // Si existe la tabla, la borramos y la volvemos a crear.
       db.execSQL("DROP TABLE IF EXISTS Clients");
        db.execSQL(sqlCreate);
    

我创建了 1 个插入作为测试,但是在我的 MainActivity 上,我这样做了:

public void crearRegistres(SQLiteDatabase db)

    int i;
    String dni ="";

    for (i = 0; i < 1000; i++) 

        dni = NumeroDNI();

        db.execSQL("INSERT INTO Clients VALUES ('" + dni + "'," + "'cognomA" + i + "'," + "'cognomB" + i + "',"+ "'nom" + i + "')");
    
    Cursor c;
    c = db.rawQuery("Select NIF from Clients", null);


    Toast.makeText(MainActivity.this, Integer.toString(c.getCount()),
            Toast.LENGTH_LONG).show();
    c.close();

我试图创建一个 Async 类,但不明白我如何调用 doInBackGround() 方法(如果它是正确执行它的方法......)。

编辑1

这是我尝试过的,但我什么也做不了,直到它完成。

  progress = ProgressDialog.show(getActivity(), "Cargando",
                        "Espere mientras cargan sus ofertas", true);
                new Thread(new Runnable() 
                    @Override
                    public void run() 
                        try 
                            Thread.sleep(2000);


                         catch (InterruptedException e) 
                            e.printStackTrace();
                        

                        getActivity().runOnUiThread(new Runnable() 

                            @Override
                            public void run() 
                                crearRegistres(db);
                                progress.dismiss();
                            
                        );
                    

                ).start();
            

LogCat 错误:

 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:200)
            at android.os.Handler.<init>(Handler.java:114)
            at android.widget.Toast$TN.<init>(Toast.java:327)
            at android.widget.Toast.<init>(Toast.java:92)
            at android.widget.Toast.makeText(Toast.java:241)
            at joancolmenero.com.practicabasedadesxmlthreads.MainActivity.NumeroDNI(MainActivity.java:111)
            at joancolmenero.com.practicabasedadesxmlthreads.MainActivity.crearRegistres(MainActivity.java:123)
            at joancolmenero.com.practicabasedadesxmlthreads.MainActivity$1.run(MainActivity.java:41)
            at java.lang.Thread.run(Thread.java:841)
03-26 11:49:20.436  21310-21310/joancolmenero.com.practicabasedadesxmlthreads E/WindowManager﹕ android.view.WindowLeaked: Activity joancolmenero.com.practicabasedadesxmlthreads.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView41f8f5b8 V.E..... R......D 0,0-684,324 that was originally added here
            at android.view.ViewRootImpl.<init>(ViewRootImpl.java:361)
            at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:248)
            at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
            at android.app.Dialog.show(Dialog.java:286)
            at android.app.ProgressDialog.show(ProgressDialog.java:116)
            at android.app.ProgressDialog.show(ProgressDialog.java:99)
            at joancolmenero.com.practicabasedadesxmlthreads.MainActivity.onCreate(MainActivity.java:29)
            at android.app.Activity.performCreate(Activity.java:5248)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2173)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2269)
            at android.app.ActivityThread.access$800(ActivityThread.java:139)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5102)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
            at dalvik.system.NativeStart.main(Native Method)

编辑2

当我运行 APP 时,大约需要 5 或 6 秒才能显示我的活动,它会显示一个白屏...

public class MainActivity extends ActionBarActivity 
Button test;
    public SQLiteDatabase db;
    public ClientsSQL Conexion;
    ProgressDialog progress;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Conexion = new ClientsSQL(this, "Clients", null, 1);
        db = Conexion.getReadableDatabase();

        new MyAsyncTask().execute();



    public void crearRegistres(SQLiteDatabase db)

        int i;
        String dni ="";

        for (i = 0; i < 1000; i++) 

            dni = NumeroDNI();

            db.execSQL("INSERT INTO Clients VALUES ('" + dni + "'," + "'cognomA" + i + "'," + "'cognomB" + i + "',"+ "'nom" + i + "')");
        
        Cursor c;
        c = db.rawQuery("Select NIF from Clients", null);



        c.close();
    
    private class MyAsyncTask extends AsyncTask<Void, Void, Void> 
        private final ProgressDialog dialog = new ProgressDialog(MainActivity.this);

        @Override
        protected void onPreExecute() 

            this.dialog.setMessage("Cargando DNI en SQLite");
            this.dialog.show();
        

        @Override
        protected Void doInBackground(Void... params) 
            db.beginTransaction();

            try 
                crearRegistres(db);

                db.setTransactionSuccessful();
             catch (Exception ignored) 

             finally 
                db.endTransaction();
            
            return null;
        


        @Override
        protected void onPostExecute(Void result) 
            super.onPostExecute(result);
            Cursor c;
            c = db.rawQuery("Select NIF from Clients where NIF", null);
            Toast.makeText(MainActivity.this, Integer.toString(c.getCount()), Toast.LENGTH_LONG).show();
            c.close();
            this.dialog.dismiss();
        
    


【问题讨论】:

我不是安卓开发者。一个建议-尝试创建一个后台服务并在后台执行数据。该后台服务不会影响前台应用程序的启动。 @Signare 服务也在 UI 线程上运行,所以这还不够。他需要一个后台线程。 @GabeSechan 它是如何工作的? (后台线程) @GabeSechan 我提到了“后台服务”。 @Signare Android 中的服务不在后台运行。对于很多人来说,这是一个奇怪的困惑来源。我知道您在想什么,我只是不确定您是否(并且绝对不确定 OP)是否知道他必须为您的答案创建一个线程和一个服务。 【参考方案1】:

使用 AsyncTask。

要启动 AsyncTask,将调用方法 doInBackground:

 new MyAsyncTask().execute();

看文档 http://developer.android.com/reference/android/os/AsyncTask.html

编辑 2:

private class MyAsyncTask extends AsyncTask<Void, Void, Void> 

        @Override
        protected void onPreExecute() 
            super.onPreExecute();
            progress = ProgressDialog.show(getActivity(), "Cargando",
                            "Espere mientras cargan sus ofertas", true);
        
        @Override
        protected Void doInBackground(Void... params) 
            crearRegistres(db);
            return null;
        
        @Override
        protected void onPostExecute(Void result) 
            super.onPostExecute(result);
            progress.dismiss();
        
    

【讨论】:

但是我必须创建另一个我提到的类? 是的,您必须创建另一个类,但它可能是一个内部类:javatpoint.com/java-inner-class 查看我的编辑,到目前为止我所做的尝试 我已经发布了 LogCatERror 我编辑了我的答案,在你的班级(活动)中添加了这个异步任务,并按照解释调用它【参考方案2】:

使用Transaction 插入您的数据。我将 16k 行插入到 Transaction 中,从 220 秒缩短到 8 秒。

This answer 似乎足够好。

我还建议 Futuroid(或类似的异步库)执行异步操作。

快速交易示例:

try 
  db.beginTransaction();
  crearRegistres(db); 
  db.setTransactionSuccessful();
 catch (Exception ignored)  
finally  db.endTransaction(); 

还有一个使用 Futuroid:

public Future<Boolean> insertRows(final SqliteDatabase db) 
    return Async.submit(new Callable<Boolean>() 
        @Override
        public Boolean call() 
            try 
                db.beginTransaction();
                crearRegistres(db);
                db.setTransactionSuccessful();
             catch (Exception ignored) 
             finally 
                db.endTransaction();
                return true;
            
        
    );

这是您从活动中调用它的方式;

 insertRows(db).addCallback(new FutureCallback<Boolean>() 
                                   @Override
                                   public void onSuccess(Boolean boolean) 
                                       Log.i("SQLITE", "Data inserted");
                                   

                                   @Override
                                   public void onFailure(Throwable t) 
                                       Log.e("SQLITE", "Unable to insert data ", t);
                                   
                               

    );

【讨论】:

它做后台功能,所以我可以在SQLite上引入数据的同时与APP交互? 使用 Futroid 是的,确实如此。操作完成后,它将调用 onSuccess(如果出现问题,则调用 onFailure),因此您将知道作业已完成。但我强烈建议你也使用交易,非常强烈。 会是这样的:tr​​y crearRegistres(db); db.setTransactionSuccessful(); 捕捉(忽略异常) 最后 db.endTransaction(); ? 我可以用@LaurentY 回答来实现你的回答吗?这样我可以更快地放数据吗? 不,他们以两种不同的方式完成相同的工作。 AsyncTask 是进行异步工作的原始方式,但它正在变得过时。如果要在 AsyncTask 中使用事务,只需复制 doInBackground() 中的第一个代码块即可。【参考方案3】:

您需要在后台线程上执行此操作。 AsyncTask 也可以工作,但如果您有任何其他 AsyncTasks 正在进行,我会避免它,因为任务是在一个线程上循环完成的,这可能会大大阻碍它。

【讨论】:

以上是关于Android - 如何处理 1000 条记录 SQLite [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:关于如何处理丢失小数的建议

android分页请求,重复数据如何处理

离开 Activity 时 Android 如何处理后台线程?

MySQL 如何处理查询中的 ORDER BY 和 LIMIT?

如何处理 SCD 类型 2 维度和重复维度记录?

Aerospike如何处理通过多个连接创建同一记录?