Android рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рдиред рднрд╛рдЧ рджреЛ

рдЦрд╛рддрд╛
рд╕рд╣рдХрд░реНрдорд┐рдпреЛрдВ, рд╢реБрдн рджреЛрдкрд╣рд░ред рд╣рдо рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдореЗрдВ рд╢реБрд░реВ рдХрд┐рдП рдЧрдП рд╡рд┐рд╖рдп рдХреЛ рдЬрд╛рд░реА рд░рдЦрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рд╣рдордиреЗ рдЙрдкрдХрд░рдг рдкрд░ рдПрдХ рдЦрд╛рддрд╛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рддрдВрддреНрд░ рдХреА рдЬрд╛рдВрдЪ рдХреАред рдпрд╣ SyncAdapter рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╣рд▓реА рд╢рд░реНрдд рдереАред

рджреВрд╕рд░реА рд╕реНрдерд┐рддрд┐ ContentProvider рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рд╣реИ, рдЬрд┐рд╕рдХреЗ рд▓реЗрдЦрди рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рджрд╕реНрддрд╛рд╡реЗрдЬ рдореЗрдВ рдЪрдмрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдЪ рдХрд╣реВрдВ, рддреЛ рдореБрдЭреЗ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкрд╕рдВрдж рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рд╡рд░реНрдгрд┐рдд рд╣реИ: рд╕рдм рдХреБрдЫ рднрд╛рд░реА рдФрд░ рдЬрдЯрд┐рд▓ рд▓рдЧрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдереЛрдбрд╝рд╛ рд╕рд╛ рдЪрдХреНрд░ рд▓рдЧрд╛рдПрдВрдЧреЗ рдФрд░ рдПрдХ рдмрд╛рд░ рдлрд┐рд░ рд╣рдо рдЗрд╕ рд╡рд┐рд╖рдп рдХрд╛ рдЕрдиреБрднрд╡ рдХрд░реЗрдВрдЧреЗред рд╣рдо рд╕реНрдЯрдм рдкреНрд░рджрд╛рддрд╛ рдХреЗ рд╕рд╛рде рдорд┐рд▓ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рд╣рдо рдЧрдВрднреАрд░ рд▓реЛрдЧ рд╣реИрдВ рдФрд░ рдЗрд╕ рдЙрдкрдХрд░рдг рдХреА рдкреВрд░реА рд╢рдХреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред

рдкрд┐рдЫрд▓реЗ рднрд╛рдЧ рдХреА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ, рдЕрдиреБрд░реЛрдз рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рдЬрдм рд╣рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рдиред рд╣рдо рдРрд╕реЗ рдорд╛рдорд▓реЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ, рдЖрдЗрдП рд╣рдорд╛рд░реЗ рдкреНрдпрд╛рд░реЗ рд╣рдмреНрд░ рдХреЛ рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рди рдХреЗрд╡рд▓ рдПрдХ рд╕рд░рд▓ рдЖрд░рдПрд╕рдПрд╕ рд░реАрдбрд░ рд▓реЗрдВ рдФрд░ рд▓рд┐рдЦреЗрдВред рд╣рд╛рдВ, рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИред

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдлрд╝реАрдб рдЬреЛрдбрд╝рдиреЗ / рдирд┐рдХрд╛рд▓рдиреЗ, рд╕рдорд╛рдЪрд╛рд░реЛрдВ рдХреА рд╕реВрдЪреА рджреЗрдЦрдиреЗ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдПрдХ рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдореЗрдВ рдЦреЛрд▓рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реЛрдЧреАред рд╣рдо рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреА рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЗрд╕реЗ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рд╕рдорд░реНрдерди-рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдореЗрдВ рдЬреЛрдбрд╝реЗ рдЧрдП SwipeRefreshLayout рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╢реБрд░реВ рдХрд░реЗрдВрдЧреЗред рдЖрдк рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВ ред

рдирд┐рд╢реНрдЪрд┐рдд рдЕрдВрддрд░рд╛рд▓ рдкрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЗрд╕ рд╕рд╛рдорд╛рди рдХреЗ рд▓рд┐рдП рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╕реНрдХреНрд░реАрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ рд╡рд╛рдВрдЫрдиреАрдп рд╣реИ рдХрд┐ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рди рдХреЗрд╡рд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕реЗ, рдмрд▓реНрдХрд┐ рд╣рдорд╛рд░реЗ рдЦрд╛рддреЗ рдХреА рд╕рд┐рд╕реНрдЯрдо рд╕реНрдХреНрд░реАрди рд╕реЗ рднреА рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рдЬреИрд╕рд╛ рдХрд┐ рд▓реЗрдЦ рдХреЗ рд╕реНрдХреНрд░реАрдирд╢реЙрдЯ рдореЗрдВ рд╣реИ)ред рд╣рдо рдЗрд╕рдХреЗ рд▓рд┐рдП рд╡рд░реАрдпрддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рд╣рдордиреЗ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдкрд░ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рд╣реИ, рдЪрд▓реЛ рд╢реБрд░реВ рдХрд░реЗрдВред

рдЦрд╛рддрд╛


рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдкрд┐рдЫрд▓реЗ рднрд╛рдЧ рд╕реЗ рдЖрд╡реЗрджрди рдореЗрдВ рдПрдХ рдЦрд╛рддрд╛ рдХреИрд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПред рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рдХреНрд░рдорд╢рдГ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рд╣рдо рдПрдХ рдЦрд╛рд▓реА рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рде рдкреНрд░рдорд╛рдгрдХ рдХреЛ рдмрджрд▓ рджреЗрдВрдЧреЗред
Authenticator.java
public class Authenticator extends AbstractAccountAuthenticator { public Authenticator(Context context) { super(context); } @Override public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { throw new UnsupportedOperationException(); } @Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { throw new UnsupportedOperationException(); } @Override public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { throw new UnsupportedOperationException(); } @Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { throw new UnsupportedOperationException(); } @Override public String getAuthTokenLabel(String authTokenType) { throw new UnsupportedOperationException(); } @Override public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { throw new UnsupportedOperationException(); } @Override public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { throw new UnsupportedOperationException(); } } 


