基于Android中Looper , Handler , Message的线程池,轻松解决Sqlite数据库的线程安全问题

基于Android中Looper , Handler , Message的线程池,轻松解决Sqlite数据库的线程安全问题

 

SQLite是基于单一磁盘文件的数据库,所以SQLite是文件级别的锁:多个线程可以同时读,但是同时只能有一个线程写。所以多线程操作时往往容易出现问题。

 

但矛盾的是,操作SQLite往往是一个耗时的过程,如果在主线程中进行,数据量一大就容易发生臭名昭著的ANR异常。

 

怎么办呢?小弟封装了一个基于Looper , Handler , Message的线程池,主要思路和其它线程池没有什么两样,重点是当分配任务到线程池中执行时,可以通过id指定在哪个线程运行,这就可以很好的解决上面提到的Sqlite数据库的线程安全问题,操作SQLite的任务固定指定一个id,让它们在同一个线程中执行,这样就不用担心多个线程对同一个SQLite数据库同时操作产生的竞争问题,其次对Sqlite数据库的操作放到了其它线程,不在主线程,也很好的解决了ANR异常问题。

 

好了,废话不多说,先上代码吧:

 

import android.os.Handler;

import android.os.Looper;

import android.os.Message;

import android.util.SparseArray;

 

import com.zjg.smart.android.debug.DetailedLog;

import com.zjg.smart.utils.DebugUtils;

import com.zjg.test.Common;

 

public final class AndroidThreadPool {

   private SparseArray<Worker> pool = new SparseArray<Worker>();

 

   private static class SingletonHelper {

      public static AndroidThreadPool instance = new AndroidThreadPool();

   }

 

   private AndroidThreadPool() {

   }

 

   public static AndroidThreadPool getInstance() {

      return SingletonHelper.instance;

   }

 

   public static abstract class Task implements Runnable {

      private boolean stop = false;

      private boolean succeed = false;

      private String errMsg = "";

 

      synchronized protected final void setErrMsg(String errMsg) {

        succeed = false;

        this.errMsg = errMsg;

      }

 

      synchronized protected final String getErrMsg() {

        return errMsg;

      }

 

      synchronized protected final boolean isSucceed() {

        return succeed;

      }

 

      synchronized protected final boolean isStop() {

        return stop;

      }

 

      synchronized final void initialize() {

        succeed = true;

        errMsg = "";

        stop = false;

      }

 

      synchronized final void stop() {

        stop = true;

      }

 

      /**

       * 寄送一个任务到主线程,不等其完成,继续往下执行

       *

       * @param runnable

       *            被寄送的任务

       */

      protected final void postMainThread(Runnable runnable) {

        if (runnable == null) {

           setErrMsg(DebugUtils.STACK_TRACE() + "runnable == null");

           return;

        }

        new Handler(Looper.getMainLooper()).post(runnable);

        return;

      }

 

      private Object waitMainThreadSyncLock = new Object();

 

      /**

       * 寄送一个任务到主线程,并等待其完成,才继续往下执行

       *

       * @param runnable

       *            被寄送的任务

       */

      protected final void waitMainThread(final Runnable runnable) {

        if (runnable == null) {

           setErrMsg(DebugUtils.STACK_TRACE() + "runnable == null");

           return;

        }

        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {

           setErrMsg(DebugUtils.STACK_TRACE()

                 + "Can't be called in the main thread.");

           return;

        }

 

        new Handler(Looper.getMainLooper()).post(new Runnable() {

 

           @Override

            public void run() {

              // TODO自动生成的方法存根

              runnable.run();

              synchronized (waitMainThreadSyncLock) {

                 waitMainThreadSyncLock.notifyAll();

              }

           }

        });

 

        synchronized (waitMainThreadSyncLock) {

           try {

              waitMainThreadSyncLock.wait();

           } catch (InterruptedException e) {

              // TODO自动生成的 catch

              e.printStackTrace();

           }

        }

      }

 

      /**

       * 子类可重载,返回运行任务的线程id

       *

       * @return

       */

      synchronized public int getRunThreadId() {

        return 0;

      }

 

      /**

       * 子类可重载,任务运行前的预处理,只会在主线程中调用

       */

      protected void pretreatment() {

      };

 

      /**

       * 子类必须重载,当任务成功时被调用,只会在主线程中调用

       */

      protected abstract void onSucceed();

 

      /**

       * 子类必须重载,当任务失败时被调用,只会在主线程中调用

       *

       * @param msg

       *            失败消息

       */

      protected abstract void onFailed(String msg);

 

      /**

       * 子类可重载,当任务被终止时被调用,只会在主线程中调用

       */

      protected void onStop() {

      }

   }

 

   synchronized public void execution(Task task) {

      int id = task.getRunThreadId();

      Worker worker = pool.get(id);

      if (worker == null) {

        worker = new Worker();

        pool.put(id, worker);

      }

      worker.execution(task);

   }

 

   synchronized public void stopThread(int id) {

      Worker worker = pool.get(id);

      if (worker != null) {

        worker.stop();

      }

   }

 

