如何从Android中的同步适配器服务访问已运行的应用程序上下文?

5
我有一个应用程序,包含多个活动,并且我使用Application Context(从Application Class扩展而来,并将其设置为持久化)在所有活动之间共享数据和对象。我使用Application Class而不是后台服务,有几个很好的原因,这里不再详细解释。
最近,我还向我的应用程序添加了自定义联系人同步适配器。它位于相同的包中,与同一APK文件中。因此,我将其设置为像应用程序中的其他所有内容一样访问Application Context,以便让它访问所有共享的数据和对象。然而,尽管它基本上可以工作,但它会创建Application Context的新实例。因此,基本上运行两个独立的应用程序实例,并且数据不能在它们之间共享。
我认为问题在于我的应用程序从未启动同步服务,而是由操作系统启动。我的所有其他活动都是由应用程序启动的,或者主要活动在启动时访问Application Context,然后App Context控制其他所有内容。是否有办法让同步服务访问现有的Application Context,而不是创建新实例?
以下是我的应用程序的基本结构:
应用程序
package com.mycomany.myapp;    
public class MyApp extends Application{
    ...
}

活动1

package com.mycomany.myapp;
public class MyActivity1 extends Activity{
    MyApp a;

    @Override
    public void onCreate(Bundle savedInstanceState){
        a = (MyApp) getApplicationContext();
        ...
    }
}

同步适配器服务

package com.mycomany.myapp;
public class SyncAdapterService extends Service {
    private static SyncAdapterImpl sSyncAdapter = null;
    private static final Object sSyncAdapterLock = new Object();
    private static ContentResolver mContentResolver = null;
    private static MyApp a;

    public SyncAdapterService() {
        super();
    }

    private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter {
        private Context mContext;

        public SyncAdapterImpl(Context context) {
            super(context, true);
            mContext = context;
        }

        @Override
        public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
            try {
                SyncAdapterService.performSync(mContext, account, extras, authority, provider, syncResult);
            } catch (OperationCanceledException e) {}
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        synchronized (sSyncAdapterLock) {
            if(a == null){
                a = (MyApp) getApplicationContext();
            }
            if (sSyncAdapter == null) {
                sSyncAdapter = new SyncAdapterImpl(getApplicationContext());
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return sSyncAdapter.getSyncAdapterBinder();
    }

    private static void performSync(Context context, Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult)
            throws OperationCanceledException {
...
    }
}
3个回答

7
你是否复制并粘贴了此SyncAdapter培训的内容http://developer.android.com/training/sync-adapters/creating-sync-adapter.html
在最后,有这个XML代码片段:
    <service
            android:name="com.example.android.datasync.SyncService"
            android:exported="true"
            android:process=":sync">
        <intent-filter>com.example.android.datasync.provider
            <action android:name="android.content.SyncAdapter"/>
        </intent-filter>
        <meta-data android:name="android.content.SyncAdapter"
                android:resource="@xml/syncadapter" />
    </service>

如果你使用属性 android:process=":sync" 创建一个单独的同步进程,那么请将其删除即可。


抱歉——我很久以前就解决了这个问题,但是忘记发布解决方案了。 - user496854
没问题。我之前也遇到了类似的情况,然后偶然看到了这个问题。我的SyncAdapter正在覆盖应用程序的SharedDefaultPreferences,反之亦然(它们是线程安全但不是进程安全的)。 - Michael Simons
太感谢了。我也正为共享偏好设置的混乱问题苦恼呢。 - makovkastar

1

您还在遇到这个问题吗? 如果服务在清单文件中声明时没有指定不同的android:process,那么它不应该在您的任务定义的默认进程中运行吗? 在这种情况下,您不能只使用getApplicationContext来获取所需内容吗? 我已经按照这种方式实现了我的同步适配器,并且它正在工作。


它应该可以,但出于某种原因它不能。getApplicationContext会拉起一个不同的应用实例。 - user496854
那么您的同步适配器不是在一个单独的项目中(具有不同的清单文件),也没有在清单文件中指定不同的进程? - kingston
我的Eclipse项目可能出了一些问题或者损坏了,或者我在清单文件中漏掉了什么。最终,我从头开始创建了一个新的项目,复制了所有的Java源文件,然后重新创建了清单文件。一旦我这样做了,一切都按照预期工作——getApplicationContext正常运行。我仍然不知道是什么原因导致原始项目出现了问题。 - user496854

1
你可能需要考虑将服务绑定到应用程序上下文中。这样,如果应用程序上下文不存在,服务也不存在,因为它在同一进程中运行(即应用程序的进程)。请参见bindSerivce()
如果你的服务是远程的,请尝试使用callbacks

1
我不确定这是否可能 - 这是一个同步适配器服务,因此我的应用程序从技术上永远不会与其交互。它由内容解析器触发(创建和绑定),当它触发同步时。我如何将其绑定到我的应用程序? - user496854

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接