рд╣рдореЗрдВ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рд╕реЗрдЯрд┐рдВрдЧ рд╕реНрдХреНрд░реАрди рдкрд░ рдЬрд╛рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП Res / xml / Authentator.xml рдлрд╝рд╛рдЗрд▓ рдХреЛ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдкреИрд░рд╛рдореАрдЯрд░ рдПрдВрдбреНрд░реЙрдЗрдб рдЬреЛрдбрд╝реЗрдВ : рдлрд╝рд╛рдЗрд▓ рдХреЗ рд╕рд╛рде рдЦрд╛рддрд╛рдкрд╣рдЪрд╛рди , рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдпреЗ рд╡рд░реАрдпрддрд╛рдПрдБ рдЦреАрдВрдЪреА рдЬрд╛рдиреА рдЪрд╛рд╣рд┐рдПред рдЬрдм рдЖрдк "рд╕рд┐рдВрдХреНрд░реЛрдирд╛рдЗрдЬрд╝реЗрд╢рди" рддрддреНрд╡ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕рд┐рдВрдХрд╕реЗрдЯрд┐рдВрдЧрдРрдХреНрдЯрд┐рд╡рд┐рдЯреА рдЦреБрд▓ рдЬрд╛рдПрдЧреАред
authenticator.xml
 <?xml version="1.0" encoding="utf-8"?> <account-authenticator xmlns:android="http://schemas.android.com/apk/res/android" android:accountPreferences="@xml/account_prefs" android:accountType="com.elegion.newsfeed.account" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:smallIcon="@drawable/ic_launcher" /> 


account_prefs.xml
 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" android:persistent="true"> <PreferenceCategory android:title="@string/general_settings" /> <PreferenceScreen android:key="com.elegion.newsfeed.KEY_ACCOUNT_SYNC" android:summary="@string/sync_settings_summary" android:title="@string/sync"> <intent android:action="com.elegion.newsfeed.ACTION_SYNC_SETTINGS" android:targetClass="com.elegion.newsfeed.activity.SyncSettingsActivity" android:targetPackage="com.elegion.newsfeed" /> </PreferenceScreen> </PreferenceScreen> 


ContentProvider


