Android
SyncAdapter는 주기적으로 데이터를 동기화합니다.
수색…
소개
앱의 동기화 어댑터 구성 요소는 기기와 서버간에 데이터를 전송하는 작업의 코드를 캡슐화합니다. 동기화 어댑터 프레임 워크는 동기화 어댑터 구성 요소에서 코드를 실행하여 앱에서 제공하는 일정 및 트리거를 기반으로합니다.
최근에 나는 SyncAdapter에서 일했는데 다른 사람들과 내 지식을 공유하고 싶다. 다른 사람들에게 도움이 될 수있다.
서버에서 요청할 때마다 최소값으로 어댑터를 동기화하십시오.
<provider
android:name=".DummyContentProvider"
android:authorities="sample.map.com.ipsyncadapter"
android:exported="false" />
<!-- This service implements our SyncAdapter. It needs to be exported, so that the system
sync framework can access it. -->
<service android:name=".SyncService"
android:exported="true">
<!-- This intent filter is required. It allows the system to launch our sync service
as needed. -->
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<!-- This points to a required XML file which describes our SyncAdapter. -->
<meta-data android:name="android.content.SyncAdapter"
android:resource="@xml/syncadapter" />
</service>
<!-- This implements the account we'll use as an attachment point for our SyncAdapter. Since
our SyncAdapter doesn't need to authenticate the current user (it just fetches a public RSS
feed), this account's implementation is largely empty.
It's also possible to attach a SyncAdapter to an existing account provided by another
package. In that case, this element could be omitted here. -->
<service android:name=".AuthenticatorService"
>
<!-- Required filter used by the system to launch our account service. -->
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<!-- This points to an XMLf ile which describes our account service. -->
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
이 코드는 매니페스트 파일에 추가해야합니다.
위의 코드에서는 syncservice와 conteprovider 및 authenticatorservice가 있습니다.
응용 프로그램에서 xml 패키지를 만들어 syncadpter 및 authenticator xml 파일을 추가해야합니다. authenticator.xml
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="@string/R.String.accountType"
android:icon="@mipmap/ic_launcher"
android:smallIcon="@mipmap/ic_launcher"
android:label="@string/app_name"
/>
syncadapter
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
android:contentAuthority="@string/R.String.contentAuthority"
android:accountType="@string/R.String.accountType"
android:userVisible="true"
android:allowParallelSyncs="true"
android:isAlwaysSyncable="true"
android:supportsUploading="false"/>
인증 기
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.os.Bundle;
public class Authenticator extends AbstractAccountAuthenticator {
private Context mContext;
public Authenticator(Context context) {
super(context);
this.mContext=context;
}
@Override
public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse, String s) {
return null;
}
@Override
public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse, String s, String s1, String[] strings, Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String s, Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public String getAuthTokenLabel(String s) {
return null;
}
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String s, Bundle bundle) throws NetworkErrorException {
return null;
}
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String[] strings) throws NetworkErrorException {
return null;
}
}
AuthenticatorService
public class AuthenticatorService extends Service {
private Authenticator authenticator;
public AuthenticatorService() {
super();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
IBinder ret = null;
if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) ;
ret = getAuthenticator().getIBinder();
return ret;
}
public Authenticator getAuthenticator() {
if (authenticator == null)
authenticator = new Authenticator(this);
return authenticator;
}
}
IpDataDBHelper
public class IpDataDBHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION=1;
private static final String DATABASE_NAME="ip.db";
public static final String TABLE_IP_DATA="ip";
public static final String COLUMN_ID="_id";
public static final String COLUMN_IP="ip";
public static final String COLUMN_COUNTRY_CODE="country_code";
public static final String COLUMN_COUNTRY_NAME="country_name";
public static final String COLUMN_CITY="city";
public static final String COLUMN_LATITUDE="latitude";
public static final String COLUMN_LONGITUDE="longitude";
public IpDataDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String CREATE_TABLE="CREATE TABLE " + TABLE_IP_DATA + "( " + COLUMN_ID + " INTEGER PRIMARY KEY ,"
+ COLUMN_IP + " INTEGER ," + COLUMN_COUNTRY_CODE + " INTEGER ," + COLUMN_COUNTRY_NAME +
" TEXT ," + COLUMN_CITY + " TEXT ," + COLUMN_LATITUDE + " INTEGER ," + COLUMN_LONGITUDE + " INTEGER)";
sqLiteDatabase.execSQL(CREATE_TABLE);
Log.d("SQL",CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_IP_DATA);
onCreate(sqLiteDatabase);
}
public long AddIPData(ContentValues values)
{
SQLiteDatabase sqLiteDatabase =getWritableDatabase();
long insertedRow=sqLiteDatabase.insert(TABLE_IP_DATA,null,values);
return insertedRow;
}
public Cursor getAllIpData()
{
String[] projection={COLUMN_ID,COLUMN_IP,COLUMN_COUNTRY_CODE,COLUMN_COUNTRY_NAME,COLUMN_CITY,COLUMN_LATITUDE,COLUMN_LONGITUDE};
SQLiteDatabase sqLiteDatabase =getReadableDatabase();
Cursor cursor = sqLiteDatabase.query(TABLE_IP_DATA,projection,null,null,null,null,null);
return cursor;
}
public int deleteAllIpData()
{
SQLiteDatabase sqLiteDatabase=getWritableDatabase();
int rowDeleted=sqLiteDatabase.delete(TABLE_IP_DATA,null,null);
return rowDeleted;
}
}
주요 활동
public class MainActivity extends AppCompatActivity {
private static final String ACCOUNT_TYPE="sample.map.com.ipsyncadapter";
private static final String AUTHORITY="sample.map.com.ipsyncadapter";
private static final String ACCOUNT_NAME="Sync";
public TextView mIp,mCountryCod,mCountryName,mCity,mLatitude,mLongitude;
CursorAdapter cursorAdapter;
Account mAccount;
private String TAG=this.getClass().getCanonicalName();
ListView mListView;
public SharedPreferences mSharedPreferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.list);
mIp=(TextView)findViewById(R.id.txt_ip);
mCountryCod=(TextView)findViewById(R.id.txt_country_code);
mCountryName=(TextView)findViewById(R.id.txt_country_name);
mCity=(TextView)findViewById(R.id.txt_city);
mLatitude=(TextView)findViewById(R.id.txt_latitude);
mLongitude=(TextView)findViewById(R.id.txt_longitude);
mSharedPreferences=getSharedPreferences("MyIp",0);
//Using shared preference iam displaying values in text view.
String txtIp=mSharedPreferences.getString("ipAdr","");
String txtCC=mSharedPreferences.getString("CCode","");
String txtCN=mSharedPreferences.getString("CName","");
String txtC=mSharedPreferences.getString("City","");
String txtLP=mSharedPreferences.getString("Latitude","");
String txtLN=mSharedPreferences.getString("Longitude","");
mIp.setText(txtIp);
mCountryCod.setText(txtCC);
mCountryName.setText(txtCN);
mCity.setText(txtC);
mLatitude.setText(txtLP);
mLongitude.setText(txtLN);
mAccount=createSyncAccount(this);
//In this code i am using content provider to save data.
/* Cursor cursor=getContentResolver().query(MyIPContentProvider.CONTENT_URI,null,null,null,null);
cursorAdapter=new SimpleCursorAdapter(this,R.layout.list_item,cursor,new String []{"ip","country_code","country_name","city","latitude","longitude"},
new int[] {R.id.txt_ip,R.id.txt_country_code,R.id.txt_country_name,R.id.txt_city,R.id.txt_latitude,R.id.txt_longitude},0);
mListView.setAdapter(cursorAdapter);
getContentResolver().registerContentObserver(MyIPContentProvider.CONTENT_URI,true,new StockContentObserver(new Handler()));
*/
Bundle settingBundle=new Bundle();
settingBundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL,true);
settingBundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED,true);
ContentResolver.requestSync(mAccount,AUTHORITY,settingBundle);
ContentResolver.setSyncAutomatically(mAccount,AUTHORITY,true);
ContentResolver.addPeriodicSync(mAccount,AUTHORITY,Bundle.EMPTY,60);
}
private Account createSyncAccount(MainActivity mainActivity) {
Account account=new Account(ACCOUNT_NAME,ACCOUNT_TYPE);
AccountManager accountManager=(AccountManager)mainActivity.getSystemService(ACCOUNT_SERVICE);
if(accountManager.addAccountExplicitly(account,null,null))
{
}else
{
}
return account;
}
private class StockContentObserver extends ContentObserver {
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.d(TAG, "CHANGE OBSERVED AT URI: " + uri);
cursorAdapter.swapCursor(getContentResolver().query(MyIPContentProvider.CONTENT_URI, null, null, null, null));
}
public StockContentObserver(Handler handler) {
super(handler);
}
}
@Override
protected void onResume() {
super.onResume();
registerReceiver(syncStaredReceiver, new IntentFilter(SyncAdapter.SYNC_STARTED));
registerReceiver(syncFinishedReceiver, new IntentFilter(SyncAdapter.SYNC_FINISHED));
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(syncStaredReceiver);
unregisterReceiver(syncFinishedReceiver);
}
private BroadcastReceiver syncFinishedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Sync finished!");
Toast.makeText(getApplicationContext(), "Sync Finished", Toast.LENGTH_SHORT).show();
}
};
private BroadcastReceiver syncStaredReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Sync started!");
Toast.makeText(getApplicationContext(), "Sync started...", Toast.LENGTH_SHORT).show();
}
};
}
MyIPContentProvider
public class MyIPContentProvider extends ContentProvider {
public static final int IP_DATA=1;
private static final String AUTHORITY="sample.map.com.ipsyncadapter";
private static final String TABLE_IP_DATA="ip_data";
public static final Uri CONTENT_URI=Uri.parse("content://" + AUTHORITY + '/' + TABLE_IP_DATA);
private static final UriMatcher URI_MATCHER= new UriMatcher(UriMatcher.NO_MATCH);
static
{
URI_MATCHER.addURI(AUTHORITY,TABLE_IP_DATA,IP_DATA);
}
private IpDataDBHelper myDB;
@Override
public boolean onCreate() {
myDB=new IpDataDBHelper(getContext(),null,null,1);
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
int uriType=URI_MATCHER.match(uri);
Cursor cursor=null;
switch (uriType)
{
case IP_DATA:
cursor=myDB.getAllIpData();
break;
default:
throw new IllegalArgumentException("UNKNOWN URL");
}
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
int uriType=URI_MATCHER.match(uri);
long id=0;
switch (uriType)
{
case IP_DATA:
id=myDB.AddIPData(contentValues);
break;
default:
throw new IllegalArgumentException("UNKNOWN URI :" +uri);
}
getContext().getContentResolver().notifyChange(uri,null);
return Uri.parse(contentValues + "/" + id);
}
@Override
public int delete(Uri uri, String s, String[] strings) {
int uriType=URI_MATCHER.match(uri);
int rowsDeleted=0;
switch (uriType)
{
case IP_DATA:
rowsDeleted=myDB.deleteAllIpData();
break;
default:
throw new IllegalArgumentException("UNKNOWN URI :" +uri);
}
getContext().getContentResolver().notifyChange(uri,null);
return rowsDeleted;
}
@Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0;
}
}
SyncAdapter
public class SyncAdapter extends AbstractThreadedSyncAdapter {
ContentResolver mContentResolver;
Context mContext;
public static final String SYNC_STARTED="Sync Started";
public static final String SYNC_FINISHED="Sync Finished";
private static final String TAG=SyncAdapter.class.getCanonicalName();
public SharedPreferences mSharedPreferences;
public SyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
this.mContext=context;
mContentResolver=context.getContentResolver();
Log.i("SyncAdapter","SyncAdapter");
}
@Override
public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
Intent intent = new Intent(SYNC_STARTED);
mContext.sendBroadcast(intent);
Log.i(TAG, "onPerformSync");
intent = new Intent(SYNC_FINISHED);
mContext.sendBroadcast(intent);
mSharedPreferences =mContext.getSharedPreferences("MyIp",0);
SharedPreferences.Editor editor=mSharedPreferences.edit();
mContentResolver.delete(MyIPContentProvider.CONTENT_URI,null,null);
String data="";
try {
URL url =new URL("https://freegeoip.net/json/");
Log.d(TAG, "URL :"+url);
HttpURLConnection connection=(HttpURLConnection)url.openConnection();
Log.d(TAG,"Connection :"+connection);
connection.connect();
Log.d(TAG,"Connection 1:"+connection);
InputStream inputStream=connection.getInputStream();
data=getInputData(inputStream);
Log.d(TAG,"Data :"+data);
if (data != null || !data.equals("null")) {
JSONObject jsonObject = new JSONObject(data);
String ipa = jsonObject.getString("ip");
String country_code = jsonObject.getString("country_code");
String country_name = jsonObject.getString("country_name");
String region_code=jsonObject.getString("region_code");
String region_name=jsonObject.getString("region_name");
String zip_code=jsonObject.getString("zip_code");
String time_zone=jsonObject.getString("time_zone");
String metro_code=jsonObject.getString("metro_code");
String city = jsonObject.getString("city");
String latitude = jsonObject.getString("latitude");
String longitude = jsonObject.getString("longitude");
/* ContentValues values = new ContentValues();
values.put("ip", ipa);
values.put("country_code", country_code);
values.put("country_name", country_name);
values.put("city", city);
values.put("latitude", latitude);
values.put("longitude", longitude);*/
//Using cursor adapter for results.
//mContentResolver.insert(MyIPContentProvider.CONTENT_URI, values);
//Using Shared preference for results.
editor.putString("ipAdr",ipa);
editor.putString("CCode",country_code);
editor.putString("CName",country_name);
editor.putString("City",city);
editor.putString("Latitude",latitude);
editor.putString("Longitude",longitude);
editor.commit();
}
}catch(Exception e){
e.printStackTrace();
}
}
private String getInputData(InputStream inputStream) throws IOException {
StringBuilder builder=new StringBuilder();
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(inputStream));
//String data=null;
/*Log.d(TAG,"Builder 2:"+ bufferedReader.readLine());
while ((data=bufferedReader.readLine())!= null);
{
builder.append(data);
Log.d(TAG,"Builder :"+data);
}
Log.d(TAG,"Builder 1 :"+data);
bufferedReader.close();*/
String data=bufferedReader.readLine();
bufferedReader.close();
return data.toString();
}
}
SyncService
public class SyncService extends Service {
private static SyncAdapter syncAdapter=null;
private static final Object syncAdapterLock=new Object();
@Override
public void onCreate() {
synchronized (syncAdapterLock)
{
if(syncAdapter==null)
{
syncAdapter =new SyncAdapter(getApplicationContext(),true);
}
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return syncAdapter.getSyncAdapterBinder();
}
}
Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow