Zip似乎不等待Observable发出数据

时间:2016-06-30 13:31:36

标签: android rx-java rx-android

我尝试使用volley运行2个并行请求以更新数据库(使用DBFlow)。只有在完成两个请求并保存其数据(FK)后,才能填充DB上的一个表。

鉴于以下示例,我希望两个扇区/员工fetch / insert并行运行,然后在插入完成后,保存合同。

/**
 * Update the sectors, employees and their contracts
 * @return An Observable to watch for the process to complete
 *
 *  sectorsFetch______sectorsInsert________contractsInsert
 *  employeesFetch____employeesInsert___/
 */
public static Observable<Void> updateEverything() {
    try {
        Log.d(TAG, "Starting update...");
        Observable<JSONArray> employeesFetch = Observable.from(ForumAPI.getInstance().getEmployees());
        Observable<List<Contract>> employeesInsert = employeesFetch.flatMap(new Func1<JSONArray, Observable<List<Contract>>>() {
            @Override
            public Observable<List<Contract>> call(JSONArray employees) {
                Log.d(TAG, "Employee list fetched");
                return saveEmployees(employees);
            }
        });

        Observable<JSONArray> sectorsFetch = Observable.from(ForumAPI.getInstance().getSectors());
        Observable<Void> sectorsInsert = sectorsFetch.flatMap(new Func1<JSONArray, Observable<Void>>() {
            @Override
            public Observable<Void> call(JSONArray sectors) {
                Log.d(TAG, "Sector list fetched");
                return saveSectors(sectors);
            }
        });

        return Observable.zip(sectorsInsert, employeesInsert, new Func2<Void, List<Contract>, Void>() {
            @Override
            public Void call(Void aVoid, List<Contract> contracts) {
                Log.d(TAG, "Sectors and employees saved. Saving contracts");
                return saveContracts(contracts);
            }
        });

    } catch (InterruptedException | ExecutionException e) {
        Log.e(TAG, e.getMessage());
        return Observable.error(e);
    }
}

注意:ForumAPI getEmployees / Sectors返回Future。

Bellow是保存方法。

/**
 * Parse and save an array of sectors
 * @param jsonSectors The array of sector to save
 * @return An Observable to watch for the process to complete.
 */
private static Observable<Void> saveSectors(JSONArray jsonSectors) {
    Log.d(TAG, "Transforming JSON sectors to object");
    List<Sector> sectList = new ArrayList<>();
    try {
        for (int i = 0; i < jsonSectors.length(); i++) {
            JSONObject jsonSect = jsonSectors.getJSONObject(i);
            Sector sect = Sector.build(jsonSect);
            sectList.add(sect);
        }
        Log.d(TAG, sectList.size() + " sectors fetched. Saving...");
        ForumDB.getDB().executeTransaction(
                FastStoreModelTransaction.insertBuilder(
                        FlowManager.getModelAdapter(Sector.class)
                ).addAll(sectList).build());

        Log.d(TAG, "Sector list saved");
    } catch (JSONException e) {
        Log.e(TAG, "Unable to parse sector list. " + e.getMessage());
        return Observable.error(e);
    }
    return Observable.empty();
}
/**
 * Parse and save an array of sectors
 * @param jsonSectors The array of sector to save
 * @return An Observable to watch for the process to complete.
 */
private static Observable<Void> saveSectors(JSONArray jsonSectors) {
    Log.d(TAG, "Transforming JSON sectors to object");
    List<Sector> sectList = new ArrayList<>();
    try {
        for (int i = 0; i < jsonSectors.length(); i++) {
            JSONObject jsonSect = jsonSectors.getJSONObject(i);
            Sector sect = Sector.build(jsonSect);
            sectList.add(sect);
        }
        Log.d(TAG, sectList.size() + " sectors fetched. Saving...");
        ForumDB.getDB().executeTransaction(
                FastStoreModelTransaction.insertBuilder(
                        FlowManager.getModelAdapter(Sector.class)
                ).addAll(sectList).build());

        Log.d(TAG, "Sector list saved");
    } catch (JSONException e) {
        Log.e(TAG, "Unable to parse sector list. " + e.getMessage());
        return Observable.error(e);
    }
    return Observable.empty();
}