рд╣рдорд╛рд░рд╛ рдкреНрд░рджрд╛рддрд╛ SQLite рдбреЗрдЯрд╛рдмреЗрд╕ рдкрд░ рдПрдХ рдЖрд╡рд░рдг рд╣реЛрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рд╣рдо рд╕рдорд╛рдЪрд╛рд░ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗред рдЖрдЗрдП рд╣рдо рдереЛрдбрд╝рд╛ рдзреНрдпрд╛рди рджреЗрдВ рдФрд░ рдЗрд╕рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред рдкреНрд░рджрд╛рддрд╛ рдЙрдбрд╝реА рдХреЗ рджреЛ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИ:
рд╕рд╛рдордЧреНрд░реА: // рдкреНрд░рд╛рдзрд┐рдХрд░рдг / рддрд╛рд▓рд┐рдХрд╛ - рддрд╛рд▓рд┐рдХрд╛ рд╕реЗ рд╕рднреА рдорд╛рдиреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░реЗрдВ
рд╕рд╛рдордЧреНрд░реА: // рдкреНрд░рд╛рдзрд┐рдХрд░рдг / рддрд╛рд▓рд┐рдХрд╛ / _id - рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рджреНрд╡рд╛рд░рд╛ рдПрдХ рдорд╛рди рдХрд╛ рдЪрдпрди рдХрд░реЗрдВ
рдкреИрдХреЗрдЬрдореИрдиреЗрдЬрд░.рдЧреЗрдЯрдкреНрд░реЛрд╡рд╛рдЗрдбрд░рдЗрдиреНрдлреЛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдСрдирдХреНрд░рд┐рдПрдЯ рд╡рд┐рдзрд┐ рдореЗрдВ рд╣рдо рдЗрд╕ рдкреНрд░рджрд╛рддрд╛ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХрд╛рд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ SQLiteUriMatcher рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░рддреЗ рд╣реИрдВред рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рдХреНрдпрд╛ рд╣реЛрддрд╛ рд╣реИ: рдкреНрд░рджрд╛рддрд╛ uri рд╕реЗ рддрд╛рд▓рд┐рдХрд╛ рдХрд╛ рдирд╛рдо рд▓реЗрддрд╛ рд╣реИ, рдлрд┐рд░ SQLiteTableProvider (рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рд▓рд┐рдП рдкреНрд░рджрд╛рддрд╛) рдХрд╛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЗрд╕ рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рд▓рд┐рдП SCHEMA рд╕реЗ рд▓рд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдВрдмрдВрдзрд┐рдд рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ SQLiteTableProvider рдкрд░ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдХреЙрд▓ рдЕрдиреБрдорд╛рдирд┐рдд рд╣реИ)ред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдкреНрд░рддреНрдпреЗрдХ рддрд╛рд▓рд┐рдХрд╛ рдХреЛ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХреЛ рдЕрдиреБрдХреВрд▓рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, ContentResolver (рдФрд░ рдЗрд╕рдХреЗ рд╕рд╛рде рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди) рдбреЗрдЯрд╛ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд╕реВрдЪрдирд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИред рдЙрд░ рдкреНрд░рдХрд╛рд░ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЗ рд▓рд┐рдП: // рдкреНрд░рд╛рдзрд┐рдХрд░рдг / рддрд╛рд▓рд┐рдХрд╛ / _id, рдЬрд╣рд╛рдВ рдкреНрд░рд╛рдердорд┐рдХ рдХреБрдВрдЬреА рдХреЗ рд╕рд╛рде рд╕рдВрдЪрд╛рд▓рди рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦрдВрдб рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред рдпрджрд┐ рд╡рд╛рдВрдЫрд┐рдд рд╣реИ, рддреЛ рдЖрдк рдЗрд╕ рдкреНрд░рджрд╛рддрд╛ рдХреЛ рдереЛрдбрд╝рд╛ рдореЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╡рд░реНрдЧ рдореЗрдВ рдбрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВред рдЕрднреНрдпрд╛рд╕ рд╕реЗ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рддрд░рд╣ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди 90% рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ (рд╢реЗрд╖ 10 рдкреВрд░реНрдг рдкрд╛рда рдЦреЛрдЬ рд╣реИрдВ, рдЬреИрд╕реЗ рдХрд┐ nocase рдЦреЛрдЬ)ред
SQLiteContentProvider.java
 public class SQLiteContentProvider extends ContentProvider { private static final String DATABASE_NAME = "newsfeed.db"; private static final int DATABASE_VERSION = 1; private static final String MIME_DIR = "vnd.android.cursor.dir/"; private static final String MIME_ITEM = "vnd.android.cursor.item/"; private static final Map<String, SQLiteTableProvider> SCHEMA = new ConcurrentHashMap<>(); static { SCHEMA.put(FeedProvider.TABLE_NAME, new FeedProvider()); SCHEMA.put(NewsProvider.TABLE_NAME, new NewsProvider()); } private final SQLiteUriMatcher mUriMatcher = new SQLiteUriMatcher(); private SQLiteOpenHelper mHelper; private static ProviderInfo getProviderInfo(Context context, Class<? extends ContentProvider> provider, int flags) throws PackageManager.NameNotFoundException { return context.getPackageManager() .getProviderInfo(new ComponentName(context.getPackageName(), provider.getName()), flags); } private static String getTableName(Uri uri) { return uri.getPathSegments().get(0); } @Override public boolean onCreate() { try { final ProviderInfo pi = getProviderInfo(getContext(), getClass(), 0); final String[] authorities = TextUtils.split(pi.authority, ";"); for (final String authority : authorities) { mUriMatcher.addAuthority(authority); } mHelper = new SQLiteOpenHelperImpl(getContext()); return true; } catch (PackageManager.NameNotFoundException e) { throw new SQLiteException(e.getMessage()); } } @Override public Cursor query(Uri uri, String[] columns, String where, String[] whereArgs, String orderBy) { final int matchResult = mUriMatcher.match(uri); if (matchResult == SQLiteUriMatcher.NO_MATCH) { throw new SQLiteException("Unknown uri " + uri); } final String tableName = getTableName(uri); final SQLiteTableProvider tableProvider = SCHEMA.get(tableName); if (tableProvider == null) { throw new SQLiteException("No such table " + tableName); } if (matchResult == SQLiteUriMatcher.MATCH_ID) { where = BaseColumns._ID + "=?"; whereArgs = new String[]{uri.getLastPathSegment()}; } final Cursor cursor = tableProvider.query(mHelper.getReadableDatabase(), columns, where, whereArgs, orderBy); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } @Override public String getType(Uri uri) { final int matchResult = mUriMatcher.match(uri); if (matchResult == SQLiteUriMatcher.NO_MATCH) { throw new SQLiteException("Unknown uri " + uri); } else if (matchResult == SQLiteUriMatcher.MATCH_ID) { return MIME_ITEM + getTableName(uri); } return MIME_DIR + getTableName(uri); } @Override public Uri insert(Uri uri, ContentValues values) { final int matchResult = mUriMatcher.match(uri); if (matchResult == SQLiteUriMatcher.NO_MATCH) { throw new SQLiteException("Unknown uri " + uri); } final String tableName = getTableName(uri); final SQLiteTableProvider tableProvider = SCHEMA.get(tableName); if (tableProvider == null) { throw new SQLiteException("No such table " + tableName); } if (matchResult == SQLiteUriMatcher.MATCH_ID) { final int affectedRows = updateInternal( tableProvider.getBaseUri(), tableProvider, values, BaseColumns._ID + "=?", new String[]{uri.getLastPathSegment()} ); if (affectedRows > 0) { return uri; } } final long lastId = tableProvider.insert(mHelper.getWritableDatabase(), values); getContext().getContentResolver().notifyChange(tableProvider.getBaseUri(), null); final Bundle extras = new Bundle(); extras.putLong(SQLiteOperation.KEY_LAST_ID, lastId); tableProvider.onContentChanged(getContext(), SQLiteOperation.INSERT, extras); return uri; } @Override public int delete(Uri uri, String where, String[] whereArgs) { final int matchResult = mUriMatcher.match(uri); if (matchResult == SQLiteUriMatcher.NO_MATCH) { throw new SQLiteException("Unknown uri " + uri); } final String tableName = getTableName(uri); final SQLiteTableProvider tableProvider = SCHEMA.get(tableName); if (tableProvider == null) { throw new SQLiteException("No such table " + tableName); } if (matchResult == SQLiteUriMatcher.MATCH_ID) { where = BaseColumns._ID + "=?"; whereArgs = new String[]{uri.getLastPathSegment()}; } final int affectedRows = tableProvider.delete(mHelper.getWritableDatabase(), where, whereArgs); if (affectedRows > 0) { getContext().getContentResolver().notifyChange(uri, null); final Bundle extras = new Bundle(); extras.putLong(SQLiteOperation.KEY_AFFECTED_ROWS, affectedRows); tableProvider.onContentChanged(getContext(), SQLiteOperation.DELETE, extras); } return affectedRows; } @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { final int matchResult = mUriMatcher.match(uri); if (matchResult == SQLiteUriMatcher.NO_MATCH) { throw new SQLiteException("Unknown uri " + uri); } final String tableName = getTableName(uri); final SQLiteTableProvider tableProvider = SCHEMA.get(tableName); if (tableProvider == null) { throw new SQLiteException("No such table " + tableName); } if (matchResult == SQLiteUriMatcher.MATCH_ID) { where = BaseColumns._ID + "=?"; whereArgs = new String[]{uri.getLastPathSegment()}; } return updateInternal(tableProvider.getBaseUri(), tableProvider, values, where, whereArgs); } private int updateInternal(Uri uri, SQLiteTableProvider provider, ContentValues values, String where, String[] whereArgs) { final int affectedRows = provider.update(mHelper.getWritableDatabase(), values, where, whereArgs); if (affectedRows > 0) { getContext().getContentResolver().notifyChange(uri, null); final Bundle extras = new Bundle(); extras.putLong(SQLiteOperation.KEY_AFFECTED_ROWS, affectedRows); provider.onContentChanged(getContext(), SQLiteOperation.UPDATE, extras); } return affectedRows; } private static final class SQLiteOpenHelperImpl extends SQLiteOpenHelper { public SQLiteOpenHelperImpl(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.beginTransactionNonExclusive(); try { for (final SQLiteTableProvider table : SCHEMA.values()) { table.onCreate(db); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.beginTransactionNonExclusive(); try { for (final SQLiteTableProvider table : SCHEMA.values()) { table.onUpgrade(db, oldVersion, newVersion); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } } } 


рдЕрдм рдЖрдкрдХреЛ рдкреНрд░рджрд╛рддрд╛ рдХреЛ AndroidManifest.xml рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ Android рдкреИрд░рд╛рдореАрдЯрд░ рдкрд░ рдзреНрдпрд╛рди рджреЗрдирд╛ рд╣реЛрдЧрд╛ : Syncable = "true" ред рдпрд╣ рдзреНрд╡рдЬ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░рд╛ рдкреНрд░рджрд╛рддрд╛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред
AndroidManifest.xml
 <provider android:name=".sqlite.SQLiteContentProvider" android:authorities="com.elegion.newsfeed" android:exported="false" android:syncable="true" /> 


рдмреНрдпрд╛рдЬ рдХреА рднреА FeedProvider рд╡рд░реНрдЧ рд╣реИ, рд╕рдорд╛рдЪрд╛рд░ рдлрд╝реАрдб рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП SQLiteTableProvider рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдиред рдЬрдм рдЖрдк рдЗрд╕ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ (рдПрдХ рдирдП рдлрд╝реАрдб рдХреА рд╕рджрд╕реНрдпрддрд╛) рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдордЬрдмреВрд░ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХрд╣рд╛ рдЬрд╛рдПрдЧрд╛ред OnContentChanged рд╡рд┐рдзрд┐ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЬрд╝рд┐рдореНрдореЗрджрд╛рд░ рд╣реИ, рдЬреЛ рдбреЗрдЯрд╛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╣реЛрдиреЗ рдкрд░ SQLiteContentProvider рд╕реЗ рдЬреБрдбрд╝ рдЬрд╛рддрд╛ рд╣реИ (рд╕рдореНрдорд┐рд▓рд┐рдд / рдЕрджреНрдпрддрди / рд╣рдЯрд╛рдПрдВ)ред рддрд╛рд▓рд┐рдХрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдЯреНрд░рд┐рдЧрд░ ( рдСрдирдХреНрд░рд┐рдПрдЯ ) рдмрдирд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдЬреЛ рдлрд╝реАрдб рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╕рдорд╛рдЪрд╛рд░ рдХреЛ рд╣рдЯрд╛ рджреЗрдЧрд╛ред рдХреЗрд╡рд▓ рд╕рдореНрдорд┐рд▓рди рдкрд░ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рдХреНрдпреЛрдВ рд╣реИ? рд▓реВрдкрд┐рдВрдЧ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдХреНрдпреЛрдВрдХрд┐ рд╣рдорд╛рд░рд╛ рдкреНрд░рджрд╛рддрд╛ рддрд╛рд▓рд┐рдХрд╛ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдЧрд╛ (рдПрдХ рд╢реАрд░реНрд╖рдХ, рдЪрд┐рддреНрд░ рдХрд╛ рд▓рд┐рдВрдХ, рдкреНрд░рдХрд╛рд╢рди рддрд┐рдерд┐, рдЖрджрд┐)ред рдЕрддрд┐рд░рд┐рдХреНрдд рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ рд╕рд┐рдВрдХрдЯреЗрдХреНрд╕реНрдЯреНрд░рд╛ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
FeedProvider.java
 public class FeedProvider extends SQLiteTableProvider { public static final String TABLE_NAME = "feeds"; public static final Uri URI = Uri.parse("content://com.elegion.newsfeed/" + TABLE_NAME); public FeedProvider() { super(TABLE_NAME); } public static long getId(Cursor c) { return c.getLong(c.getColumnIndex(Columns._ID)); } public static String getIconUrl(Cursor c) { return c.getString(c.getColumnIndex(Columns.IMAGE_URL)); } public static String getTitle(Cursor c) { return c.getString(c.getColumnIndex(Columns.TITLE)); } public static String getLink(Cursor c) { return c.getString(c.getColumnIndex(Columns.LINK)); } public static long getPubDate(Cursor c) { return c.getLong(c.getColumnIndex(Columns.PUB_DATE)); } public static String getRssLink(Cursor c) { return c.getString(c.getColumnIndex(Columns.RSS_LINK)); } @Override public Uri getBaseUri() { return URI; } @Override public void onContentChanged(Context context, int operation, Bundle extras) { if (operation == INSERT) { extras.keySet(); final Bundle syncExtras = new Bundle(); syncExtras.putLong(SyncAdapter.KEY_FEED_ID, extras.getLong(KEY_LAST_ID, -1)); ContentResolver.requestSync(AppDelegate.sAccount, AppDelegate.AUTHORITY, syncExtras); } } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table if not exists " + TABLE_NAME + "(" + Columns._ID + " integer primary key on conflict replace, " + Columns.TITLE + " text, " + Columns.LINK + " text, " + Columns.IMAGE_URL + " text, " + Columns.LANGUAGE + " text, " + Columns.PUB_DATE + " integer, " + Columns.RSS_LINK + " text unique on conflict ignore)"); db.execSQL("create trigger if not exists after delete on " + TABLE_NAME + " begin " + " delete from " + NewsProvider.TABLE_NAME + " where " + NewsProvider.Columns.FEED_ID + "=old." + Columns._ID + ";" + " end;"); } public interface Columns extends BaseColumns { String TITLE = "title"; String LINK = "link"; String IMAGE_URL = "imageUrl"; String LANGUAGE = "language"; String PUB_DATE = "pubDate"; String RSS_LINK = "rssLink"; } } 


рд╕рд┐рдо рдХреЗ рдкреАрдЫреЗ, рдЦрд░рдЧреЛрд╢ рдорд┐рдВрдХ рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ рдФрд░ рджрд┐рдЦрдиреЗ рд╡рд╛рд▓рд╛ рдЧреНрд▓рд╛рд╕ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИред

SyncAdapter


SyncAdapter'a рдмрдирд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рддреЛрдбрд╝рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдЖрдЗрдП рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪреЗрдВ рдХрд┐ рдЖрдЦрд┐рд░ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ, рдЗрд╕рдХреЗ рдХреНрдпрд╛ рдлрд╛рдпрджреЗ рд╣реИрдВред рдпрджрд┐ рдЖрдк рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдкрд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдХрдо рд╕реЗ рдХрдо рд╣рдореЗрдВ рдорд┐рд▓реЗрдЧрд╛:


рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЕрдЪреНрдЫрд╛ рд╣реИ, рд╣реИ рдирд╛? рд╣рдо рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рдХрд┐ рдЬрдм ContentProvider рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд╣рдо рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рдЙрд╕рдореЗрдВ рдбреЗрдЯрд╛ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдбреЗрдЯрд╛ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдФрд░ "рдореИрдиреБрдЕрд▓ рдореЛрдб" рдореЗрдВ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд╕рдорд╛рдкреНрдд рдХрд░ рджреЗрддрд╛ рд╣реИред

рдЗрд╕ рд╕рд╛рдордЧреНрд░реА рдХреЛ рдПрдХреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЖрдкрдХреЗ рдЦрд╛рддреЗ рдХреЛ рдЖрд╡реЗрджрди рдореЗрдВ рдПрдХреАрдХреГрдд рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╕рдорд╛рди рд╣реИред рд╣рдореЗрдВ рд╕рд┐рд╕реНрдЯрдо рдореЗрдВ рдПрдХреАрдХрд░рдг рдХреЗ рд▓рд┐рдП AbstractThreadedSyncAdapter рдФрд░ рд╕реЗрд╡рд╛ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред AbstractThreadedSyncAdapter рдореЗрдВ рд╕рд┐рд░реНрдл рдПрдХ рдЕрдореВрд░реНрдд рдСрдирд░рдлреЙрд░реНрдорд╕рдВрдХрдВрдЯ рд╡рд┐рдзрд┐ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рд╕рднреА рдЬрд╛рджреВ рд╣реЛрддреЗ рд╣реИрдВред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣рд╛рдБ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ? рдкреНрд░реЗрд╖рд┐рдд рдПрдХреНрд╕реНрдЯреНрд░рд╛рд╕ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ (FeedProvider.onContentChanged рдореЗрдВ SyncExtras рдпрд╛рдж рд░рдЦреЗрдВ), рдпрд╛ рддреЛ рдПрдХ рдЯреЗрдк рдпрд╛ рд╕рднреА рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рд╣рдо рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдлрд╝реАрдб рдХрд╛ рдЪрдпрди рдХрд░рддреЗ рд╣реИрдВ, рд╕рдВрджрд░реНрдн рджреНрд╡рд╛рд░рд╛ рдЖрд░рдПрд╕рдПрд╕ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ ContentProviderClient рдкреНрд░рджрд╛рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ рдЕрдкрдиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ ред SyncResult SyncResult рдХрд╛ рдЙрдкрдпреЛрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЛ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ (рдЕрдкрдбреЗрдЯ, рддреНрд░реБрдЯрд┐рдпреЛрдВ, рдЖрджрд┐ рдХреА рд╕рдВрдЦреНрдпрд╛) рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реВрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
SyncAdapter.java
 public class SyncAdapter extends AbstractThreadedSyncAdapter { public static final String KEY_FEED_ID = "com.elegion.newsfeed.sync.KEY_FEED_ID"; public SyncAdapter(Context context) { super(context, true); } @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { final long feedId = extras.getLong(KEY_FEED_ID, -1); if (feedId > 0) { syncFeeds(provider, syncResult, FeedProvider.Columns._ID + "=?", new String[]{String.valueOf(feedId)}); } else { syncFeeds(provider, syncResult, null, null); } } private void syncFeeds(ContentProviderClient provider, SyncResult syncResult, String where, String[] whereArgs) { try { final Cursor feeds = provider.query( FeedProvider.URI, new String[]{ FeedProvider.Columns._ID, FeedProvider.Columns.RSS_LINK }, where, whereArgs, null ); try { if (feeds.moveToFirst()) { do { syncFeed(feeds.getString(0), feeds.getString(1), provider, syncResult); } while (feeds.moveToNext()); } } finally { feeds.close(); } } catch (RemoteException e) { Log.e(SyncAdapter.class.getName(), e.getMessage(), e); ++syncResult.stats.numIoExceptions; } } private void syncFeed(String feedId, String feedUrl, ContentProviderClient provider, SyncResult syncResult) { try { final HttpURLConnection cn = (HttpURLConnection) new URL(feedUrl).openConnection(); try { final RssFeedParser parser = new RssFeedParser(cn.getInputStream()); try { parser.parse(feedId, provider, syncResult); } finally { parser.close(); } } finally { cn.disconnect(); } } catch (IOException e) { Log.e(SyncAdapter.class.getName(), e.getMessage(), e); ++syncResult.stats.numIoExceptions; } } } 


SyncService рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рднреА рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИред рд╣рдореЗрдВ рдЕрдкрдиреЗ SyncAdapter рдХреЗ рд╕рд╛рде рд╕рдВрдЪрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд┐рд╕реНрдЯрдо рдХреЛ рдПрдХ IBinder рдСрдмреНрдЬреЗрдХреНрдЯ рджреЗрдирд╛ рд╣реИред рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд▓рд┐рдП рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╣рдо рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреЗ рдПрдбреЗрдкреНрдЯрд░ рдХреЗ рд▓рд┐рдП рдкрдВрдЬреАрдХрд░рдг рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рд╣рдореЗрдВ xml-meta file рд╕рд┐рдВрдХ_adapter.xml рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рд╕рд╛рде рд╣реА AndroidManifest.xml рдореЗрдВ рдЗрд╕ рд╕рднреА рд╕рд╛рдорд╛рди рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред
SyncService.java
 public class SyncService extends Service { private static SyncAdapter sSyncAdapter; @Override public void onCreate() { super.onCreate(); if (sSyncAdapter == null) { sSyncAdapter = new SyncAdapter(getApplicationContext()); } } @Override public IBinder onBind(Intent intent) { return sSyncAdapter.getSyncAdapterBinder(); } } 


sync_adapter.xml
 <?xml version="1.0" encoding="utf-8"?> <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:accountType="com.elegion.newsfeed.account" android:allowParallelSyncs="false" android:contentAuthority="com.elegion.newsfeed" android:isAlwaysSyncable="true" android:supportsUploading="false" android:userVisible="true" /> 


AndroidManifest.xml
 <service android:name=".sync.SyncService" android:exported="false" android:process=":sync"> <intent-filter> <action android:name="android.content.SyncAdapter" /> </intent-filter> <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/sync_adapter" /> </service> 


рдФрд░ рдЕрдм рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ


рдЫрд╡рд┐
рдЗрд╕ рддрд░рд╣ рд╕реЗ рдЯреЗрдк рдХреА рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рд╡рд┐рдВрдбреЛ рджрд┐рдЦрд╛рдИ рджреЗрдЧреАред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВ, рд╣рдо рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдФрд░ рд╡рд┐рдЬрд╝реБрдЕрд▓рд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛ рдордЬрдмреВрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП SwipeRefreshLayout рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╣рдордд рд╣реБрдПред FeedList.java рдлрд╝реАрдб рд╕реВрдЪреА рдФрд░ NewsList.java рдлрд╝реАрдб рд╕реВрдЪреА рдХреЛ рдЖрдо рдЕрднрд┐рднрд╛рд╡рдХ SwipeToRefreshList.java рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реЗрдЧрд╛ ред

рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ ContentResolver ( SwipeToRefreshList.onResume () рд╡рд┐рдзрд┐) рдореЗрдВ рдПрдХ рдСрдмреНрдЬрд░реНрд╡рд░ рдХреЛ рдкрдВрдЬреАрдХреГрдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, ContentResolver.addStatusChangeListener рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред SwipeToRefreshList.onStatusChanged рд╡рд┐рдзрд┐ рдореЗрдВ , ContentResolver.isSyncActive рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдБрдЪ рдХрд░реЗрдВ рдФрд░ рдЗрд╕ рдкрд░рд┐рдгрд╛рдо рдХреЛ SwipeToRefreshList.onSyncStatusChanged рд╡рд┐рдзрд┐ рд╕реЗ рдкрд╛рд╕ рдХрд░реЗрдВ, рдЬреЛ рд╡рд╛рд░рд┐рд╕ рджреНрд╡рд╛рд░рд╛ рдЕрдзрд┐рд▓реЗрдЦрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдпрд╣ рд╕рдм рд╡рд┐рдзрд┐ рдЬреЛ рдХрд░реЗрдЧреА рд╡рд╣ SwipeRefreshLayout рдХреА рдкреНрд░рдЧрддрд┐ рдкрдЯреНрдЯреА рдХреЛ рдЫрд┐рдкрд╛рдиреЗ / рджрд┐рдЦрд╛рдиреЗ рдХреА рд╣реИред рдЪреВрдВрдХрд┐ SyncStatusObserver.onStatusChanged рдХреЛ рдПрдХ рдЕрд▓рдЧ рдереНрд░реЗрдб рд╕реЗ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рдо рдкрд░рд┐рдгрд╛рдо рдХреЛ рдПрдХ рд╣реИрдВрдбрд▓рд░ рдореЗрдВ рд▓рдкреЗрдЯрддреЗ рд╣реИрдВред рд╡рдВрд╢рдЬреЛрдВ рдореЗрдВ SwipeToRefreshList.onRefresh рд╕рд╛рдордЧреНрд░реА ContentResolver.requestSync рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдордЬрдмреВрд░ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рд╢реБрд░реВ рдХрд░рддрд╛ рд╣реИред

рд╕рднреА рд╕реВрдЪрд┐рдпреЛрдВ рдХреЛ CursorLoader + CursorAdapter рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реЛрдб рдФрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдХрд┐ ContentProvider рдХреЗ рд╕рд╛рде рдорд┐рд▓рдХрд░ рднреА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рд╕реВрдЪрд┐рдпреЛрдВ рдХреА рдкреНрд░рд╛рд╕рдВрдЧрд┐рдХрддрд╛ рдХреА рдирд┐рдЧрд░рд╛рдиреА рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддреА рд╣реИред рдЬреИрд╕реЗ рд╣реА рдкреНрд░рджрд╛рддрд╛ рдХреЛ рдПрдХ рдирдпрд╛ рдЖрдЗрдЯрдо рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╕рднреА CursorLoaders рд╕реВрдЪрдирд╛рдПрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ рдФрд░ CursorAdapter рдореЗрдВ рдбреЗрдЯрд╛ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░реЗрдВрдЧреЗред
SwipeToRefreshList.java
 public class SwipeToRefreshList extends Fragment implements SwipeRefreshLayout.OnRefreshListener, SyncStatusObserver, AdapterView.OnItemClickListener, SwipeToDismissCallback { private SwipeRefreshLayout mRefresher; private ListView mListView; private Object mSyncMonitor; private SwipeToDismissController mSwipeToDismissController; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fmt_swipe_to_refresh_list, container, false); mListView = (ListView) view.findViewById(android.R.id.list); return (mRefresher = (SwipeRefreshLayout) view); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mRefresher.setColorScheme( android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_green_light, android.R.color.holo_orange_light ); mSwipeToDismissController = new SwipeToDismissController(mListView, this); } @Override public void onResume() { super.onResume(); mRefresher.setOnRefreshListener(this); mSyncMonitor = ContentResolver.addStatusChangeListener( ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE | ContentResolver.SYNC_OBSERVER_TYPE_PENDING, this ); mListView.setOnItemClickListener(this); mListView.setOnTouchListener(mSwipeToDismissController); mListView.setOnScrollListener(mSwipeToDismissController); } @Override public void onPause() { mRefresher.setOnRefreshListener(null); ContentResolver.removeStatusChangeListener(mSyncMonitor); mListView.setOnItemClickListener(null); mListView.setOnTouchListener(null); mListView.setOnScrollListener(null); super.onPause(); } @Override public final void onRefresh() { onRefresh(AppDelegate.sAccount); } @Override public final void onStatusChanged(int which) { mRefresher.post(new Runnable() { @Override public void run() { onSyncStatusChanged(AppDelegate.sAccount, ContentResolver .isSyncActive(AppDelegate.sAccount, AppDelegate.AUTHORITY)); } }); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { } @Override public boolean canDismissView(View view, int position) { return false; } @Override public void dismissView(View view, int position) { } public void setListAdapter(ListAdapter adapter) { final DataSetObserver dataSetObserver = mSwipeToDismissController.getDataSetObserver(); final ListAdapter oldAdapter = mListView.getAdapter(); if (oldAdapter != null) { oldAdapter.unregisterDataSetObserver(dataSetObserver); } mListView.setAdapter(adapter); adapter.registerDataSetObserver(dataSetObserver); } protected void onRefresh(Account account) { } protected void onSyncStatusChanged(Account account, boolean isSyncActive) { } protected void setRefreshing(boolean refreshing) { mRefresher.setRefreshing(refreshing); } } 


рдЫрд╡рд┐
рддреЛ, рдордЬрдмреВрд░ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЗ рд╕рд╛рде рд╣рд▓ рдХрд┐рдпрд╛ред рд▓реЗрдХрд┐рди рд░рд╕ рд╣реА рд╕реНрд╡рдд: рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рд╣реИред рдпрд╛рдж рд░рдЦреЗрдВ, рд╣рдордиреЗ рдЕрдкрдиреЗ рдЦрд╛рддреЗ рдореЗрдВ рд╕реЗрдЯрд┐рдВрдЧ рд╕реНрдХреНрд░реАрди рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдерди рдЬреЛрдбрд╝рд╛ рд╣реИ? рдЕрдЪреНрдЫрд╛ рдЕрднреНрдпрд╛рд╕ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдПрдХреНрд╢рди рдмрд╛рд░ рдореЗрдВ рдПрдХ рдмрдЯрди рджреНрд╡рд╛рд░рд╛ рдЗрд╕ рд╕реНрдХреНрд░реАрди рддрдХ рдкрд╣реБрдВрдЪ рдХреЛ рджреЛрд╣рд░рд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред

рд╡рд╣ рдХреНрдпрд╛ рд╣реИ - рдмрд╛рдИрдВ рдУрд░ рджрд┐рдЦрд╛рдИ рджреЗ рд░рд╣рд╛ рд╣реИред рддрдХрдиреАрдХреА рд░реВрдк рд╕реЗ, рдпрд╣ рдПрдХ рдЧрддрд┐рд╡рд┐рдзрд┐ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╣реИ ( SyncSettings.java ), рдЬрд┐рд╕рдХреА рд╕реЗрдЯрд┐рдВрдЧ res / xml / Sync_prefs.xml рд╕реЗ рд▓реА рдЧрдИ рд╣реИрдВред

рдмрджрд▓рддреЗ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдСрдирд░реЗрдбрд┐рдВрдЧ рдкреЗрд░рд┐рдлреЗрд░реЗрд╢рдирдЪреЗрдВрдЬреНрдб рдореЗрдердб ( рдСрдирд╢реЗрдпрд░рд┐рдВрдЧ рдкреНрд░реЗрдЬреЗрдВрд╢рди рдЪреЗрдВрдЬрд▓реЗрдВрд╕рд░ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди) рдореЗрдВ рдЯреНрд░реИрдХ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рдордп-рд╕рдордп рдкрд░ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреЛ рд╕рдХреНрд╖рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд┐рдзрд┐ рд╣реИ ContentResolver.addPeriodicSync , рдЕрдХреНрд╖рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╡рд┐рдЪрд┐рддреНрд░ рд░реВрдк рд╕реЗ рдкрд░реНрдпрд╛рдкреНрдд, ContentResolver.removePeriodicSync ред рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдЕрдВрддрд░рд╛рд▓ рдХреЛ рдЕрджреНрдпрддрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, ContentResolver.addPeriodicSync рд╡рд┐рдзрд┐ рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдХреНрдпреЛрдВрдХрд┐, рдЬреИрд╕рд╛ рдХрд┐ рдЗрд╕ рдкрджреНрдзрддрд┐ рдХреЗ рд▓рд┐рдП рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдХрд╣рддрд╛ рд╣реИ: "рдпрджрд┐ рдЦрд╛рддрд╛, рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдФрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдХреЗ рд╕рд╛рде рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рдФрд░ рдЖрд╡рдзрд┐рдХ рд╕рд┐рдВрдХ рд╣реИ, рддреЛ рдПрдХ рдирдпрд╛ рдЖрд╡рдзрд┐рдХ рд╕рд┐рдВрдХ рдирд╣реАрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛, рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдкрд┐рдЫрд▓реЗ рдПрдХ рдХреА рдЖрд╡реГрддреНрддрд┐ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред" рдпрджрд┐ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдХреА рдпреЛрдЬрдирд╛ рд╣реИ, рддреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдФрд░ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЛ рдирдП рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рди рдореЗрдВ рдирд╣реАрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛, рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдкрд┐рдЫрд▓реЗ рдПрдХ рдХреЗ рдЕрдВрддрд░рд╛рд▓ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛)ред



sync_prefs.xml
 <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:key="com.elegion.newsfeed.KEY_SYNC" android:title="@string/sync"> <CheckBoxPreference android:defaultValue="false" android:key="com.elegion.newsfeed.KEY_AUTO_SYNC" android:summary="@string/auto_sync_summary" android:title="@string/auto_sync" /> <ListPreference android:defaultValue="@string/auto_sync_interval_default" android:dependency="com.elegion.newsfeed.KEY_AUTO_SYNC" android:entries="@array/auto_sync_intervals" android:entryValues="@array/auto_sync_interval_values" android:key="com.elegion.newsfeed.KEY_AUTO_SYNC_INTERVAL" android:title="@string/auto_sync_interval" /> </PreferenceCategory> </PreferenceScreen> 


SyncSettings.java
 public class SyncSettings extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String KEY_AUTO_SYNC = "com.elegion.newsfeed.KEY_AUTO_SYNC"; private static final String KEY_AUTO_SYNC_INTERVAL = "com.elegion.newsfeed.KEY_AUTO_SYNC_INTERVAL"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.sync_prefs); final ListPreference interval = (ListPreference) getPreferenceManager() .findPreference(KEY_AUTO_SYNC_INTERVAL); interval.setSummary(interval.getEntry()); } @Override public void onResume() { super.onResume(); getPreferenceManager().getSharedPreferences() .registerOnSharedPreferenceChangeListener(this); } @Override public void onPause() { getPreferenceManager().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); super.onPause(); } @Override public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { if (TextUtils.equals(KEY_AUTO_SYNC, key)) { if (prefs.getBoolean(key, false)) { final long interval = Long.parseLong(prefs.getString( KEY_AUTO_SYNC_INTERVAL, getString(R.string.auto_sync_interval_default) )); ContentResolver.addPeriodicSync(AppDelegate.sAccount, AppDelegate.AUTHORITY, Bundle.EMPTY, interval); } else { ContentResolver.removePeriodicSync(AppDelegate.sAccount, AppDelegate.AUTHORITY, new Bundle()); } } else if (TextUtils.equals(KEY_AUTO_SYNC_INTERVAL, key)) { final ListPreference interval = (ListPreference) getPreferenceManager().findPreference(key); interval.setSummary(interval.getEntry()); ContentResolver.addPeriodicSync( AppDelegate.sAccount, AppDelegate.AUTHORITY, Bundle.EMPTY, Long.parseLong(interval.getValue()) ); } } } 