   synchronized public void destroy() {

      for (int i = 0, size = pool.size(); i < size; i++) {

        Worker worker = pool.valueAt(i);

        if (worker != null) {

           worker.destroy();

        }

      }

      pool.clear();

   }

 

   class Worker {

      private Task task = null;

      private Object taskSyncLock = new Object();

 

      private Handler handler = null;

      private Object handlerSyncLock = new Object();

 

      private Thread thread = new Thread() {

        @Override

        public void run() {

           super.run();

           Looper.prepare();

 

           synchronized (handlerSyncLock) {

              handler = new Handler() {

                 @Override

                 public void handleMessage(Message msg) {

                    super.handleMessage(msg);

                    final Task task = (Task) msg.obj;

                    if (task != null) {

                      synchronized (taskSyncLock) {

                         Worker.this.task = task;

                      }

                      task.initialize();

                      task.waitMainThread(new Runnable() {

 

                         @Override

                         public void run() {

                            // TODO自动生成的方法存根

                            if (task.isSucceed()) {

                               task.pretreatment();

                            }

                         }

                      });

                      if (task.isSucceed()) {

                         task.run();

                       }

                      if (!task.isStop()) {

                         new Handler(Looper.getMainLooper())

                               .post(new Runnable() {

 

                                  @Override

                                  public void run() {

                                    if (task.succeed) {

                                       task.onSucceed();

                                    } else {

                                       task.onFailed(task.errMsg);

                                    }

                                  }

                               });

 

                      } else {

                         new Handler(Looper.getMainLooper())

                               .post(new Runnable() {

 

                                  @Override

                                  public void run() {

                                    task.onStop();

                                  }

                               });

                      }

 

                      synchronized (taskSyncLock) {

                         Worker.this.task = null;

                      }

                    }

                 }

              };

              handlerSyncLock.notifyAll();

           }

           Looper.loop();

        }

      };

 

      void execution(Task task) {

        if (handler == null) {

           if (thread != null) {

              thread.start();

           }

 

           if (handler == null) {

              synchronized (handlerSyncLock) {

                 if (handler == null) {

                    try {

                      handlerSyncLock.wait();

                    } catch (InterruptedException e) {

                     

                      e.printStackTrace();

                    }

                 }

              }

           }

        }

 

        Message msg = handler.obtainMessage();

        msg.obj = task;

        handler.sendMessage(msg);

      }

 

      void stop() {

        if (thread != null && thread.isAlive()) {

           if (task != null) {

              synchronized (taskSyncLock) {

                 if (task != null) {

                    task.stop();

                    task = null;

                 }

              }

           }

        }

      }

 

      void destroy() {

        if (thread != null && thread.isAlive()) {

           if (task != null) {

              synchronized (taskSyncLock) {

                 if (task != null) {

                    task.stop();

                    task = null;

                 }

              }

           }

           if (handler != null) {

              synchronized (handlerSyncLock) {

                 if (handler != null) {

                    handler.getLooper().quit();

                 }

              }

           }

           thread.interrupt();

        }

      }

   }

}

 

 

代码有点多,但不难理解,我来解释一下:

客户代码通过扩展Task,重载run()、getRunThreadId()、pretreatment()、onSucceed()、onFailed(String msg)、onStop()方法来完成任务。

Worker,顾名思义,工作者,它维护一个线程,并在线程中开启一个Looper.loop(),等待任务的到来。

线程池采用单例模式,并通过id维护一个Worker的SparseArray集合,当execution一个Task时,通过Task的成员方法getRunThreadId()取得id,通过id取得对应的Worker,通过此Worke的线程的Handle把Task寄送到线程中执行。

思路就这么简单。

 

下面是我的一个应用场景:

AndroidThreadPool.getInstance().execution(new Task() {

        private int max = 0;

        private int progress = 0;

 

        @Override

        public void run() {

 

           InputStream inputStream = null;

           OutputStream out = null;

           try {

              File dir = AppUtils.getAppFileDir(

                    ExceptionCatchService.this, EXCEPTION_REPORT_TAG);

              File file = new File(dir, new SimpleDateFormat(

                    "yyyy-MM-dd-HH-mm-ss").format(new Date())

                    + "."

                    + EXCEPTION_REPORT_TAG);

              if (!file.exists()) {

                 file.createNewFile();

              }

              out = new FileOutputStream(file);

              byte[] buffer = new byte[1024];

              int length = -1;

              inputStream = new ByteArrayInputStream(exception

                   .getBytes("utf-8"));

              max = inputStream.available();

              while ((length = inputStream.read(buffer)) != -1) {

                 progress += length;

                 new Handler(Looper.getMainLooper())

                      .post(new Runnable() {

 

                         @Override

                         public void run() {

                            Intent intent = new Intent(

                                  RECEIVER_ACTION);

                            intent.putExtra(PROGRESS_TAG, progress);

                            intent.putExtra(MAX_TAG, max);

                            intent.putExtra(MSG_TAG, "");

                            sendBroadcast(intent);

                         }

                       });

 

                 out.write(buffer, 0, length);

              }

           } catch (IOException e) {

              e.printStackTrace();

           } finally {

              if (out != null) {

                 try {

                    out.flush();

                 } catch (IOException e) {

                    e.printStackTrace();

                 }

                 try {

                    out.close();

                 } catch (IOException e) {

                    e.printStackTrace();

                 }

              }

              if (inputStream != null) {

                 try {

                    inputStream.close();

                 } catch (IOException e) {

                    e.printStackTrace();

                 }

              }

           }

         }

 

        @Override

        protected void onSucceed() {

           Intent intent = new Intent(RECEIVER_ACTION);

           intent.putExtra(PROGRESS_TAG, progress);

           intent.putExtra(MAX_TAG, max);

           intent.putExtra(MSG_TAG, "保存异常报告完毕。");

           sendBroadcast(intent);

           ExceptionCatchService.this.stopSelf();

        }

 

        @Override

        protected void onStop() {

 

           Intent intent = new Intent(RECEIVER_ACTION);

 

           intent.putExtra(PROGRESS_TAG, progress);

           intent.putExtra(MAX_TAG, max);

           intent.putExtra(MAX_TAG, "保存异常报告被终止。");

 

           sendBroadcast(intent);

 

           ExceptionCatchService.this.stopSelf();

        }

 

        @Override

        protected void onFailed(String msg) {

           // TODO自动生成的方法存根

          

        }

 

     });

 

