从网络获取数据(2)使用SyncAdapter

之前我们讲的都是及时传输数据,这些随机的数据传输不利于管理,影响内存或者电池的使用,现在安卓提供了一个sync adapter框架,

帮助管理和自动进行数据传输,并且在不同app间合作进行同步。还有如下特色:

 Plug-in architecture

允许我们添加数据传输的代码到系统以可调用组件的形式

 Automated execution

允许我们基于一些标准的自动数据传输,包括数据改变、逝去时间或者一天中的时间(including data changes, elapsed time, or time of day)。此外,系统添加不能执行的传输到一个队列中,在可能时运行他们

 Automated network checking

系统仅仅会执行数据传输当设备有网络连接(不用自己判断有没有网了)

 Improved battery performance

允许我们集中应用的所有数据传输任务发生在一个地方,这样他们全部同时运行。我们的应用传输也和其他应用的数据传输一起协同调度。这些因素减少了系统开启网络的次数,减少电量使用

 Account management and authentication

如果我们的应用要求用户授权或者服务登录,我们可以选择性的集成账户管理和权限认证到我们的数据传输中。

下面来学习如何使用Sync Adapter

Creating a Stub Authenticator

sync adapter假设我们的数据传输和一个账号关联并且服务器数据存储需要登录权限。

及时我们不需要账户,也要模拟添加一个。

(1)继承AbstractAccountAuthenticator,实现默认方法

(2)绑定Authenticator到框架

提供一个绑定服务,在服务的OnCreate方法实例化Authenticator, 在onBind方法返回mAuthenticator.getBinder().

返回的这个IBinder是在OnCreate方法中创建的Authenticator对象获得的。

(3)添加Authenticator Metadata文件

在res/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"/>

(4)在Manifest中声明Authenticator

为上面创建的服务添加声明:

   <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>元素设置了一个filter由android.accounts.AccountAuthenticator触发,由系统发送用来运行这个authenticator。当filter被触发,系统开启AuthenticatorService,我们提供的用来wrap Authenticator的bound service。

<meta-data>元素为Authenticator声明metadata。Android:name属性连接meta-data到Authentication框架。Android:resource元素指定我们之前创建的Authenticator metadata文件。

Creating a Stub Content Provider

如果没有内容提供器,还要创建一个提供器。这个不相信讲了,参看http://blog.csdn.net/qingziguanjun1/article/details/51330360

Creating a Sync Adapter

最重要的部分就是创建这个适配器了,这个适配器包裹了传输数据的代码。以我们在app中提供的调度和触发器为基础,sync Adapter

框架运行这些代码在sync adapter 组件中。(又是Adapter,这种设计方式很棒啊?)。我们需要添加下面的组成:

Sync adapter class.
A class that wraps your data transfer code in an interface compatible with the sync adapter framework.
Bound Service.
A component that allows the sync adapter framework to run the code in your sync adapter class.
Sync adapter XML metadata file.
A file containing information about your sync adapter. The framework reads this file to find out how to load and schedule your data transfer.
Declarations in the app manifest.
XML that declares the bound service and points to sync adapter-specific metadata.

一共四个部分,一个Adapter类,一个绑定服务,一个xml,在nanifest声明服务,指向Adapter。

和Authenticator很像啊,我们只负责定义这些部分,然后在Manifest中声明一下如何使用他们,然后就系统会帮我们调用。

那我们是在哪里开始调用的呢?后面会讲到

下面开始讲解四个部分:

Create a Sync Adapter Class

(1)继承AbstractThreadedSyncAdapter,提供构造器,构造器执行设置,比如使用内容提供器,那么实例化一个ContentResolver对象。

下面是例子

(2)在onPerformSync中添加数据传输代码

这个方法接收的参数好几个,哪里来的,系统传递的?为什么sunshine的这个方法没有使用这几个参数?这些参数应该从下面

创建的绑定服务传来的。

(3)绑定sync adapter到框架

在服务的OnCreate方法,单例线程安全的创建SyncAdapter对象。饿汉式。

package com.example.android.syncadapter;
/**
 * Define a Service that returns an IBinder for the
 * sync adapter class, allowing the sync adapter framework to call
 * onPerformSync().
 */
public class SyncService extends Service {
    // Storage for an instance of the sync adapter
    private static SyncAdapter sSyncAdapter = null;
    // Object to use as a thread-safe lock
    private static final Object sSyncAdapterLock = new Object();
    /*
     * Instantiate the sync adapter object.
     */
    @Override
    public void onCreate() {
        /*
         * Create the sync adapter as a singleton.
         * Set the sync adapter as syncable
         * Disallow parallel syncs
         */
        synchronized (sSyncAdapterLock) {
            if (sSyncAdapter == null) {
                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
            }
        }
    }
    /**
     * Return an object that allows the system to invoke
     * the sync adapter.
     *
     */
    @Override
    public IBinder onBind(Intent intent) {
        /*
         * 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()
         */
        return sSyncAdapter.getSyncAdapterBinder();
    }
}

(4)添加框架要求的账户

最好的地方的在开启活动的OnCreate方法,不过sunshine的就是在adapter中定义了一个getAccount方法。

public class MainActivity extends FragmentActivity {
    ...
    ...
    // Constants
    // The authority for the sync adapter‘s content provider
    public static final String AUTHORITY = "com.example.android.datasync.provider"
    // An account type, in the form of a domain name
    public static final String ACCOUNT_TYPE = "example.com";
    // The account name
    public static final String ACCOUNT = "dummyaccount";
    // Instance fields
    Account mAccount;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        // Create the dummy account
        mAccount = CreateSyncAccount(this);
        ...
    }
    ...
    /**
     * Create a new dummy account for the sync adapter
     *
     * @param context The application context
     */
    public static Account CreateSyncAccount(Context context) {
        // Create the account type and default account
        Account newAccount = new Account(
                ACCOUNT, ACCOUNT_TYPE);
        // Get an instance of the Android account manager
        AccountManager accountManager =
                (AccountManager) context.getSystemService(
                        ACCOUNT_SERVICE);
        /*
         * Add the account and account type, no password or user data
         * If successful, return the Account object, otherwise report an error.
         */
        if (accountManager.addAccountExplicitly(newAccount, null, null))) {
            /*
             * If you don‘t set android:syncable="true" in
             * in your <provider> element in the manifest,
             * then call context.setIsSyncable(account, AUTHORITY, 1)
             * here.
             */
        } else {
            /*
             * The account exists or some other error occurred. Log this, report it,
             * or handle it internally.
             */
        }
    }
    ...
}

(5)添加metadata文件

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

android:contentAuthority:内容提供器的权限

android:accountType:前面Authenticator定义的类型,也是第四步添加的账户类型

android:userVisible:同步账户类型的可见性

android:allowParallelSyncs 允许sync adapter的多个实例同时运行

android:isAlwaysSyncable: sync adapter可以在任何指定时间运行,设置为falst,调用requestSync方法.Sunshine设为

true,还是调用了这个requestSync方法啊,这不科学啊。

(6)定义adapter在Manifest中

添加权限:

网络权限,此外,应用需要请求读写sync adapter设置权限,这样可以在应用其他组件编程控制sync adapter。

还需要一个特殊的权限允许应用使用我们创建的Authenticator组件。

<manifest>

...

<uses-permission

android:name="android.permission.INTERNET"/>

<uses-permission

android:name="android.permission.READ_SYNC_SETTINGS"/>

<uses-permission

android:name="android.permission.WRITE_SYNC_SETTINGS"/>

<uses-permission

android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>

...

</manifest>

接着就是定义服务

     <service
                android:name="com.example.android.datasync.SyncService"
                android:exported="true"
                android:process=":sync">
            <intent-filter>
                <action android:name="android.content.SyncAdapter"/>
            </intent-filter>
            <meta-data android:name="android.content.SyncAdapter"
                    android:resource="@xml/syncadapter" />
        </service>

使用android.content.SyncAdapter action,系统发送去运行sync adapter。

然后android:process,告诉service在一个全局线程中执行(这个怎么知道这个线程),如果有多个sync adapter,可以分享

线程,减少开销。

Running a Sync Adapter

时间: 2024-11-09 03:07:16

从网络获取数据(2)使用SyncAdapter的相关文章