рдпрд╣ рд╕рдм рдПрдХ рдвреЗрд░ рдореЗрдВ рдПрдХрддреНрд░ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдореЗрдВ рдПрдХ рдХрд╛рдо рдХрд░рдиреЗ рд╡рд╛рд▓рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдорд┐рд▓рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдЙрди рд╕рднреА рдЕрдЪреНрдЫрд╛рдЗрдпреЛрдВ рдХреЗ рд╕рд╛рде рд╣реЛрддрд╛ рд╣реИ, рдЬреЛ рдПрдВрдбреНрд░реЙрдЗрдб рд╕рд┐рд╕реНрдЯрдо рд╣рдореЗрдВ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдкрд░реНрджреЗ рдХреЗ рдкреАрдЫреЗ рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рд╕реНрд╡рд╛рджрд┐рд╖реНрдЯ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╕рд┐рдВрдХ рдПрдбреЗрдкреНрдЯрд░ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреА рд╢рдХреНрддрд┐ рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред

рдпрд╣ рд╕рдм, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИред рдкреВрд░реНрдг рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реНрд░реЛрдд рдпрд╣рд╛рдВ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ ред рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред рд░рдЪрдирд╛рддреНрдордХ рдЖрд▓реЛрдЪрдирд╛ рдХрд╛ рд╕реНрд╡рд╛рдЧрдд рд╣реИред

Android рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝реЗрд╢рдиред рднрд╛рдЧ рдПрдХ

Source: https://habr.com/ru/post/In216857/


All Articles