Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access an already-running Application Context from a Sync Adapter service in Android?

I have an app that consists of several activities, and I use the Application Context (entended from the Application Class, and I made it persistent) to share data and objects between all the activities. I use the Application Class instead of a background service for several good reasons, which I won't go into here.

I also recently added an custom contact sync adapter to my app. It's under the same package, in the same APK. So, I set it up to access the Application Context just like everything else in my app to give it access to all the shared data and objects. However, even though it works (mostly), it creates a new instance of the Application Context. So there are basically 2 separate instances of my application running, and the data isn't shared between them.

I think that the problem is that my Applicattion never starts the sync service, the OS does. All my other activities are either started by the application, or the main activity accesses the Application Context when it launches, and then the App Context controls everything else. Is there a way to have the sync service access the existing Application Context, instead of creating the new instance of it?

Here's the basic structure of my app:

The application

package com.mycomany.myapp;    
public class MyApp extends Application{
    ...
}

Activity1

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

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

SyncAdapterService

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 {
...
    }
}
like image 863
user496854 Avatar asked Nov 05 '11 04:11

user496854


3 Answers

Have you copy&pasted this training for the SyncAdapter http://developer.android.com/training/sync-adapters/creating-sync-adapter.html?

At the end there is this XML Snippet:

    <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>

With the attribute android:process=":sync" meaning you create a separate sync process. Remove it and you're good to go.

like image 50
Michael Simons Avatar answered Dec 15 '22 21:12

Michael Simons


You might want to look into binding the service to your Application context. That way, if your application context does not exist, the service won't exist, as it runs in the same process (that of the Application) . See bindSerivce()

If your service is a remote one try using callbacks

like image 25
Reno Avatar answered Dec 15 '22 19:12

Reno


Are you still having this problem? If the service is declared in your manifest file without specifying a different android:process, isn't it supposed to run in the default process defined by your task? Can't you in that case just use getApplicationContext to get what you need? I have my sync adapter implemented in this way and it is working

like image 41
kingston Avatar answered Dec 15 '22 19:12

kingston