Android应用使用SyncAdapter传输数据

本文涉及的产品
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
数据传输服务 DTS,数据同步 1个月
简介: 转自 : http://blog.csdn.net/javensun/article/details/41984373 在Android设备和web服务器之间同步数据会使你的应用更实用,更吸引用户,例如,将手机数据传到服务端实现数据备份,将数据从服务端取回让用户能够脱机使用。在某些情况下,用户会发现这样会更方便:通过web修改信息然后在手机上就可以继续使用,或者隔一段时间将手机上

转自 : http://blog.csdn.net/javensun/article/details/41984373


在Android设备和web服务器之间同步数据会使你的应用更实用,更吸引用户,例如,将手机数据传到服务端实现数据备份,将数据从服务端取回让用户能够脱机使用。在某些情况下,用户会发现这样会更方便:通过web修改信息然后在手机上就可以继续使用,或者隔一段时间将手机上的数据上传到一个总存储区。
虽然你可以在应用中设计自己的数据传输系统,但也应该考虑一下用Android的sync adater框架。它可以协助管理和自动发起数据传输,也可以协调不同应用的同步操作。使用这个同步框架比自己设计数据传输策略有如下优势:
插件架构:
可以将数据传输的代码以可调用组件的形式添加到系统中。
自动执行:
可以根据不同条件自动发起数据传输,比如数据变更,间隔一定时间,或者是每天定时。而且,系统会将暂时不能运行的操作添加到队列里,在可能的情况下重新发起。
自动检查网络:
系统只会在有网络的情况下发起数据传输
优化电池性能:
可以集中处理数据传输任务。将你的应用的数据传输与其他应用的传输结合,减少系统切换网络的次数,从而降低功耗。
账号管理认证:
如果你的应用需要用户认证功能,你可以选择在数据传输中整合进账号管理认证。

这篇课程将教你如何创建sync adapter并绑定对应的Service,如何提供那些将sync adapter插入到框架中所需的组件,如何用不同的方式运行sync adapter.
注意:Sync adapter是异步运行的,因此使用的时候要知道它并不是即时响应的。如果需要实时传输,应该使用  AsyncTask 或者  IntentService.


创建Authenticator

Sync adapter 框架假设数据传输时是要账号认证的。因此,需要你在sync adapter中提供一个叫authenticator的组件。这个组件将会插入到android的账号认证框架中,并提供管理用户认证信息的标准接口。
即使你的应用不需要账号认证,你还是需要创建一个authenticator组件。如果你不用账号登录,authenticator的信息将被忽略,因此你可以提供一个仅包含了方法实现的组件。还需要提供一个Service给sync adapter框架,以调用authenticator的方法。

接下来将教你如何定义一个满足sync adapter框架需要的虚拟authenticator。如果你需要创建一个真实管理用户账户的authenticator,请参阅 AbstractAccountAuthenticator的文档。

添加Authenticator 组件

创建一个继承自  AbstractAccountAuthenticator 的类,通过返回null或是抛出异常来模拟实现需要的方法。
下面的代码段是一份样例
<span class="com">/*
 * Implement AbstractAccountAuthenticator and stub out all
 * of its methods
 */</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Authenticator</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">AbstractAccountAuthenticator</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Simple constructor</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Authenticator</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Context</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">super</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">context</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Editing properties is not supported</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> editProperties</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">AccountAuthenticatorResponse</span><span class="pln" style="color: rgb(0, 0, 0);"> r</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> s</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">throw</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">UnsupportedOperationException</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Don't add additional accounts</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> addAccount</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">AccountAuthenticatorResponse</span><span class="pln" style="color: rgb(0, 0, 0);"> r</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> s</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> s2</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pun" style="color: rgb(102, 102, 0);">[]</span><span class="pln" style="color: rgb(0, 0, 0);"> strings</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> bundle</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">throws</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">NetworkErrorException</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Ignore attempts to confirm credentials</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> confirmCredentials</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">AccountAuthenticatorResponse</span><span class="pln" style="color: rgb(0, 0, 0);"> r</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> account</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> bundle</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">throws</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">NetworkErrorException</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Getting an authentication token is not supported</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> getAuthToken</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">AccountAuthenticatorResponse</span><span class="pln" style="color: rgb(0, 0, 0);"> r</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> account</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> s</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> bundle</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">throws</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">NetworkErrorException</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">throw</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">UnsupportedOperationException</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Getting a label for the auth token is not supported</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> getAuthTokenLabel</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> s</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">throw</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">UnsupportedOperationException</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Updating user credentials is not supported</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> updateCredentials</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">AccountAuthenticatorResponse</span><span class="pln" style="color: rgb(0, 0, 0);"> r</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> account</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> s</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> bundle</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">throws</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">NetworkErrorException</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">throw</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">UnsupportedOperationException</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Checking features for the account is not supported</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> hasFeatures</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">AccountAuthenticatorResponse</span><span class="pln" style="color: rgb(0, 0, 0);"> r</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> account</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pun" style="color: rgb(102, 102, 0);">[]</span><span class="pln" style="color: rgb(0, 0, 0);"> strings</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">throws</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">NetworkErrorException</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">throw</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">UnsupportedOperationException</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

将Authenticator绑定至Framework

为了使Sync adapter框架能够访问你的authenticator,你必须为它创建一个服务。这个服务提供了一个binder对象,供框架调用authenticator时,或是在authenticator和框架之间传输数据时使用。
既然框架首次启动这个服务时它就需要访问authenticator,你可以通过在Service的onCreate()里调用authenticator的构造方法将其实例化。
下面的示例代码展示了如何定义这个服务:

<span class="com">/**
 * A bound Service that instantiates the authenticator
 * when started.
 */</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">AuthenticatorService</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Service</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Instance field that stores the authenticator object</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">private</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Authenticator</span><span class="pln" style="color: rgb(0, 0, 0);"> mAuthenticator</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Create a new authenticator object</span><span class="pln" style="color: rgb(0, 0, 0);">
        mAuthenticator </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Authenticator</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">this</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * When the system binds to this Service to make the RPC call
     * return the authenticator's IBinder.
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">IBinder</span><span class="pln" style="color: rgb(0, 0, 0);"> onBind</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Intent</span><span class="pln" style="color: rgb(0, 0, 0);"> intent</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> mAuthenticator</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getIBinder</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>


添加Authenticator的元数据(Metadata)文件

将authenticator组件添加到账号框架中时,你需要提供描述这个组件的元数据。元数据中声明了你创建的账号类型和一些在需要显示给用户的信息(若账号类型对用户可见)。元数据声明在一个XML文件中,这个文件保存在你应用工程的 /res/xml/目录中。名字自定义,一般叫做 authenticator.xml
XML文件中包含单独一个具有以下属性的 <account-authenticator>元素:
android:accountType
同步框架要求每个sync adapter有一个账号类型。框架会把账号类型作为识别sync adapter的内部标识。对于需要登录的服务器,账号类型会和账号名一起作为登录信息发送给服务器。
如果你的服务器不要求登录,你也要提供一个账号类型,它标明了你所控制的域,框架用这个账号类型来管理你的sync adapter,但是不发送给服务器。
android:icon
指向一个用做图标的Drawable资源。如果你在 res/xml/syncadapter.xml 设置了 android:userVisible="true”  属性将Sync adapter对用户可见,那必须要提供一个图标资源。它将显示在“设置”应用的“账号”一项中。
android:smallIcon
小版本的图标。依据屏幕的尺寸,它可能在设置中用来代替 android:icon。
android:label
给用户标识账号类型的字符串。在“设置”里和上面的图标显示在一起。
以下的代码段是刚刚创建的authenticator 所对应的XML文件:
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:accountType="example.com"
        android:icon="@drawable/ic_launcher"
        android:smallIcon="@drawable/ic_launcher"
        android:label="@string/app_name"/>

声明Authenticator

通过之前的几步,我们创建了一个将与authenticator与framework关联的Service。要让系统能认识这个Service,我们需要在应用的manifest文件中的  <application> 下声明一个 <service> 子元素如下:
    <service
            android:name="com.example.android.syncadapter.AuthenticatorService">
        <intent-filter>
            <action android:name="android.accounts.AccountAuthenticator"/>
        </intent-filter>
        <meta-data
            android:name="android.accounts.AccountAuthenticator"
            android:resource="@xml/authenticator" />
    </service>

<intent-filter> 设置了通过action  android.accounts.AccountAuthenticator 启动的filter。这个action是由系统发送的。当被触发时,系统会启动你之前提供的封装了你的athtenticator的  AuthenticatorService 。
  <meta-data> 声明了authenticator的元数据。通过 android:name 属性将meta-data与认证框架关联。 android:resource 指定刚才创建的元数据文件的名字。

除了authenticator以外, sync adapter还需要一个content provider。

创建Content Provider

设计同步框架是用来与安全易用的Content Privder框架协作的。因此,使用同步框架的应用已经先有一个Content Provider来存储本地数据。如果同步框架要运行你的Sync adapter,而你还没有Content Provider,那应用会崩溃。如果你准备开发一个需要与服务端传输数据的应用,那么强烈推荐你用Content Provider来存储数据。不仅是方便使用SyncAdapter,而且它也具有更好的安全性。
尽管如此,如果你已经将本地数据存储为别的什么格式,你仍然可以使用Sync Adapter来传输数据。 为了满足同步框架对Content Privder的要求,你需要在应用中添加一个虚拟的Content Privder,实现一下必须的方法,可以全部返回null或者0. 添加好之后,你就可以通过Sync Adapter按照你自己的存储形式来传输数据。
如果你应用中已经使用过Content Provider,你就可以跳过接下来这一段课程,直接进行“ 创建Sync Adapter”这一节。如果没有,那接下来会教你如何添加一个ContentProvider,这样才能将Sync Adapter添加到框架中。

添加一个Content Provider

继承  ContentProvider 类 ,实现那些必要的方法。如下面这段代码:
<span class="com">/*
 * Define an implementation of ContentProvider that stubs out
 * all methods
 */</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">StubProvider</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">ContentProvider</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * Always return true, indicating that the
     * provider loaded correctly.
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">boolean</span><span class="pln" style="color: rgb(0, 0, 0);"> onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">true</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * Return an empty String for MIME type
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> getType</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * query() always returns no results
     *
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Cursor</span><span class="pln" style="color: rgb(0, 0, 0);"> query</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Uri</span><span class="pln" style="color: rgb(0, 0, 0);"> uri</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pun" style="color: rgb(102, 102, 0);">[]</span><span class="pln" style="color: rgb(0, 0, 0);"> projection</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> selection</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pun" style="color: rgb(102, 102, 0);">[]</span><span class="pln" style="color: rgb(0, 0, 0);"> selectionArgs</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> sortOrder</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * insert() always returns null (no URI)
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Uri</span><span class="pln" style="color: rgb(0, 0, 0);"> insert</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Uri</span><span class="pln" style="color: rgb(0, 0, 0);"> uri</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">ContentValues</span><span class="pln" style="color: rgb(0, 0, 0);"> values</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * delete() always returns "no rows affected" (0)
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">int</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">delete</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Uri</span><span class="pln" style="color: rgb(0, 0, 0);"> uri</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> selection</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pun" style="color: rgb(102, 102, 0);">[]</span><span class="pln" style="color: rgb(0, 0, 0);"> selectionArgs</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">0</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * update() always returns "no rows affected" (0)
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">int</span><span class="pln" style="color: rgb(0, 0, 0);"> update</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Uri</span><span class="pln" style="color: rgb(0, 0, 0);"> uri</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">ContentValues</span><span class="pln" style="color: rgb(0, 0, 0);"> values</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> selection</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pun" style="color: rgb(102, 102, 0);">[]</span><span class="pln" style="color: rgb(0, 0, 0);"> selectionArgs</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">0</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

在Manifest中声明Provider

同步框架通过检查应用的manifest文件中的声明来确认应用是否有ContentProvider。要声明Provider,需要在manifest里添加一个  <provider> 属性,它具有以下属性:
android:name="com.example.android.datasync.provider.StubProvider"
指定实现ContentProvider的完整类名。
android:authorities="com.example.android.datasync.provider"
用来唯一指定一个ContentProvider的URI authority。这个值最好设置为“包名 + .provider”。 
Even though you're declaring your stub provider to the system, nothing tries to access the provider itself.
android:exported="false"
设置外部应用是否可以访问。因为我们的Provider并不需要别的应用访问,所以设置为”false”。这个值并不影响同步框架的访问。
android:syncable="true"
设置是否可同步。如果设置为true 就不需要在代码中再调用setIsSyncable() 。这个值决定了同步框架可以与Provider传输数据,但是也仅在你明确调用的时候才传输。( 译者注:SyncAdapter有类似属性:isAlwaysSyncable )。

以下代码段说明了如何在manifest中声明Provider:
<span class="tag" style="color: rgb(0, 0, 136);"><manifest</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="atn" style="color: rgb(136, 34, 136);">xmlns:android</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"http://schemas.android.com/apk/res/android"</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="atn" style="color: rgb(136, 34, 136);">package</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"com.example.android.network.sync.BasicSyncAdapter"</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="atn" style="color: rgb(136, 34, 136);">android:versionCode</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"1"</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="atn" style="color: rgb(136, 34, 136);">android:versionName</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"1.0"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="tag" style="color: rgb(0, 0, 136);">></span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="tag" style="color: rgb(0, 0, 136);"><application</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:allowBackup</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"true"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:icon</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"@drawable/ic_launcher"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:label</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"@string/app_name"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:theme</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"@style/AppTheme"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="tag" style="color: rgb(0, 0, 136);">></span><span class="pln" style="color: rgb(0, 0, 0);">
    ...
    </span><span class="tag" style="color: rgb(0, 0, 136);"><provider</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider.StubProvider"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:authorities</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:exported</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"false"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:syncable</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"true"</span><span class="tag" style="color: rgb(0, 0, 136);">/></span><span class="pln" style="color: rgb(0, 0, 0);">
    ...
    </span><span class="tag" style="color: rgb(0, 0, 136);"></application></span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="tag" style="color: rgb(0, 0, 136);"></manifest></span>
到此为止,我们已经创建了同步框架所有需要的依赖项。接下来需要创建数据传输的组件,叫做Sync Adapter.

创建SyncAdapter

应用中的SyncAdapter封装了应用和服务器传输数据的代码。同步框架会根据你设置的定期任务或者触发器运行SyncAdapter组件中的代码。要在应用中添加SyncAdapter需要添加如下几点:
  • SyncAdapter 类
    这个类会将数据传输的代码按照与同步框架兼容的接口进行封装。
  • 同步Service
    提供给外部进行绑定,让框架可以运行SyncAdapter中的代码。
  • SyncAdapter的XML文件
    其中包含了SyncAdapter的一些信息,框架会根据这个文件的内容来决定如何加载和安排数据传输。
  • 在AndroidManifest中的声明
    声明了绑定用的Service,并标明了SyncAdapter的元数据文件。

创建SyncAdapter类

包括继承基类、定义构造方法、实现数据传输的方法。

继承AbstracThreadedSyncAdapter基类

首先要继承 AbstractThreadedSyncAdapter 基类并且实现其构造方法。在 构造方法中做一些创建 SyncAdapter时需要的 设置 ,类似于在 Activity.onCreate() 设置一个Activity。例如,如果你使用ContentProvider存储数据的,在构造方法中就去获取一下 ContentResolver 的实例。因为在Android3.0版本中新加了一个支持 parallelSyncs 参数的构造方法,为保持兼容需要创建两种形式的构造方法。

注意: 同步框架是为单实例SyncAdapter组件而设计的( 译者注:若非单例模式可能会导致内存泄露。实例化SyncAdapter的详细内容请看 Bind the Sync Adapter to the Framework.

下面的例子展示了如何实现  AbstractThreadedSyncAdapter 及其构造方法。
<span class="com">/**
 * Handle the transfer of data between a server and an
 * app, using the Android sync adapter framework.
 */</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">SyncAdapter</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">AbstractThreadedSyncAdapter</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Global variables</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Define a variable to contain a content resolver instance</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pln" style="color: rgb(0, 0, 0);"> mContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/**
     * Set up the sync adapter
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">SyncAdapter</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Context</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">boolean</span><span class="pln" style="color: rgb(0, 0, 0);"> autoInitialize</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">super</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">context</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> autoInitialize</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * If your app uses a content resolver, get an instance of it
         * from the incoming Context
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        mContentResolver </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/**
     * Set up the sync adapter. This form of the
     * constructor maintains compatibility with Android 3.0
     * and later platform versions
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">SyncAdapter</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Context</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="kwd" style="color: rgb(0, 0, 136);">boolean</span><span class="pln" style="color: rgb(0, 0, 0);"> autoInitialize</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="kwd" style="color: rgb(0, 0, 136);">boolean</span><span class="pln" style="color: rgb(0, 0, 0);"> allowParallelSyncs</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">super</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">context</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> autoInitialize</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> allowParallelSyncs</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * If your app uses a content resolver, get an instance of it
         * from the incoming Context
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        mContentResolver </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

添加数据传输的代码至onPerformSync()

SyncAdapter不会自动做数据传输,它只是封装你的代码,以便框架可以在后台调用,而不需要你的应用介入。同步框架准备要同步应用数据的时候,它会调用你SyncAdapter中实现的 onPerformSync()方法。
为了方便SyncAdapter获取你应用的数据,同步框架调用 onPerformSync()  时会传入以下参数:
  • Account
    与本次触发事件关联的Account对象,如果你的服务器不需要账号,直接无视就可以。
  • Extras
    包含一些标志位的Bundle 对象
  • Authority
    系统中ContentProvider的authority,一般是你自己应用中的ContentProvider对应的authority。
  • Content provider client
    authority对应的ContentProviderClient,它是ContentProvider的一个轻量接口,具有与ContentResolver相同的功能。如果是用ContentProvider保存的数据,你可以用这个对象连接到ContentProvider,否则无视就好。
  • Sync result
     SyncResult对象,可以用来将同步的结果传给同步框架。
下面的代码段展示了 onPerformSync()的总体结构:
<span class="pln" style="color: rgb(0, 0, 0);">    </span><span class="com">/*
     * Specify the code you want to run in the sync adapter. The entire
     * sync adapter runs in a background thread, so you don't have to set
     * up your own background processing.
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onPerformSync</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> account</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> extras</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> authority</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">ContentProviderClient</span><span class="pln" style="color: rgb(0, 0, 0);"> provider</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">SyncResult</span><span class="pln" style="color: rgb(0, 0, 0);"> syncResult</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * Put the data transfer code here.
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span>
当然实际实现的  onPerformSync()是根据你的同步需求和服务器连接协议定制的,通常是下面几个通用的步骤:
  • 连接服务器
    虽然同步开始时你可以认为网络是通畅的,但是同步框架并不会自动帮你连接服务器
  • 下载上传数据
    SyncAdapter不会自动做数据传输。如果你要从服务端取数据存到本地,那你必须提供请求、下载、插入数据的代码。同样,如果需要上传数据,也要读数据、发送数据请求。除此之外,还需要处理数据传输中发生的网络错误。
  • 处理数据冲突
    SyncAdapter不会自动处理服务端和本地的数据冲突。而且,也不会检测本地和服务端的数据哪一个更新。你必须自己提供算法处理这种场景。
  • 清理
    在传输结束后关闭与服务器的链接,清理临时文件和缓存。
注意:同步框架自动将   onPerformSync() 放在后台线程,因此不需要自己设置后台运行。
除了同步相关的任务之外,也应该尽量将网络相关的任务添加到
onPerformSync()中。将网络操作集中处理可以降低频繁的发起终止网络造成的功耗。要了解如何高效的完成网络访问,可以参阅 Transferring Data Without Draining the Battery,其中讲了几个网络传输任务,可以添加到数据传输的代码中。

将SyncAdapter绑定到framework

现在我们已经有了一个封装了数据传输代码的SyncAdapter,接下来还要把它开放给framework调用,需要创建一个绑定用的Service,并把SyncAdapter的binder对象传给framework。通过这个binder,framework就可以调用到 onPerformSync()方法。
在Service的 onCreate()方法中以单实例的形式实例化SyncAdapter,这样也会将SyncAdapter的实例化延迟到framework首次传输数据要创建Service的时候执行。实例化的过程要保证线程安全,以免同步框架会将多次同步响应添加到队列中。
下面的代码段展示了如何实现Service类、实例化SyncAdapter并获取binder对象:
<span class="kwd" style="color: rgb(0, 0, 136);">package</span><span class="pln" style="color: rgb(0, 0, 0);"> com</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">example</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">android</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">syncadapter</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="com">/**
 * Define a Service that returns an </span><code style="line-height: 14px;"><a target=_blank target="_blank" href="http://developer.android.com/reference/android/os/IBinder.html" style="color: rgb(37, 138, 175); text-decoration: none;">IBinder</a></code><span class="com"> for the
 * sync adapter class, allowing the sync adapter framework to call
 * onPerformSync().
 */</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">SyncService</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Service</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Storage for an instance of the sync adapter</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">private</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">SyncAdapter</span><span class="pln" style="color: rgb(0, 0, 0);"> sSyncAdapter </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Object to use as a thread-safe lock</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">private</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Object</span><span class="pln" style="color: rgb(0, 0, 0);"> sSyncAdapterLock </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Object</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/*
     * Instantiate the sync adapter object.
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">synchronized</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">sSyncAdapterLock</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="kwd" style="color: rgb(0, 0, 136);">if</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">sSyncAdapter </span><span class="pun" style="color: rgb(102, 102, 0);">==</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
                sSyncAdapter </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">SyncAdapter</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">getApplicationContext</span><span class="pun" style="color: rgb(102, 102, 0);">(),</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">true</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/**
     * Return an object that allows the system to invoke
     * the sync adapter.
     *
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">IBinder</span><span class="pln" style="color: rgb(0, 0, 0);"> onBind</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Intent</span><span class="pln" style="color: rgb(0, 0, 0);"> intent</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * Get the object that allows external processes
         * to call onPerformSync(). The object is created
         * in the base class code when the SyncAdapter
         * constructors call super()
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> sSyncAdapter</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getSyncAdapterBinder</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

注意: 更详细的示例代码可以参阅示例工程BasicSyncAdapter.zip.


添加Account

同步框架要求每个SyncAdapter必须有一个账号类型,对应之前在“添加Authenticator元数据文件”提到的。现在需要在Android系统中设置这个账号类型:调用 addAccountExplicitly()方法,添加一个具有账号类型的虚拟账号。最好是在打开应用页面时的  onCreate()中调用这个方法。下面是示例:
<span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">MainActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">FragmentActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Constants</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// The authority for the sync adapter's content provider</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider"</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// An account type, in the form of a domain name</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT_TYPE </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"example.com"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// The account name</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"dummyaccount"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Instance fields</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> mAccount</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">protected</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">super</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Create the dummy account</span><span class="pln" style="color: rgb(0, 0, 0);">
        mAccount </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">CreateSyncAccount</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">this</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/**
     * Create a new dummy account for the sync adapter
     *
     * @param context The application context
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">CreateSyncAccount</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Context</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Create the account type and default account</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> newAccount </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
                ACCOUNT</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT_TYPE</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Get an instance of the Android account manager</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">AccountManager</span><span class="pln" style="color: rgb(0, 0, 0);"> accountManager </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">AccountManager</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getSystemService</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
                        ACCOUNT_SERVICE</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * Add the account and account type, no password or user data
         * If successful, return the Account object, otherwise report an error.
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">if</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">accountManager</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">addAccountExplicitly</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">newAccount</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">)))</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="com">/*
             * If you don't set android:syncable="true" in
             * in your <provider> element in the manifest,
             * then call context.setIsSyncable(account, AUTHORITY, 1)
             * here.
             */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">else</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="com">/*
             * The account exists or some other error occurred. Log this, report it,
             * or handle it internally.
             */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

添加SyncAdapter的元数据文件

要将SyncAdapger添加到框架中,需要给框架提供描述SyncAdapter的元数据和一些别的标志位。元数据指定了SyncAdapter的账号类型、对应的ContentProvider的Authority、系统中和SyncAdapter相关的部分UI,和其他的一些同步相关的标志。声明元数据的XML文件保存在 /res/xml/ 目录下,名字自定义,但一般叫做 syncadapter.xml
这个XML文件包含了一个单独的元素 <sync-adapter>,它具有以下属性:
  • android contentAuthority
    之前创建的ContentProvider对应的URI的Authority。如果你的数据是从ContentProvider传给服务端的,那这个要对应ContentProvider的XML中<provider> 元素的android:authorities属性值。
  • android accountType
    同步框架所需要的账号类型,需要与前面在代码段中的ACCOUNT_TYPE 常量还有authenticator的元数据文件中定义的保持一致。
  • android:userVisible
    设置SyncAdapter的账号类型是否在“设置”应用可见。默认情况下账号的图标和标签是在“设置”中可见的。除非你有与应用关联的账号类型或域,否则还是将它设为不可见。即使设置为不可见,还是可以让用户在应用内的界面对SyncAdapter进行控制。
  • android:supportsUploading
    允许应用上传数据到云端。如果你的应用只需要下载数据,那就设置为false。(译者注:当发起同步时设置了ContentResolver.SYNC_EXTRAS_UPLOAD,这个属性才起作用,用来决定是否支持仅上传的操作。ContentResolver中的 notifyChange(android.net.Uri, android.database.ContentObserver, boolean)方法发起的同步会带仅上传的SYNC_EXTRAS_UPLOAD标志位
  • android:allowParallelSyncs
    设置是否允许SyncAdapter多实例同时运行。如果你的应用需要支持多账号并发传输数据时才需要使用这个标志,如果没有并发的数据传输,那这个标志是无效的。
  • android:isAlwaysSyncable
    指定同步框架是否可以在任意时间运行你的SyncAdapter。如果你只希望通过程序控制何时发起,那就设置为false,然后通过调用 requestSync()发起。了解更多请参看Running a Sync Adapter;(译者注:Provider中有isSyncable属性,功能类似
下面的代码展示了使用一个虚拟账号仅作下载的SyncAdapter的XML文件内容:
<span class="pun" style="color: rgb(102, 102, 0);"><?</span><span class="pln" style="color: rgb(0, 0, 0);">xml version</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="str" style="color: rgb(136, 0, 0);">"1.0"</span><span class="pln" style="color: rgb(0, 0, 0);"> encoding</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="str" style="color: rgb(136, 0, 0);">"utf-8"</span><span class="pun" style="color: rgb(102, 102, 0);">?></span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="tag" style="color: rgb(0, 0, 136);"><sync-adapter</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">xmlns:android</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"http://schemas.android.com/apk/res/android"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:contentAuthority</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:accountType</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"com.android.example.datasync"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:userVisible</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"false"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:supportsUploading</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"false"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:allowParallelSyncs</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"false"</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="atn" style="color: rgb(136, 34, 136);">android:isAlwaysSyncable</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"true"</span><span class="tag" style="color: rgb(0, 0, 136);">/></span>

在AndroidManifest中声明SyncAdapter

创建了SyncAdapter之后,就要请求相关的权限并声明绑定用的Service。因为SyncAdapter是在本地与网络传输数据的,就需要申请访问互联网的权限。除此之外,为了在程序中控制SyncAdapter,还需要申请读写SyncAdapter设置的权限。还有允许使用之前创建的authenticator组件的权限
申请这些权限需要在  <manifest>元素里添加以下子元素:
以下的代码段展示了如何添加这些权限:
<span class="tag" style="color: rgb(0, 0, 136);"><manifest></span><span class="pln" style="color: rgb(0, 0, 0);">
...
    </span><span class="tag" style="color: rgb(0, 0, 136);"><uses-permission</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"android.permission.INTERNET"</span><span class="tag" style="color: rgb(0, 0, 136);">/></span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="tag" style="color: rgb(0, 0, 136);"><uses-permission</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"android.permission.READ_SYNC_SETTINGS"</span><span class="tag" style="color: rgb(0, 0, 136);">/></span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="tag" style="color: rgb(0, 0, 136);"><uses-permission</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"android.permission.WRITE_SYNC_SETTINGS"</span><span class="tag" style="color: rgb(0, 0, 136);">/></span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="tag" style="color: rgb(0, 0, 136);"><uses-permission</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"android.permission.AUTHENTICATE_ACCOUNTS"</span><span class="tag" style="color: rgb(0, 0, 136);">/></span><span class="pln" style="color: rgb(0, 0, 0);">
...
</span><span class="tag" style="color: rgb(0, 0, 136);"></manifest></span>

最后,要声明Framework与SyncAdapter交互用的Service,在 <application>中添加下面的子元素:
<span class="pln" style="color: rgb(0, 0, 0);">        </span><span class="tag" style="color: rgb(0, 0, 136);"><service</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"com.example.android.datasync.SyncService"</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="atn" style="color: rgb(136, 34, 136);">android:exported</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"true"</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="atn" style="color: rgb(136, 34, 136);">android:process</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">":sync"</span><span class="tag" style="color: rgb(0, 0, 136);">></span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="tag" style="color: rgb(0, 0, 136);"><intent-filter></span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="tag" style="color: rgb(0, 0, 136);"><action</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"android.content.SyncAdapter"</span><span class="tag" style="color: rgb(0, 0, 136);">/></span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="tag" style="color: rgb(0, 0, 136);"></intent-filter></span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="tag" style="color: rgb(0, 0, 136);"><meta-data</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="atn" style="color: rgb(136, 34, 136);">android:name</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"android.content.SyncAdapter"</span><span class="pln" style="color: rgb(0, 0, 0);">
                    </span><span class="atn" style="color: rgb(136, 34, 136);">android:resource</span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="atv" style="color: rgb(136, 0, 0);">"@xml/syncadapter"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="tag" style="color: rgb(0, 0, 136);">/></span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="tag" style="color: rgb(0, 0, 136);"></service></span>

<intent-filter>元素设置了一个由Action 为 android.content.SyncAdapter的Intent触发的过滤器,系统要运行SyncAdapter时会发送这个Intent。当过滤器被触发时,系统会创建绑定用的Service,本例中即 SyncService
android:exported="true"的属性允许出你的应用之外的进程来访问这个Service。
  android:process=":sync" 告诉系统在名为 sync 的全局共享的进程中运行这个Service。如果你的应用中有多个SyncAdapter,他们可以共享这个进程,可以降低一些消耗。
  <meta-data> 元素规定了我们之前创建SyncAdapter元数据XML文件。 android:name 属性说明了这个元数据是给同步框架的。 android:resource元素指定了元数据文件的名字。
现在我们准备好了SyncAdapter所有的组件。下面来看一下如何告诉同步框架来运行你的SyncAdapter,通过事件响应的方式或是定时触发。

运行SyncAdapter

前面我们讲了如何创建一个封装数据传输代码的SyncAdapter,如何添加其它组件将SyncAdapter加入到系统。至此我们要安装一个带有SyncAdapter的应用已经万事俱备了,但是还并没有看到如何运行SyncAdapter。
你应该通过定期任务或是根据一些事件的结果来运行SyncAdapter。比如,隔一段时间或在每天某个特殊的时间运行,或是在本地数据变化后运行。
但要避免根据用户直接的操作来运行,因为这样的话就难以发挥同步框架管理的优势。比如,不要在UI中提供刷新按钮。
你可以用以下几种方式运行SyncAdapter:
  • 服务端数据变化时
    服务端数据变化时,根据服务端发送的消息运行。这样可以避免轮询服务器影响性能和功耗。
  • 本地数据变化时
    本地数据变化后同步可以将本地变化的数据发送到服务端,适合用来确保服务端数据最新。如果数据真的是用ContentProvider保存的,那这种方式是很容易实现的(译者注:在ContentProvider中使用ContentResolver的 notifyChange(android.net.Uri, android.database.ContentObserver, boolean)方法);如果是伪造的ContentProvider,那可能要麻烦一些。
  • 系统发送网络消息时
    当系统发出保持TCP/IP连接开启的网络消息时发起,这个网络消息是网络框架的一部分。这是自动同步的一种方式,可以考虑和基于时间间隔的同步结合起来使用。
  • 固定时间间隔
    自定义一个固定的时间间隔,或者是每天的某个时间点发起
  • 即时发起
    由用户手动操作发起。但是,为了有更好的体验,最好还是以自动同步为主,这样可以降低电池和网络资源的消耗。
接下来的课程进一步讲述了这几种运行方式。

服务端数据变更时同步

如果你的应用是从服务端取数据的,并且服务端数据变更频繁,就可以在数据变更后从服务端下载。要这么做,首先要服务端发送一条特殊的消息到你应用的 BroadcastReceiver,然后应用调用  ContentResolver.requestSync() 发起同步。谷歌云消息( Google Cloud Messaging )提供了发送这种消息的服务端和客户端的组件。使用GCM比轮询服务器更可靠更有效率,轮询需要 保持 一个一直 活动的 Service ,而GCM使用仅在消息到达时才被激活的 BroadcastReceiver;即使服务端没有变更,轮询还是要定期的消耗电量,而GCM仅在需要的时候才会发送消息。
注意:如果通过GCM发送广播给所有安装了应用的设备来发起同步,那这些设备差不多会在同时收到消息。这样会同时有多个SyncAdapter实例运行,导致服务器和网络过载。为了避免这种情况,应该在这些设备上各自做不同期限的延时。
下面的代码段展示了如何在收到GCM消息时运行   requestSync()发起同步:
<span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">GcmBroadcastReceiver</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">BroadcastReceiver</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Constants</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Content provider authority</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider"</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Account type</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT_TYPE </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Account</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"default_account"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Incoming Intent key for extended data</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> KEY_SYNC_REQUEST </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync.KEY_SYNC_REQUEST"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onReceive</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Context</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Intent</span><span class="pln" style="color: rgb(0, 0, 0);"> intent</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Get a GCM object instance</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">GoogleCloudMessaging</span><span class="pln" style="color: rgb(0, 0, 0);"> gcm </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="typ" style="color: rgb(102, 0, 102);">GoogleCloudMessaging</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getInstance</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">context</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Get the type of GCM message</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> messageType </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> gcm</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getMessageType</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">intent</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * Test the message type and examine the message contents.
         * Since GCM is a general-purpose messaging system, you
         * may receive normal messages that don't require a sync
         * adapter run.
         * The following code tests for a a boolean flag indicating
         * that the message is requesting a transfer from the device.
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">if</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">GoogleCloudMessaging</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">MESSAGE_TYPE_MESSAGE</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">equals</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">messageType</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="pun" style="color: rgb(102, 102, 0);">&&</span><span class="pln" style="color: rgb(0, 0, 0);">
            intent</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getBooleanExtra</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">KEY_SYNC_REQUEST</span><span class="pun" style="color: rgb(102, 102, 0);">))</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="com">/*
             * Signal the framework to run your sync adapter. Assume that
             * app initialization has already created the account.
             */</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">requestSync</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">ACCOUNT</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">null</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

ContentProvider数据变化时同步

如果你应用的数据是用ContentProvider管理的,并且希望数据更新的时候也同步到服务端,那就可以设置应用自动同步。首先,需要为ContentProvider注册一个Observer,当ContentProvider数据变化后,框架层会调用这个Observer。在Observer中调用 requestSync()告诉框架运行sync adapter。

注意: 如果你使用的是伪造的content provider,因为provider中没有数据,那onChange() 永远不会被调用到。这时,你需要自己提供检测数据变化的机制,然后在数据变化时调用requestSync() ;

要给你的ContentProvider创建Observer,只要继承 ContentObserver类并且实现其中的 onChange()方法。 在 onChange()中调用  requestSync()来运行SyncAdapter。

注册一个Observer,将它作为参数传入 registerContentObserver(),在调用时还需要传入需要监听的URI。ContentProvider框架会将这个URI与传入  ContentResolver的方法(例如 ContentResolver.insert())的URI进行比较。如果匹配成功,那你的 ContentObserver.onChange()会被调用。

下面的一段代码展示了如何定义一个在表数据变化时调用 requestSync() 的 ContentObserver

public class MainActivity extends FragmentActivity {
    ...
    // Constants
    // Content provider scheme
    public static final String SCHEME = "content://";
    // Content provider authority
    public static final String AUTHORITY = "com.example.android.datasync.provider";
    // Path for the content provider table
    public static final String TABLE_PATH = "data_table";
    // Account
    public static final String ACCOUNT = "default_account";
    // Global variables
    // A content URI for the content provider's data table
    Uri mUri;
    // A content resolver for accessing the provider
    ContentResolver mResolver;
    ...
    public class TableObserver extends ContentObserver {
        /*
         * Define a method that's called when data in the
         * observed content provider changes.
         * This method signature is provided for compatibility with
         * older platforms.
         */
        @Override
        public void onChange(boolean selfChange) {
            /*
             * Invoke the method signature available as of
             * Android platform version 4.1, with a null URI.
             */
            onChange(selfChange, null);
        }
        /*
         * Define a method that's called when data in the
         * observed content provider changes.
         */
        @Override
        public void onChange(boolean selfChange, Uri changeUri) {
            /*
             * Ask the framework to run your sync adapter.
             * To maintain backward compatibility, assume that
             * changeUri is null.
            ContentResolver.requestSync(ACCOUNT, AUTHORITY, null);
        }
        ...
    }
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Get the content resolver object for your app
        mResolver = getContentResolver();
        // Construct a URI that points to the content provider data table
        mUri = new Uri.Builder()
                  .scheme(SCHEME)
                  .authority(AUTHORITY)
                  .path(TABLE_PATH)
                  .build();
        /*
         * Create a content observer object.
         * Its code does not mutate the provider, so set
         * selfChange to "false"
         */
        TableObserver observer = new TableObserver(false);
        /*
         * Register the observer for the data table. The table's path
         * and any of its subpaths trigger the observer.
         */
        mResolver.registerContentObserver(mUri, true, observer);
        ...
    }
    ...
}

收到网络消息后发起同步(????存疑)

译者注: setSyncAutomatically()实际使用中被用作自动同步开关,在 本地Provider中notifyChange时和定期同步时都会判断这个开关状态,与本段中文档描述的不一致。

当网络连接可用时,Android系统会每隔几秒钟发送一条消息来保持手机的TCP/IP连接打开。这个消息也会到达每个应用的 ContentResolver 。通过调用 setSyncAutomatically(),可以设置 ContentResolve 在收到消息时自动发起同步。
通过设置在收到网络消息时发起同步,能确保在网络可用时发起同步。 如果你不需要在数据变化时立即强制发起同步,但是又想要保证数据有规律的更新,则可以使用这个选项。类似的,如果你不希望按照固定的时间间隔来同步但又希望能够频繁点的同步的话,也可以使用这个选项。
由于  setSyncAutomatically() 不会禁用 addPeriodicSync(),因此你的SyncAdapter可能会被频繁的重复触发。因此如果要定期的触发同步,就应该禁用掉  setSyncAutomatically()
下面的代码段展示了如何配置 ContentResolver 通过网络消息触发同步: 
<span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">MainActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">FragmentActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Constants</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Content provider authority</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Account</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"default_account"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Global variables</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// A content resolver for accessing the provider</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pln" style="color: rgb(0, 0, 0);"> mResolver</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">protected</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">super</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Get the content resolver for your app</span><span class="pln" style="color: rgb(0, 0, 0);">
        mResolver </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> getContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Turn on automatic syncing for the default account and authority</span><span class="pln" style="color: rgb(0, 0, 0);">
        mResolver</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">setSyncAutomatically</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">ACCOUNT</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">true</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

定期同步

设置固定的间隔时间,或者设置在每天的某个固定的时间点触发同步,或者两者同时使用。通过定期同步可以粗略的匹配服务端
数据的更新间隔。
同样,你也可以设置晚上同步,在服务端相对空闲的时间段上传数据。大多数用户在晚上会保持开机并充电的状态,因此这个时间点通常可用。而且,手机在运行你的SyncAdapter时不会运行其他的任务。尽管如此,如果要使用这种方式,一定要保证每个设备触发同步的时间有些许不同,试想如果所有的设备同时发起同步,你的服务器和运营商网络恐怕都会过载。
一般情况下,如果你的用户不需要即时更新数据,但又期望能够有规律的更新,那定期同步就派上用场了。还有一种情况,如果你想在数据更新的可用性和SyncAdapter运行效率之间做一个平衡,不想过度消耗资源的话,定期同步也是个不错的选择。
通过调用 addPeriodicSync()可以设置一个固定的时间间隔,在经过这段时间后发起同步。由于同步框架也负责其他SyncAdapter的执行,为了最大化电池续航,这个同步的间隔时间可能会有几秒的误差。而且,在没有网络的时候,框架也不会发起同步。
注意 addPeriodicSync()并不能在一天的某个特定时间点发起同步,要实现这一点需要使用重复的闹钟作触发。关于重复闹钟更详细的信息在的 AlarmManager参考文档中有描述。如果你是调用的 setInexactRepeating()设置触发时间,那么时间要设置成随机的,这样能保证将不同设备的同步时间错开。
addPeriodicSync()并不会禁用 setSyncAutomatically(),因此可能会有多个同步在短时间内发生。而且,只有少数的Flag可以在 addPeriodicSync()中使用,其他不允许使用的Flag可以参考 addPeriodicSync()的文档。
以下代码段展示了如何设置定期同步: 
<span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">MainActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">FragmentActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Constants</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Content provider authority</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Account</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"default_account"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Sync interval constants</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">long</span><span class="pln" style="color: rgb(0, 0, 0);"> SECONDS_PER_MINUTE </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">60L</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">long</span><span class="pln" style="color: rgb(0, 0, 0);"> SYNC_INTERVAL_IN_MINUTES </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">60L</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">long</span><span class="pln" style="color: rgb(0, 0, 0);"> SYNC_INTERVAL </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);">
            SYNC_INTERVAL_IN_MINUTES </span><span class="pun" style="color: rgb(102, 102, 0);">*</span><span class="pln" style="color: rgb(0, 0, 0);">
            SECONDS_PER_MINUTE</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Global variables</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// A content resolver for accessing the provider</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pln" style="color: rgb(0, 0, 0);"> mResolver</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">protected</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">super</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Get the content resolver for your app</span><span class="pln" style="color: rgb(0, 0, 0);">
        mResolver </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> getContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * Turn on periodic syncing
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">addPeriodicSync</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
                ACCOUNT</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
                AUTHORITY</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">EMPTY</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);">
                SYNC_INTERVAL</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span>

按需同步

通过响应用户请求发起同步是最不建议的同步策略。同步框架专门设计了按计划同步的策略来节省功耗。在数据变化时发起同步才是高效的做法,因为电量确实消耗在了传输新数据上。
与之相比,允许用户按需同步意味着同步是被自己发起的,会导致用户在并没有数据变化时发起同步,这种并没有刷新任何数据的同步对网络与电量资源的使用都是低效的。一般情况下,应用尽量使用一些其他的信号来触发同步,或者使用定期同步,而不是通过用户交互来触发。
尽管如此,如果你还是要按需发起同步,那就设置手动同步的flag,然后调用 ContentResolver.requestSync()
按需同步使用以下flag:
强制发起手动同步,同步框架会忽略当前的一些设置,比如自动同步开关状态。
强制立即发起同步。如果不设置这个选项,系统为了优化功耗可能会等待几秒钟,将一段时间内的几次同步合并发起。
以下代码展示了如何通过响应按键来发起同步: 

<span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">class</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">MainActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">extends</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">FragmentActivity</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Constants</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Content provider authority</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync.provider"</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Account type</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT_TYPE </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"com.example.android.datasync"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Account</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">static</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">final</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">String</span><span class="pln" style="color: rgb(0, 0, 0);"> ACCOUNT </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(136, 0, 0);">"default_account"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">// Instance fields</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="typ" style="color: rgb(102, 0, 102);">Account</span><span class="pln" style="color: rgb(0, 0, 0);"> mAccount</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="lit" style="color: rgb(0, 102, 102);">@Override</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">protected</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="kwd" style="color: rgb(0, 0, 136);">super</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">onCreate</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">savedInstanceState</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * Create the dummy account. The code for CreateSyncAccount
         * is listed in the lesson Creating a Sync Adapter
         */</span><span class="pln" style="color: rgb(0, 0, 0);">

        mAccount </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">CreateSyncAccount</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">this</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="com">/**
     * Respond to a button click by calling requestSync(). This is an
     * asynchronous operation.
     *
     * This method is attached to the refresh button in the layout
     * XML file
     *
     * @param v The View associated with the method call,
     * in this case a Button
     */</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">public</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">void</span><span class="pln" style="color: rgb(0, 0, 0);"> onRefreshButtonClick</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="typ" style="color: rgb(102, 0, 102);">View</span><span class="pln" style="color: rgb(0, 0, 0);"> v</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="pun" style="color: rgb(102, 102, 0);">...</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">// Pass the settings flags by inserting them in a bundle</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pln" style="color: rgb(0, 0, 0);"> settingsBundle </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Bundle</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
        settingsBundle</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">putBoolean</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">SYNC_EXTRAS_MANUAL</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">true</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        settingsBundle</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">putBoolean</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">
                </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">SYNC_EXTRAS_EXPEDITED</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">true</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="com">/*
         * Request the sync for the default account, authority, and
         * manual sync settings
         */</span><span class="pln" style="color: rgb(0, 0, 0);">
        </span><span class="typ" style="color: rgb(102, 0, 102);">ContentResolver</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">requestSync</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">mAccount</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> AUTHORITY</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> settingsBundle</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span>




附:

Android同步框架发起同步判断条件

所有同步发起时会判断以下属性:
  1. Provider的isSyncable
  2. SyncAdapter的isAlwaysSyncable
自动同步(SYNC_EXTRAS_MANUAL 为false)发起时除以上之外,还要判断以下:
  1. 系统总同步开关( getMasterSyncAutomatically
  2. SyncAdapter同步开关( getSyncAutomatically
若是通过调用ContentResolver 的notifyChange发起自动同步还需判断(时会带SYNC_EXTRAS_UPLOAD标志,Android设计原意是仅将本地数据更新至服务端。此时SyncAdapter中的supportsUploading若是false,则不能发起自动同步):
  1.  supportsUploading



相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
Sqoop 企业级大数据迁移方案实战
Sqoop是一个用于在Hadoop和关系数据库服务器之间传输数据的工具。它用于从关系数据库(如MySQL,Oracle)导入数据到Hadoop HDFS,并从Hadoop文件系统导出到关系数据库。 本课程主要讲解了Sqoop的设计思想及原理、部署安装及配置、详细具体的使用方法技巧与实操案例、企业级任务管理等。结合日常工作实践,培养解决实际问题的能力。本课程由黑马程序员提供。
目录
相关文章
|
3天前
|
移动开发 API Android开发
构建高效Android应用:Kotlin协程的实践指南
【5月更文挑战第11天】 在移动开发领域,性能优化和资源管理是至关重要的。特别地,对于Android开发者来说,合理利用Kotlin协程可以极大地改善应用的响应性和稳定性。本文将深入探讨Kotlin协程在Android中的实际应用,包括它们如何简化异步编程模型、提高UI线程的响应性,以及减少内存消耗。我们将通过具体案例分析,了解如何在实际项目中有效地使用协程,从而帮助开发者构建更加高效的Android应用程序。
|
1天前
|
存储 传感器 Android开发
构建高效Android应用:从优化布局到提升性能
【5月更文挑战第13天】 在竞争激烈的移动应用市场中,一个高效的Android应用不仅需要具备直观的用户界面和丰富的功能,还要确保流畅的性能和快速的响应时间。本文将深入探讨如何通过优化布局设计、减少资源消耗以及利用系统提供的API来提升Android应用的性能。我们将分析布局优化的策略,讨论内存使用的常见陷阱,并介绍异步处理和电池寿命的考量。这些技术的综合运用将帮助开发者构建出既美观又高效的Android应用。
|
1天前
|
移动开发 Android开发 开发者
构建高效Android应用:探究Kotlin协程的优化实践
【5月更文挑战第13天】 在移动开发领域,Android平台的流畅体验至关重要。随着Kotlin语言的普及,协程作为其核心特性之一,为异步编程提供了简洁且高效的解决方案。本文将深入探讨Kotlin协程在Android应用中的优化使用,从基本概念到实际案例分析,旨在帮助开发者构建更加响应迅速、性能卓越的应用。我们将通过对比传统线程与协程的差异,展示如何利用协程简化代码结构,并通过优化实践减少资源消耗,提升用户体验。
|
2天前
|
移动开发 监控 Android开发
构建高效Android应用:Kotlin协程的实践与优化
【5月更文挑战第12天】 在移动开发领域,性能与响应性是衡量一个应用程序优劣的关键指标。特别是在Android平台上,由于设备的多样性和系统资源的限制,开发者需要精心编写代码以确保应用流畅运行。近年来,Kotlin语言因其简洁性和功能性而广受欢迎,尤其是其协程特性,为异步编程提供了强大而轻量级的解决方案。本文将深入探讨如何在Android应用中使用Kotlin协程来提升性能,以及如何针对实际问题进行优化,确保应用的高效稳定执行。
|
4天前
|
Android开发 数据库管理
Android如何在Activity和Service之间传递数据
Android如何在Activity和Service之间传递数据
10 3
|
5天前
|
开发工具 Android开发 Windows
Android应用] 问题2:ERROR: unknown virtual device name:
Android应用] 问题2:ERROR: unknown virtual device name:
10 2
|
5天前
|
XML JSON API
转Android上基于JSON的数据交互应用
转Android上基于JSON的数据交互应用
|
数据采集 传感器 编解码
【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )
【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )
241 0
|
数据采集 存储 编解码
【Android RTMP】音频数据采集编码 ( FAAC 音频编码参数设置 | FAAC 编码器创建 | 获取编码器参数 | 设置 AAC 编码规格 | 设置编码器输入输出参数 )
【Android RTMP】音频数据采集编码 ( FAAC 音频编码参数设置 | FAAC 编码器创建 | 获取编码器参数 | 设置 AAC 编码规格 | 设置编码器输入输出参数 )
226 0
|
数据采集 Android开发 索引
【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 )(二)
【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 )(二)
444 0
【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 )(二)