Skip to content

Commit 5a4b661

Browse files
SUPERCILEXmorganchen12
authored andcommitted
Support for joins (#276)
* Update FirebaseArray to support joined data * Update FirebaseRecyclerAdapter to support joined data * Refactor setOnChangedListener * Update FirebaseListAdapter to support joined data * Refactor setOnChangedListener * Update README.md * Handle key not found at dataRef * Handle onCancelled * Handle onCancelled * Handle onCancelled * Update FirebaseArray.java * Update FirebaseArray.java * Update FirebaseListAdapter.java * Update FirebaseRecyclerAdapter.java * Update FirebaseArray.java * Update FirebaseListAdapter.java * Log a warning instead of exception if key is missing * Extract indexed array into separate class * Fix formatting * Fix formatting * Fix formatting * Refactor adapters * Fix IndexOutOfBoundsException and list item not being removed * Make getIndexForKey available to implementations * Code cleanup and optimizations * Add copyright * Update FirebaseRecyclerAdapter.java * Re-architected IndexFirebaseArray * Fix Intellij's annoying obsession with putting interfaces at the bottom of a class * Update IndexFirebaseArray.java * Fix "key not found" exception when a key from the key ref has a null value in the data ref location. * Extract FirebaseIndexListAdapter * Cleanup for final review * Cleanup for final review * Update FirebaseArray.java * Refactoring of IndexFirebaseArray * Update README.md * Improved cleanup speed. * Renames * Handle case when dataSnapshot value is null * Update IndexFirebaseArray.java * Renamed to FirebaseIndexArray * Cleanup * Fixed condition in isMatch method * Tweaks * Add back supers * Update FirebaseArray.java * Make life compile * Update FirebaseArray.java * Fix package statements moving around * Cleanup * Add clearer error logging * Updated documentation * Even clearer * Relax query requirements and remove unnecessary constructors. * fix typo * tests part 1 * test travis should fail * tests part 2 * Remove unnecessary constructor * Fix typo * Fix nits
1 parent cce75a8 commit 5a4b661

14 files changed

+860
-284
lines changed

database/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,22 @@ recycler.setAdapter(mAdapter);
269269
```
270270

271271
Like before, we get a custom RecyclerView populated with data from Firebase by setting the properties to the correct fields.
272+
273+
## Using FirebaseUI with indexed data
274+
If your data is [properly indexed](https://firebase.google.com/docs/database/android/structure-data#best_practices_for_data_structure), change your adapter initalization like so:
275+
276+
For a `RecyclerView`, use `FirebaseIndexRecyclerAdapter` instead of `FirebaseRecyclerAdapter`:
277+
```java
278+
new FirebaseIndexRecyclerAdapter<Chat, ChatHolder>(Chat.class,
279+
android.R.layout.two_line_list_item,
280+
ChatHolder.class,
281+
keyRef, // The Firebase location containing the list of keys to be found in dataRef.
282+
dataRef) //The Firebase location to watch for data changes. Each key key found at keyRef's location represents a list item in the RecyclerView.
283+
```
284+
285+
And for a `ListView`, use `FirebaseIndexListAdapter`;
286+
```java
287+
new FirebaseIndexListAdapter<Chat>(this, Chat.class, android.R.layout.two_line_list_item, keyRef, dataRef)
288+
```
289+
290+
`keyRef` is the location of your keys, and `dataRef` is the location of your data.

database/src/androidTest/java/com/firebase/ui/database/ApplicationTest.java

Lines changed: 0 additions & 45 deletions
This file was deleted.

database/src/androidTest/java/com/firebase/ui/database/FirebaseArrayOfObjectsTest.java

Lines changed: 30 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -18,79 +18,48 @@
1818
import android.test.InstrumentationTestCase;
1919
import android.test.suitebuilder.annotation.SmallTest;
2020

21+
import com.firebase.ui.database.utils.Bean;
2122
import com.google.firebase.FirebaseApp;
22-
import com.google.firebase.database.DatabaseError;
2323
import com.google.firebase.database.DatabaseReference;
2424
import com.google.firebase.database.FirebaseDatabase;
25-
import com.google.firebase.database.Query;
26-
27-
import junit.framework.AssertionFailedError;
2825

2926
import org.junit.After;
3027
import org.junit.Before;
3128
import org.junit.Test;
3229
import org.junit.runner.RunWith;
3330

3431
import java.util.concurrent.Callable;
35-
import java.util.concurrent.TimeUnit;
32+
33+
import static com.firebase.ui.database.TestUtils.getAppInstance;
34+
import static com.firebase.ui.database.TestUtils.getBean;
35+
import static com.firebase.ui.database.TestUtils.runAndWaitUntil;
3636

3737
@RunWith(AndroidJUnit4.class)
3838
@SmallTest
3939
public class FirebaseArrayOfObjectsTest extends InstrumentationTestCase {
40-
public static class Bean {
41-
int number;
42-
String text;
43-
boolean bool;
44-
45-
public Bean() {
46-
// necessary for Jackson
47-
}
48-
49-
public Bean(int number, String text, boolean bool) {
50-
this.number = number;
51-
this.text = text;
52-
this.bool = bool;
53-
}
54-
public Bean(int index) {
55-
this(index, "Text "+index, index % 2 == 0);
56-
}
57-
58-
public int getNumber() {
59-
return number;
60-
}
61-
62-
public String getText() {
63-
return text;
64-
}
65-
66-
public boolean isBool() {
67-
return bool;
68-
}
69-
}
70-
7140
private DatabaseReference mRef;
7241
private FirebaseArray mArray;
7342

7443
@Before
7544
public void setUp() throws Exception {
76-
FirebaseApp app = ApplicationTest.getAppInstance(getInstrumentation().getContext());
45+
FirebaseApp app = getAppInstance(getInstrumentation().getContext());
7746
mRef = FirebaseDatabase.getInstance(app).getReference()
7847
.child("firebasearray").child("objects");
7948
mArray = new FirebaseArray(mRef);
8049
mRef.removeValue();
81-
runAndWaitUntil(mArray, mRef, new Runnable() {
82-
@Override
83-
public void run() {
84-
for (int i = 1; i <= 3; i++) {
85-
mRef.push().setValue(new Bean(i, "Text " + i, i % 2 == 0 ? true : false), i);
50+
runAndWaitUntil(mArray, new Runnable() {
51+
@Override
52+
public void run() {
53+
for (int i = 1; i <= 3; i++) {
54+
mRef.push().setValue(new Bean(i, "Text " + i, i % 2 == 0), i);
55+
}
56+
}
57+
}, new Callable<Boolean>() {
58+
@Override
59+
public Boolean call() throws Exception {
60+
return mArray.getCount() == 3;
61+
}
8662
}
87-
}
88-
}, new Callable<Boolean>() {
89-
@Override
90-
public Boolean call() throws Exception {
91-
return mArray.getCount() == 3;
92-
}
93-
}
9463
);
9564
}
9665

@@ -113,7 +82,7 @@ public void testSize() throws Exception {
11382
@Test
11483
public void testPushIncreasesSize() throws Exception {
11584
assertEquals(3, mArray.getCount());
116-
runAndWaitUntil(mArray, mRef, new Runnable() {
85+
runAndWaitUntil(mArray, new Runnable() {
11786
public void run() {
11887
mRef.push().setValue(new Bean(4));
11988
}
@@ -124,9 +93,10 @@ public Boolean call() throws Exception {
12493
}
12594
});
12695
}
96+
12797
@Test
12898
public void testPushAppends() throws Exception {
129-
runAndWaitUntil(mArray, mRef, new Runnable() {
99+
runAndWaitUntil(mArray, new Runnable() {
130100
public void run() {
131101
mRef.push().setValue(new Bean(4), 4);
132102
}
@@ -140,71 +110,32 @@ public Boolean call() throws Exception {
140110

141111
@Test
142112
public void testAddValueWithPriority() throws Exception {
143-
runAndWaitUntil(mArray, mRef, new Runnable() {
113+
runAndWaitUntil(mArray, new Runnable() {
144114
public void run() {
145115
mRef.push().setValue(new Bean(4), 0.5);
146116
}
147117
}, new Callable<Boolean>() {
148118
public Boolean call() throws Exception {
149-
return mArray.getItem(3).getValue(Bean.class).getNumber() == 3 && mArray.getItem(0).getValue(Bean.class).getNumber() == 4;
119+
return mArray.getItem(3).getValue(Bean.class).getNumber() == 3 && mArray.getItem(0)
120+
.getValue(Bean.class)
121+
.getNumber() == 4;
150122
}
151123
});
152124
}
153125

154126
@Test
155127
public void testChangePriorities() throws Exception {
156-
runAndWaitUntil(mArray, mRef, new Runnable() {
128+
runAndWaitUntil(mArray, new Runnable() {
157129
public void run() {
158130
mArray.getItem(2).getRef().setPriority(0.5);
159131
}
160132
}, new Callable<Boolean>() {
161133
public Boolean call() throws Exception {
162-
return getBean(mArray, 0).getNumber() == 3 && getBean(mArray, 1).getNumber() == 1 && getBean(mArray, 2).getNumber() == 2;
134+
return getBean(mArray, 0).getNumber() == 3
135+
&& getBean(mArray, 1).getNumber() == 1
136+
&& getBean(mArray, 2).getNumber() == 2;
163137
//return isValuesEqual(mArray, new int[]{3, 1, 2});
164138
}
165139
});
166140
}
167-
168-
private static boolean isValuesEqual(FirebaseArray array, int[] expected) {
169-
if (array.getCount() != expected.length) return false;
170-
for (int i=0; i < array.getCount(); i++) {
171-
if (!array.getItem(i).getValue(Integer.class).equals(expected[i])) {
172-
return false;
173-
}
174-
}
175-
return true;
176-
}
177-
178-
private Bean getBean(FirebaseArray array, int index) {
179-
return array.getItem(index).getValue(Bean.class);
180-
}
181-
182-
public static void runAndWaitUntil(final FirebaseArray array, Query ref, Runnable task, Callable<Boolean> done) throws InterruptedException {
183-
final java.util.concurrent.Semaphore semaphore = new java.util.concurrent.Semaphore(0);
184-
array.setOnChangedListener(new FirebaseArray.OnChangedListener() {
185-
public void onChanged(EventType type, int index, int oldIndex) {
186-
semaphore.release();
187-
}
188-
189-
@Override
190-
public void onCancelled(DatabaseError databaseError) {
191-
throw new IllegalStateException(databaseError.toException());
192-
}
193-
});
194-
task.run();
195-
boolean isDone = false;
196-
long startedAt = System.currentTimeMillis();
197-
while (!isDone && System.currentTimeMillis() - startedAt < 5000) {
198-
semaphore.tryAcquire(1, TimeUnit.SECONDS);
199-
try {
200-
isDone = done.call();
201-
} catch (Exception e) {
202-
e.printStackTrace();
203-
// and we're not done
204-
}
205-
}
206-
if (!isDone) {
207-
throw new AssertionFailedError();
208-
}
209-
array.setOnChangedListener(null);
210-
}}
141+
}

0 commit comments

Comments
 (0)