【问题标题】:Share Database Between Activity and Service在活动和服务之间共享数据库
【发布时间】:2012-07-06 08:19:55
【问题描述】:

我正在创建一个排队上传管理器。在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 实例请求上传照片的问题。我刚刚读完服务和绑定服务文档,感觉很好,但不是很好。

【问题讨论】:

  • 除了已经发布的答案之外,我从您链接的问题中看到,排队机制中的一个决定性因素是网络连接性。我使用BroadcastReceiver 来“监听”连接的变化并将其与IntentService 耦合。我的ActivitiesIntentService 发送网络请求,如果没有连接,它会将请求添加到队列并终止。每当BroadcastReceiver 接收到“已连接”网络Intent 时,它就会启动IntentService,然后处理之前排队的任何内容。

标签: android sqlite file-upload service ipc


【解决方案1】:

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 的引用)。

【讨论】:

    【解决方案2】:

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

    我不会。

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

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

    • 使用活动接收的LocalBroadcastManager 发送本地广播,或
    • 调用活动在startActivity() 上的Intent 额外提供的PendingIntent,或
    • 试试 Square 的 Otto event bus(看起来很有趣,但我还没用过)
    • 等。

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

    这就是为什么您不应该为绑定而烦恼的原因,因为您不需要绑定,但您确实需要启动服务。

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

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

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

    这是解决这个问题的正确方法吗?

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

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

    如果您希望将数据库用作未决下载的后备存储,以防出现一些中断(例如,用户关闭设备电源)并且您希望稍后继续下载这些下载,这很好。但是,该服务将通过您通过startService() 发送给它的命令知道要下载什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-20
      • 2019-01-31
      • 2013-02-25
      • 1970-01-01
      相关资源
      最近更新 更多