Backport to Java 6...

Android Studio automatically folds lambda-style, so it won't get too out of hand.
Rx/Retrolambda
Bradlee Speice 2014-06-14 16:41:11 -04:00
parent e945ef51a7
commit 4269988b7c
7 changed files with 148 additions and 54 deletions

View File

@ -1,6 +1,6 @@
apply plugin: 'android' apply plugin: 'android'
apply plugin: 'android-apt' apply plugin: 'android-apt'
apply plugin: 'retrolambda' //apply plugin: 'retrolambda'
buildscript { buildscript {
repositories { repositories {
@ -8,7 +8,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.3' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.3'
classpath 'me.tatarka:gradle-retrolambda:1.3.2' //classpath 'me.tatarka:gradle-retrolambda:1.3.2'
} }
} }
@ -75,10 +75,14 @@ android {
lintOptions { lintOptions {
abortOnError false abortOnError false
} }
/*
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
*/
defaultConfig {} defaultConfig {}
productFlavors { productFlavors {
} }

View File

@ -21,6 +21,8 @@ import butterknife.InjectView;
import butterknife.OnClick; import butterknife.OnClick;
import rx.Subscription; import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
/** /**
* Created by bspeice on 5/20/14. * Created by bspeice on 5/20/14.
@ -59,8 +61,18 @@ public class BookItemHolder {
//TODO: Refactor //TODO: Refactor
subscription = bookDownloadManager.getDownloadEvents() subscription = bookDownloadManager.getDownloadEvents()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.filter((event) -> event.getB().getInitials().equals(b.getInitials())) .filter(new Func1<DLProgressEvent, Boolean>() {
.subscribe((event) -> displayProgress((int) event.toCircular())); @Override
public Boolean call(DLProgressEvent event) {
return event.getB().getInitials().equals(b.getInitials());
}
})
.subscribe(new Action1<DLProgressEvent>() {
@Override
public void call(DLProgressEvent event) {
BookItemHolder.this.displayProgress((int) event.toCircular());
}
});
} }
private void displayInstalled() { private void displayInstalled() {

View File

@ -15,15 +15,21 @@ import org.bspeice.minimalbible.MinimalBible;
import org.bspeice.minimalbible.R; import org.bspeice.minimalbible.R;
import org.bspeice.minimalbible.activities.BaseFragment; import org.bspeice.minimalbible.activities.BaseFragment;
import org.bspeice.minimalbible.activities.downloader.manager.RefreshManager; import org.bspeice.minimalbible.activities.downloader.manager.RefreshManager;
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookCategory; import org.crosswire.jsword.book.BookCategory;
import org.crosswire.jsword.book.BookComparators; import org.crosswire.jsword.book.BookComparators;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.InjectView; import butterknife.InjectView;
import rx.Observable; import rx.Observable;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.functions.Func2;
/** /**
* A placeholder fragment containing a simple view. * A placeholder fragment containing a simple view.
@ -119,22 +125,35 @@ public class BookListFragment extends BaseFragment {
// Listen for the books! // Listen for the books!
refreshManager.getAvailableModulesFlattened() refreshManager.getAvailableModulesFlattened()
.filter((book) -> book.getBookCategory() == .filter(new Func1<Book, Boolean>() {
BookCategory.fromString(getArguments().getString(ARG_BOOK_CATEGORY))) @Override
// Repack all the books public Boolean call(Book book) {
.toSortedList((book1, book2) -> return book.getBookCategory() ==
BookComparators.getInitialComparator().compare(book1, book2)) BookCategory.fromString(BookListFragment.this.getArguments()
.observeOn(AndroidSchedulers.mainThread()) .getString(ARG_BOOK_CATEGORY));
.subscribe((books) -> {
downloadsAvailable.setAdapter(new BookListAdapter(inflater, books));
if (getActivity() != null) {
// On a screen rotate, getActivity() will be null. But, the activity will
// already have been set up correctly, so we don't need to worry about it.
// If not null, we need to set it up now.
setInsets(getActivity(), downloadsAvailable);
} }
if (refreshDialog != null) { })
refreshDialog.cancel(); // Repack all the books
.toSortedList(new Func2<Book, Book, Integer>() {
@Override
public Integer call(Book book1, Book book2) {
return BookComparators.getInitialComparator().compare(book1, book2);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<List<Book>>() {
@Override
public void call(List<Book> books) {
downloadsAvailable.setAdapter(new BookListAdapter(inflater, books));
if (BookListFragment.this.getActivity() != null) {
// On a screen rotate, getActivity() will be null. But, the activity will
// already have been set up correctly, so we don't need to worry about it.
// If not null, we need to set it up now.
setInsets(BookListFragment.this.getActivity(), downloadsAvailable);
}
if (refreshDialog != null) {
refreshDialog.cancel();
}
} }
}); });
} }

View File

@ -5,9 +5,11 @@ import android.util.Log;
import org.bspeice.minimalbible.MinimalBible; import org.bspeice.minimalbible.MinimalBible;
import org.crosswire.jsword.book.Book; import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.install.InstallException; import org.crosswire.jsword.book.install.InstallException;
import org.crosswire.jsword.book.install.Installer;
import javax.inject.Inject; import javax.inject.Inject;
import rx.functions.Action1;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
/** /**
@ -33,14 +35,18 @@ public class BookDownloadThread {
// First, look up where the Book came from // First, look up where the Book came from
refreshManager.installerFromBook(b) refreshManager.installerFromBook(b)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.subscribe((installer) -> { .subscribe(new Action1<Installer>() {
try { @Override
installer.install(b); public void call(Installer installer) {
} catch (InstallException e) { try {
Log.d(TAG, e.getMessage()); installer.install(b);
} } catch (InstallException e) {
Log.d(TAG, e.getMessage());
}
bookDownloadManager.getDownloadEvents().onNext(new DLProgressEvent(DLProgressEvent.PROGRESS_BEGINNING, b)); bookDownloadManager.getDownloadEvents()
.onNext(new DLProgressEvent(DLProgressEvent.PROGRESS_BEGINNING, b));
}
}); });
} }

View File

@ -66,13 +66,16 @@ public class InstalledManager implements BooksListener {
if (installedBooks == null) { if (installedBooks == null) {
initialize(); initialize();
} }
try { // Not sure why we need to call this multiple times, but...
// This worked in the past, but isn't now... while (Books.installed().getBooks().contains(b)) {
// installedBooks.remove(b); try {
Book realBook = installedBooks.getBook(b.getInitials()); // This worked in the past, but isn't now...
b.getDriver().delete(realBook); // installedBooks.remove(b);
} catch (BookException e) { Book realBook = installedBooks.getBook(b.getInitials());
Log.e("InstalledManager", "Unable to remove book (already uninstalled?): " + e.getLocalizedMessage()); b.getDriver().delete(realBook);
} catch (BookException e) {
Log.e("InstalledManager", "Unable to remove book (already uninstalled?): " + e.getLocalizedMessage());
}
} }
} }
} }

View File

@ -14,6 +14,10 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import rx.Observable; import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
/** /**
@ -44,16 +48,30 @@ public class RefreshManager {
private void refreshModules() { private void refreshModules() {
if (availableModules == null) { if (availableModules == null) {
availableModules = Observable.from(downloadManager.getInstallers().values()) availableModules = Observable.from(downloadManager.getInstallers().values())
.map(installer -> { .map(new Func1<Installer, Map<Installer, List<Book>>>() {
Map<Installer, List<Book>> map = new HashMap<Installer, List<Book>>(); @Override
map.put(installer, installer.getBooks()); public Map<Installer, List<Book>> call(Installer installer) {
return map; Map<Installer, List<Book>> map = new HashMap<Installer, List<Book>>();
map.put(installer, installer.getBooks());
return map;
}
}).subscribeOn(Schedulers.io()) }).subscribeOn(Schedulers.io())
.cache(); .cache();
// Set refresh complete when it is. // Set refresh complete when it is.
availableModules.observeOn(Schedulers.io()) availableModules.observeOn(Schedulers.io())
.subscribe((onNext) -> {}, (onError) -> {}, () -> refreshComplete.set(true)); .subscribe(new Action1<Map<Installer, List<Book>>>() {
@Override
public void call(Map<Installer, List<Book>> onNext) {}
}, new Action1<Throwable>() {
@Override
public void call(Throwable onError) {}
}, new Action0() {
@Override
public void call() {
refreshComplete.set(true);
}
});
} }
} }
@ -64,9 +82,19 @@ public class RefreshManager {
public Observable<Book> getAvailableModulesFlattened() { public Observable<Book> getAvailableModulesFlattened() {
return availableModules return availableModules
// First flatten the Map to its lists // First flatten the Map to its lists
.flatMap((books) -> Observable.from(books.values())) .flatMap(new Func1<Map<Installer, List<Book>>, Observable<? extends List<Book>>>() {
@Override
public Observable<? extends List<Book>> call(Map<Installer, List<Book>> books) {
return Observable.from(books.values());
}
})
// Then flatten the lists // Then flatten the lists
.flatMap(Observable::from); .flatMap(new Func1<List<Book>, Observable<? extends Book>>() {
@Override
public Observable<? extends Book> call(List<Book> t1) {
return Observable.from(t1);
}
});
} }
/** /**
@ -74,12 +102,16 @@ public class RefreshManager {
* @return The cached book list, or null * @return The cached book list, or null
*/ */
public List<Book> getBookList() { public List<Book> getBookList() {
List<Book> availableList = new ArrayList<>(); List<Book> availableList = new ArrayList<Book>();
availableModules.reduce(availableList, (books, installerListMap) -> { availableModules.reduce(availableList,
for (List<Book> l : installerListMap.values()) { new Func2<List<Book>, Map<Installer, List<Book>>, List<Book>>() {
books.addAll(l); @Override
public List<Book> call(List<Book> books, Map<Installer, List<Book>> installerListMap) {
for (List<Book> l : installerListMap.values()) {
books.addAll(l);
}
return books;
} }
return books;
}); });
return availableList; return availableList;
} }
@ -89,17 +121,25 @@ public class RefreshManager {
* @param b The book to search for * @param b The book to search for
* @return The Installer that should be used for this book. * @return The Installer that should be used for this book.
*/ */
public Observable<Installer> installerFromBook(Book b) { public Observable<Installer> installerFromBook(final Book b) {
return availableModules.filter(installerListMap -> { return availableModules.filter(new Func1<Map<Installer, List<Book>>, Boolean>() {
for (List<Book> element : installerListMap.values()) { @Override
if (element.contains(b)) { public Boolean call(Map<Installer, List<Book>> installerListMap) {
return true; for (List<Book> element : installerListMap.values()) {
if (element.contains(b)) {
return true;
}
} }
return false;
} }
return false;
}) })
.first() .first()
.map(element -> element.entrySet().iterator().next().getKey()); .map(new Func1<Map<Installer, List<Book>>, Installer>() {
@Override
public Installer call(Map<Installer, List<Book>> element) {
return element.entrySet().iterator().next().getKey();
}
});
} }
public boolean isRefreshComplete() { public boolean isRefreshComplete() {

View File

@ -67,7 +67,12 @@ public class DownloadActivityTest extends InstrumentationTestCase {
final Book testBook = i.getBooks().get(0); final Book testBook = i.getBooks().get(0);
bdm.installBook(testBook); bdm.installBook(testBook);
await().atMost(30, TimeUnit.SECONDS) await().atMost(30, TimeUnit.SECONDS)
.until(() -> Books.installed().getBooks().contains(testBook)); .until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return Books.installed().getBooks().contains(testBook);
}
});
// Validate that we can actually do something with the book // Validate that we can actually do something with the book
// TODO: Validate that the book exists on the filesystem too // TODO: Validate that the book exists on the filesystem too
@ -83,7 +88,12 @@ public class DownloadActivityTest extends InstrumentationTestCase {
// TODO: Validate that the book is off the filesystem // TODO: Validate that the book is off the filesystem
im.removeBook(testBook); im.removeBook(testBook);
await().atMost(10, TimeUnit.SECONDS) await().atMost(10, TimeUnit.SECONDS)
.until(() -> !Books.installed().getBooks().contains(testBook)); .until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return !Books.installed().getBooks().contains(testBook);
}
});
} }
} }