从网络获取数据,解析后输出。

我们要做的是从网络获取数据,在Activity中显示出来. 首先我们要导入gson包,它的作用是把Json字符串转换成相等的Java对象.把从网络获取数据和保存数据的方法写成类,方便以后调用. import java.io.BufferedReader; //从网络获取数据import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.HttpURLCon

网络获取数据的Xml的Pull解析

网络获取的XML的Pull解析 <?xml version="1.0" encoding="utf-8" ?> - <students> - <student xuehao="1233">  <name>张三</name>   <address>北京市昌平区</address> - <call>  <phone>010-37464567&l

从网络获取数据(1)从newThread到AsyncTask在到IntentService

概述 安卓不允许在UI线程中发送网络请求,因此必须新启动一个线程. 如果我们在活动中new Thread,这样就会有问题,这个线程会随着活动的生命周期结束而结束,如果活动的命比这个线程短,活动死掉了,线程还没有进行完,然后也不幸 挂了,这样,获取数据的任务就相当于是失败了,这肯定是不可以的啊.所以我们需要使用一个后台进程,比如AsyncTask,但是这个AsyncTask也要能快速完成(最多几秒), 不过他也有的一个问题就是,如果用户选择屏幕,后台的那个AsyncTask没有执行完,又会新建一个

iOS中从网络获取数据的几种方法的比较

IOS中获取网络数据一般有三种:1.NSURLCondition(已过时) 2.NSURLSession  3.三方库AFNetWorking NSURLSession 是苹果对NSULRCondition的替代品,NSURLSession比NSURLCondition多了 1.可配置的数据信息NSURLSessionConfiguration,NSURLSessionConfiguration使你可以设置你要请求的数据,通常的设置如缓存,也可以使用默认的配置信息defaultCongurati

AFN 获取数据,数据解析:JSON 介绍

AFN的介绍: 可以自动对服务器返回的数据进行解析,默认将服务器返回的数据当做 JSON 数据解析 是集XML解析,Json解析,网络图片下载,plist解析,数据流请求操作,上传,下载,缓存等网络众多功能于一身的强大的类库. 网络获取数据一直是手机软件的重中之重,如果处理的不好,会造成很差的用户体验.随着ASIHTTPRequest的停止更新,更换网络库是必然的事情,AFNetworking就是很好的替代品.而且都是轻量级,不要担心加入太多库会多软件性能有影响. AFN使用的注意事项:  (1

Android网络之数据解析----使用Google Gson解析Json数据

[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4063452.html 联系方式:[email protected] [正文] 文章回顾: Android网络之数据解析----SAX方式解析XML数据 一.Json数据的介绍                                                             

基于Android4.0ListView从网络获取图片文字资源显示

平时的一些Android学习视频中,他们都是基于Android的去使用ListView,我看到都是会在UI线程中去访问网络获取数据,但是这在Android4.0之后是行不通的. 首先我们来理一下思绪: 我们需要从网络上下载一份xml数据,里面包含了需要显示的文字和图片路径.所以我们首先需要的就是先去下载数据,下载数据完成之后再在Adapter中显示图片的时候去下载图片,然后显示出来.这是基本的思路.但是做着做着会发现一些问题,比如,我们如何能保证数据下载完全,才去绑定适配器和数据他们.然后假如我

volley源码解析(四)--CacheDispatcher从缓存中获取数据

从上一篇文章我们已经知道,现在要处理的问题就是CacheDispatcher和NetworkDispatcher怎么分别去缓存和网络获取数据的问题,这两个问题我分开来讲. 但是首先说明的是,这两个问题其实是有联系的,当CacheDispatcher获取不到缓存的时候,会将request放入网络请求队列,从而让NetworkDispatcher去处理它: 而当NetworkDispatcher获得数据以后,又会将数据缓存,下次CacheDispatcher就可以从缓存中获得数据了. 这篇文章,就让

获取数据源数据的实现---Architecting Android

UserRepository,这个接口,描述了Repository提供给用户的功能就是getUsers,getUser(ID).用户只管使用,其它细节无需理会. /** * Interface that represents a Repository for getting {@link User} related data. */ public interface UserRepository { /** * Get an {@link rx.Observable} which will em