/**
 * Parse and save an array of employees
 * @param jsonEmployees The array of employee to save
 * @return An Observable to watch for the process to complete.
 */
private static Observable<List<Contract>> saveEmployees(JSONArray jsonEmployees) {
    Log.d(TAG, "Transforming JSON employees to object");
    List<Person> empList = new ArrayList<>();
    List<Contract> contractList = new ArrayList<>();
    try {
        for (int i = 0; i < jsonEmployees.length(); i++) {
            JSONObject jsonEmp = jsonEmployees.getJSONObject(i);
            Person emp = Person.build(jsonEmp);
            empList.add(emp);
            JSONArray jsonContracts = jsonEmp.getJSONArray("sectors");
            for (int j = 0; j <  jsonContracts.length(); j++) {
                Contract contract = new Contract();
                contract.setSectorId(jsonContracts.getJSONObject(j).getInt("id"));
                contract.setPersonForumId(emp.getForumId());
                contractList.add(contract);
            }
        }
        Log.d(TAG, empList.size() + " employees fetched. Saving...");
        ForumDB.getDB().executeTransaction(
                FastStoreModelTransaction.insertBuilder(
                        FlowManager.getModelAdapter(Person.class)
                ).addAll(empList).build());
        Log.d(TAG, "Employee list saved");
    } catch (JSONException e) {
        Log.e(TAG, "Unable to parse employee list. " + e.getMessage());
        return Observable.error(e);
    }
    return Observable.just(contractList);
}

/**
 * Save a list of contract
 * @param contracts The list of contract to save
 * @return An Observable to watch for the process to complete.
 */
private static Void saveContracts(List contracts) {
    ForumDB.getDB().executeTransaction(
            FastStoreModelTransaction.insertBuilder(
                    FlowManager.getModelAdapter(Contract.class)
            ).addAll(contracts).build());
    Log.d(TAG, "Contract list saved");

    return null;
}

问题是,当从Android活动订阅该全局observable时,我的观察者onCompleted会在sectorFetch发出数据之后立即被调用(无论是扇区插入还是我的zip都被调用)。

Bellow是日志

D/com.xx.observable.DataUpdater: Starting update...
D/com.xx.helper.ForumAPI: Requesting employee list
D/com.xx.helper.ForumAPI: Request added to queue...
D/com.xx.helper.ForumAPI: Requesting sector list
D/com.xx.helper.ForumAPI: Request added to queue
D/com.xx.observable.DataUpdater: Sector list fetched
D/com.xx.observable.DataUpdater: Transforming JSON sectors to object
D/com.xx.observable.DataUpdater: 8 sectors fetched. Saving...
D/com.xx.observable.DataUpdater: Sector list saved
D/com.xx.activity.Startup: onCompleted reached

我无法找到问题所在。我的一个观察者是否正在发出一些东西,所以我的拉链会在它之前被调用吗?

1 个答案:

答案 0 :(得分:2)

1.1.6中的zip文档已更新,以描述此案例:

  

操作员按照指定的顺序订阅其来源,并在取消订阅其他来源时,如果其中一个来源比其他来源短,则热切地完成。因此,其他源可能永远无法运行完成(因此不会调用doOnCompleted()。如果源的长度完全相同,也可能发生这种情况;如果源A完成且B已被消耗,即将完成,操作员检测到A不会发送更多值,并且会立即取消订阅B.例如:zip(Arrays.asList(range(1, 5).doOnCompleted(action1), range(6, 5).doOnCompleted(action2)), (a) -> a) action1将被调用但action2将不会。 / p>

换句话说,请勿使用empty()进行压缩。您可以使用Observable.<Void>just(null)压缩并忽略该轨道。