一些初步信息:
我必须为 Android 库创建一个 API。此 API 必须处理通用数据的基本 CRUD(查找、查找全部、插入、更新、删除)操作。然后使用此库的其他应用程序可以将此 API 与他们想要的任何数据/对象一起使用。但是,这些数据存储在后端服务器中,由在不同设备(基本上是 BaaS)中拥有相同应用程序的所有用户存储和使用。这些应用程序应该能够在没有互联网连接的情况下工作。因此,查看了 Google I/O 制作的有关如何在 android 中设计 REST 客户端的视频并进行了关注。
因此现在:
- 在插入/更新/删除数据时,API 使用本地 Content Provider 并为数据设置特定标志。
- 我有一个 SyncAdapter 正在运行,它会在每次运行时检查 sqlite 中的所有数据。
- 它检查数据具有的标志(如果它已被插入、更新或删除),并调用 REST API 以将其与服务器同步
但是,我希望应用程序能够将回调传递给这个 sincronization。基本上,我想要的是,当应用程序从我的 API 调用“插入”方法时,它应该向它传递一个回调。这个回调应该做两件事:
- 定义在插入失败的情况下要做什么
- 定义在插入成功的情况下要做什么。
这是我想做的一个例子:
GenericData data = new GenericData();
//Initialize data
API.insert(GenericData.class, data, new CallBack<GenericData>(){
@Override
public void onSuccess(GenericData insertedData){
//Data inserted and syncronized successfully
}
@Override
public void onFailure(){
//Data failed to be inserted an/or sincronized
}
});
作为匿名类,此回调将从应用程序中的 AsyncTask 调用。我想要做的是,callBack.onSuccess(data)
如果同步成功完成,callBack.onFailure()
则从 SyncAdapter 调用,如果同步失败,则从 SyncAdapter 调用。
因此,回调类看起来像这样:
//Concrete empty methods are set so it's not necessary to implement all these methods
public abstract class Callback<T>{
public void onSuccess(T insertedData){}
public void onFailure(){}
}
我想到的是:
创建一个将处理“插入”回调的 BroadcastReceiver。该接收器将监听特定的 Intent。
当 SyncAdapter 同步完一行插入的数据后,它会创建一个特定的 Intent 并广播它。作为附加数据,此 Intent 将包含已处理行的 id 和同步状态(如果成功或失败)。当接收器被调用时,它会从意图中获取行的 id,获取该 id 的特定回调,并根据同步调用的状态callBack.onSuccess(data)
或callBack.onFailure()
.
我的问题来自确定要调用哪个回调。每个“API.insert(..)”方法都传递一个Callback
子类,它是一个匿名类。我不知道如何序列化它,或者用行的特定 id “存储”它。如果可以以某种方式对其进行序列化,那么 BroadcastReceiver 就会执行Callback callback = lookup(id)
并获取与该 id 关联的回调。但是我不知道这是否可能,因为我尝试序列化回调并且它不起作用。我认为问题在于 Activity 本身(从中调用 insert 方法)本身不可序列化,因此回调也无法序列化。
我考虑过可能不使用匿名类,而是使用命名的回调类。但是话又说回来,如果我允许Callback
在方法中传递一个对象,那么您仍然可以将一个匿名类传递给它。因此,任何完全做到这一点的应用程序都会出错。因此,即使回调作为匿名类传递,它们也应该可以工作,除非上述情况有替代方案。
另外,如果它是 Activity 中的匿名类,我会喜欢它,因此回调可以使用 Activity 中定义的变量。例如,要在一行中插入 2 个不同的对象(回调将使用OtherData data
活动中定义的对象)。如果它可以以某种方式完成,那么如果 Activity 仍然启动并运行,则回调应该使用相同的 Activity 对象。但是如果 Activity 已关闭,则以某种方式对其进行序列化,因此当稍后调用回调时,它会使用 Activity 中的变量/数据,然后再进行 cloaed/destroyed
有任何想法吗?
PS:另外,就像我说的回调和数据应该是通用的,所以调用回调的方法应该支持任何可能的类型。我想这无论如何都不是问题,例如使用通配符Callback<?> callback = lookupCallback(id)
。
更新:
好吧,我想我有一个解决方案,也许。
然后我遇到的主要问题是,我需要 Callback 是一个匿名类并同时可序列化,这是不可能的。如果它是可序列化的,但不是一个令人讨厌的类,我不能使用调用它的 Activity 中的变量/属性(这是处理这些回调所必需的)。但是,如果它是一个匿名类,但不可序列化,那么我无法序列化回调,以便在 SyncAdapter 完成同步时对其进行反序列化和调用。
所以我想也许我可以这样做,包括两全其美:
这将是 CallBack 类:
//Concrete empty methods are set so it's not necessary to implement all these methods
public abstract class Callback<T> implements Serializable{
public void onSuccess(T insertedData){}
public void onFailure(){}
}
每个回调都应该是一个命名类(外部类或静态内部类等),并在其创建者中传递一个活动。然后,您可以从您想要的活动中获取您想要的任何字段。
我认为通过示例可以更好地显示这一点,因此我将尝试包括一个:“我创建了一个用户和一个包含该用户的地址。我想插入用户,然后在我知道该用户已插入时插入地址” .
在这种情况下,我想我会有这样的回调:
public class UserInsertedCallback extends Callback<User> implements Serializable{
//Here goes serialId
private Address address;
public UserInsertedCallback(UserActivity activity){
address = activity.getAddress();
}
@Override
public void onSuccess(User insertedUser){
//This is another callback we may want to use
Callback<Address> callback = createCallback();
//I create Foreign Key in Address referencing the user
address.setUserId(insertedUser.getId());
API.insert(Address.class, address, callback);
}
}
现在这将是活动:
public class UserActivity extends Activity{
private Address address;
....
public Address getAddress(){return address;}
private class TestTask extends AsyncTask<Void,Void,Void>{
@Override
protected Void doInBackground(Void... void){
User user = ... //create user
address = ... //create address
API.insert(User.class, user, new UserInsertedCallback(UserActivity.this));
}
}
}
我的 API 方法将序列化 UserInsertedCallback 并将其插入到可以轻松检索的数据库表中。这里没有问题,假设 Address 是可序列化的。即使不是,开发人员只需在 UserInsertedCallback 中包含可序列化的对象/原语,并可以在onSuccess()
. 随着回调的序列化,只要 SyncAdapter 成功插入用户,它就可以从数据库中获取序列化的回调,反序列化它,并从中调用“onSuccess(insertedUser)”。
如果只需要 Address 对象,那么 UserInsertedCallback 的构造函数可以取而代之。但也许开发人员还需要 Activity 中的其他东西,所以他们也有能力传递 Activity。
当然,我敢肯定这并不那么容易,但我很快就会尝试看看这是否可行。我仍然不知道如何防止人们将回调作为匿名类传递