可见run()、onSucceed()、onFailed(String msg)是必须重载的,getRunThreadId()没有重载,采用默认的id值0。

 

 

 

下面是我封装的常用的SQLite操作,以供参考。

 

SqliteDatabaseTask.java,SQLite操作的基类:

public abstract class SqliteDatabaseTask extends Task {

   // log_begin

   private static final DetailedLog Log = new DetailedLog();

   private static final String LOG_TAG = Common.LOG_TAG;

 

   // log_end

 

   protected File databaseFile = null;

 

   protected abstract boolean asyncHandleDatabase(SQLiteDatabase database);

 

   public SqliteDatabaseTask(File databaseFile) {

      if (databaseFile == null) {

        throw new NullPointerException("\"databaseFile == null\"");

      }

      this.databaseFile = databaseFile;

   }

 

   @Override

   public void run() {

      // TODO自动生成的方法存根

      SQLiteDatabase database = null;

      try {

        database = SqliteDatabaseUtils.openDatabase(databaseFile);

        if (database == null) {

           setErrMsg(this + ",打开数据库文件\"" + databaseFile.getAbsolutePath()

                 + "\"失败。");

           return;

        }

        if (!asyncHandleDatabase(database)) {

           return;

        }

      } finally {

        if (database != null) {

           database.close();

        }

      }

   }

}

 

SqliteDatabaseQueryTask.java,用于查询:

public abstract class SqliteDatabaseQueryTask extends SqliteDatabaseTask {

  

 

   public SqliteDatabaseQueryTask(File databaseFile) {

      super(databaseFile);

   }

 

   @Override

   protected final boolean asyncHandleDatabase(SQLiteDatabase database) {

      // TODO

      waitMainThread(new Runnable() {

 

        @Override

        public void run() {

           // TODO自动生成的方法存根

           m_sqlString = getSqlString();

        }

      });

      if (m_sqlString == null) {

        setErrMsg(this + ":\"getSqlString()\" return null.");

        return false;

      }

      if (m_sqlString.length() == 0) {

        setErrMsg(this + ":\"getSqlString()\" return \"\".");

        return false;

      }

      waitMainThread(new Runnable() {

 

        @Override

        public void run() {

           // TODO自动生成的方法存根

           m_args = getArgs();

        }

      });

      Cursor cursor = null;

      try {

        cursor = database.rawQuery(m_sqlString, m_args);

        if (cursor == null) {

           setErrMsg(this

                 + ":查询数据库时返回的\"cursor\" = null, \"sqlString\" = \""

                 + m_sqlString

                 + "\", \"args\" = "

                 + (m_args == null ? null : Arrays.toString(m_args)

                      + "."));

           return false;

        }

        if (!asycHandleCursor(cursor)) {

           return false;

        }

      } finally {

        if (cursor != null) {

           cursor.close();

        }

      }

      return true;

   }

 

   protected abstract boolean asycHandleCursor(Cursor cursor);

 

   private String m_sqlString = "";

 

   protected abstract String getSqlString();

 

   private String[] m_args = null;

 

   protected abstract String[] getArgs();

}

 

 

SqliteDatabaseSaveTask.java,用于保存:

public abstract class SqliteDatabaseSaveTask extends SqliteDatabaseTask {

   // log_begin

   private static final DetailedLog Log = new DetailedLog();

   private static final String LOG_TAG = Common.LOG_TAG;

 

   // log_end

 

   public SqliteDatabaseSaveTask(File databaseFile) {

      super(databaseFile);

   }

 

   protected abstract boolean asyncSave(SQLiteDatabase database);

 

   @Override

   protected final boolean asyncHandleDatabase(final SQLiteDatabase database) {

      database.beginTransaction();

      try {

        if (!asyncSave(database)) {

           return false;

        }

        database.setTransactionSuccessful();

      } finally {

        database.endTransaction();

      }

      return true;

   }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值