在活动和服务之间共享数据库

时间:2012-07-05 21:11:09

标签: android sqlite file-upload service ipc

我正在创建一个排队的上传管理器。通过this回答我上一个问题的指导,我将使用服务来上传这些图片。建议我使用数据库来跟踪成功上传的文件和待处理的文件。

我最初的研究让我相信我会想要创建一个绑定服务,所以我可以在照片上传后更新我的用户界面,以及启动服务,这样它就可以独立于我创建的活动而运行它。看来我还需要通过应用清单中的process=":something"指令在自己的进程中启动它。

我的问题是,在N个活动客户端和上传服务中共享SQLite(除非有更好的方法)数据库的最佳方式是什么?

我设想它的工作原理如下:伪代码:

// in an app
writeRecordToDb( . . . );

// start service
if( service doesn't exist )
{
  // start service, and bind
}

// in the service:
if( shared db has another row )
{
  doDownload( . . . );

  if( download worked )
  {
    notifyActivity();

    if( db has another row )
      doDownload( . . . );
  }
  else
  {
    retryDownload( . . . );
  }
}

这是正确的方法吗?我再次尝试避免在几乎没有蜂窝信号的情况下让多个Activity实例请求照片上传的问题。我刚读完服务和绑定服务文档,我感觉很好,但不是很好。

2 个答案:

答案 0 :(得分:4)

  

我最初的研究让我相信我想要创建一个绑定服务

我不会。

  

所以我可以在照片上传后更新我的用户界面

您无需使用绑定模式来更新UI。你可以:

  • 使用活动选择的LocalBroadcastManager发送本地广播,或
  • 通过活动调用PendingIntent Intent附加内容中提供的startActivity(),或
  • 试试Square Otto event bus(看起来很有趣,但我还没用过它)
  • 等。
  

以及已启动的服务,因此它可以独立于创建它的活动

运行

这就是为什么你不应该打扰绑定,因为你不需要它,但你需要启动服务。

  

我的问题是,在N个活动客户端和上传服务中共享SQLite(除非有更好的方法)数据库的最佳方式是什么?

选项#1:将您的SQLiteOpenHelper保留在静态数据成员中

选项#2:在数据库周围使用ContentProvider包装器

  

这是正确的方法吗?

使用数据库作为组件之间的通信通道类似于两个隔壁邻居使用由双翼飞机拖曳的横幅相互通信。是的,它有效。但是,它很慢且很昂贵。

(另外,当你需要一架双翼飞机时,从来没有双翼飞机,但我离题了......)

如果您希望将数据库用作待处理下载的后备存储,如果存在中断(例如,用户关闭设备)并且您希望稍后获取这些下载,那就没问题。但是,该服务将通过startService()发送给它的命令知道要下载的内容。

答案 1 :(得分:3)

CommonsWare基本上涵盖了您需要的所有内容......但是这里有一些代码说明了这两个选项,以防万一有任何混淆。

  1. 将您的SQLiteOpenHelper保留在静态数据成员中。

    public class DatabaseHelper extends SQLiteOpenHelper { 
        private static DatabaseHelper mInstance = null;
    
        private static final String DATABASE_NAME = "databaseName";
        private static final String DATABASE_TABLE = "tableName";
        private static final int DATABASE_VERSION = 1;
    
        private Context mCxt;
    
        public static DatabaseHelper getInstance(Context ctx) {
            /** 
             * use the application context as suggested by CommonsWare.
             * this will ensure that you dont accidentally leak an Activitys
             * context (see this article for more information: 
             * http://developer.android.com/resources/articles/avoiding-memory-leaks.html)
             */
            if (mInstance == null) {
                mInstance = new DatabaseHelper(ctx.getApplicationContext());
            }
            return mInstance;
        }
    
        /**
         * constructor should be private to prevent direct instantiation.
         * make call to static factory method "getInstance()" instead.
         */
        private DatabaseHelper(Context ctx) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
            this.mCtx = ctx;
        }
    }
    

    然后在Service / Activity中,保留对DatabaseHelper的引用并致电getInstance()

  2. 将数据库包裹在ContentProvider中。如果您已经实现了一个,那么您只需使用

    mContext.getContentResolver().query(...);
    

    这是有效的,因为ActivityService都延伸Context(其中包含对ContentResolver的引用)。