Load more mangas on scroll
This commit is contained in:
		
							parent
							
								
									2aaaad7a24
								
							
						
					
					
						commit
						e7116bdcab
					
				| @ -102,6 +102,11 @@ public class DatabaseHelper implements MangaManager, ChapterManager { | |||||||
|         return mMangaManager.getManga(id); |         return mMangaManager.getManga(id); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public Manga getMangaBlock(String url) { | ||||||
|  |         return mMangaManager.getMangaBlock(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public Observable<PutResult> insertManga(Manga manga) { |     public Observable<PutResult> insertManga(Manga manga) { | ||||||
|         return mMangaManager.insertManga(manga); |         return mMangaManager.insertManga(manga); | ||||||
| @ -112,6 +117,11 @@ public class DatabaseHelper implements MangaManager, ChapterManager { | |||||||
|         return mMangaManager.insertMangas(mangas); |         return mMangaManager.insertMangas(mangas); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public PutResult insertMangaBlock(Manga manga) { | ||||||
|  |         return mMangaManager.insertMangaBlock(manga); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public Observable<DeleteResult> deleteManga(Manga manga) { |     public Observable<DeleteResult> deleteManga(Manga manga) { | ||||||
|         return mMangaManager.deleteManga(manga); |         return mMangaManager.deleteManga(manga); | ||||||
|  | |||||||
| @ -20,10 +20,14 @@ public interface MangaManager { | |||||||
| 
 | 
 | ||||||
|     Observable<List<Manga>> getManga(int id); |     Observable<List<Manga>> getManga(int id); | ||||||
| 
 | 
 | ||||||
|  |     Manga getMangaBlock(String url); | ||||||
|  | 
 | ||||||
|     Observable<PutResult> insertManga(Manga manga); |     Observable<PutResult> insertManga(Manga manga); | ||||||
| 
 | 
 | ||||||
|     Observable<PutResults<Manga>> insertMangas(List<Manga> mangas); |     Observable<PutResults<Manga>> insertMangas(List<Manga> mangas); | ||||||
| 
 | 
 | ||||||
|  |     PutResult insertMangaBlock(Manga manga); | ||||||
|  | 
 | ||||||
|     Observable<DeleteResult> deleteManga(Manga manga); |     Observable<DeleteResult> deleteManga(Manga manga); | ||||||
| 
 | 
 | ||||||
|     Observable<DeleteResults<Manga>> deleteMangas(List<Manga> mangas); |     Observable<DeleteResults<Manga>> deleteMangas(List<Manga> mangas); | ||||||
|  | |||||||
| @ -70,6 +70,24 @@ public class MangaManagerImpl extends BaseManager implements MangaManager { | |||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public Manga getMangaBlock(String url) { | ||||||
|  |         List<Manga> result = db.get() | ||||||
|  |                 .listOfObjects(Manga.class) | ||||||
|  |                 .withQuery(Query.builder() | ||||||
|  |                         .table(MangasTable.TABLE) | ||||||
|  |                         .where(MangasTable.COLUMN_URL + "=?") | ||||||
|  |                         .whereArgs(url) | ||||||
|  |                         .build()) | ||||||
|  |                 .prepare() | ||||||
|  |                 .executeAsBlocking(); | ||||||
|  | 
 | ||||||
|  |         if (result.isEmpty()) | ||||||
|  |             return null; | ||||||
|  | 
 | ||||||
|  |         return result.get(0); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public Observable<PutResult> insertManga(Manga manga) { |     public Observable<PutResult> insertManga(Manga manga) { | ||||||
|         return db.put() |         return db.put() | ||||||
|                 .object(manga) |                 .object(manga) | ||||||
| @ -84,6 +102,13 @@ public class MangaManagerImpl extends BaseManager implements MangaManager { | |||||||
|                 .createObservable(); |                 .createObservable(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public PutResult insertMangaBlock(Manga manga) { | ||||||
|  |         return db.put() | ||||||
|  |                 .object(manga) | ||||||
|  |                 .prepare() | ||||||
|  |                 .executeAsBlocking(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public Observable<DeleteResult> deleteManga(Manga manga) { |     public Observable<DeleteResult> deleteManga(Manga manga) { | ||||||
|         return db.delete() |         return db.delete() | ||||||
|                 .object(manga) |                 .object(manga) | ||||||
|  | |||||||
| @ -83,6 +83,8 @@ public class MangasTable { | |||||||
|                 + COLUMN_INITIALIZED + " BOOLEAN NOT NULL, " |                 + COLUMN_INITIALIZED + " BOOLEAN NOT NULL, " | ||||||
|                 + COLUMN_VIEWER + " INTEGER NOT NULL, " |                 + COLUMN_VIEWER + " INTEGER NOT NULL, " | ||||||
|                 + COLUMN_CHAPTER_ORDER + " INTEGER NOT NULL" |                 + COLUMN_CHAPTER_ORDER + " INTEGER NOT NULL" | ||||||
|                 + ");"; |                 + ");" | ||||||
|  |                 + "CREATE INDEX " + TABLE + "_" + COLUMN_URL + "_index ON " + TABLE + "(" + COLUMN_URL + ");"; | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -12,11 +12,12 @@ import eu.kanade.mangafeed.sources.Source; | |||||||
| import eu.kanade.mangafeed.ui.adapter.CatalogueListHolder; | import eu.kanade.mangafeed.ui.adapter.CatalogueListHolder; | ||||||
| import eu.kanade.mangafeed.view.CatalogueListView; | import eu.kanade.mangafeed.view.CatalogueListView; | ||||||
| import rx.Observable; | import rx.Observable; | ||||||
|  | import rx.Subscription; | ||||||
| import rx.android.schedulers.AndroidSchedulers; | import rx.android.schedulers.AndroidSchedulers; | ||||||
| import rx.schedulers.Schedulers; | import rx.schedulers.Schedulers; | ||||||
| import uk.co.ribot.easyadapter.EasyAdapter; | import uk.co.ribot.easyadapter.EasyAdapter; | ||||||
| 
 | 
 | ||||||
| public class CatalogueListPresenter { | public class CatalogueListPresenter extends BasePresenter { | ||||||
| 
 | 
 | ||||||
|     CatalogueListView view; |     CatalogueListView view; | ||||||
|     EasyAdapter<Manga> adapter; |     EasyAdapter<Manga> adapter; | ||||||
| @ -25,6 +26,8 @@ public class CatalogueListPresenter { | |||||||
|     @Inject SourceManager sourceManager; |     @Inject SourceManager sourceManager; | ||||||
|     @Inject DatabaseHelper db; |     @Inject DatabaseHelper db; | ||||||
| 
 | 
 | ||||||
|  |     private Subscription mMangaFetchSubscription; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     public CatalogueListPresenter(CatalogueListView view) { |     public CatalogueListPresenter(CatalogueListView view) { | ||||||
|         this.view = view; |         this.view = view; | ||||||
| @ -38,24 +41,32 @@ public class CatalogueListPresenter { | |||||||
| 
 | 
 | ||||||
|         adapter = new EasyAdapter<>(view.getActivity(), CatalogueListHolder.class); |         adapter = new EasyAdapter<>(view.getActivity(), CatalogueListHolder.class); | ||||||
|         view.setAdapter(adapter); |         view.setAdapter(adapter); | ||||||
|  |         view.setScrollListener(); | ||||||
| 
 | 
 | ||||||
|         getMangasFromSource(); |         getMangasFromSource(1); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void getMangasFromSource() { |     public void getMangasFromSource(int page) { | ||||||
|         selectedSource.pullPopularMangasFromNetwork(1) |         subscriptions.remove(mMangaFetchSubscription); | ||||||
|  | 
 | ||||||
|  |         mMangaFetchSubscription = selectedSource.pullPopularMangasFromNetwork(page) | ||||||
|                 .subscribeOn(Schedulers.io()) |                 .subscribeOn(Schedulers.io()) | ||||||
|                 .flatMap(Observable::from) |  | ||||||
|                 .flatMap(networkManga -> db.getManga(networkManga.url) |  | ||||||
|                         .flatMap(result -> { |  | ||||||
|                             if (result.size() == 0) { |  | ||||||
|                                 return db.insertManga(networkManga) |  | ||||||
|                                         .flatMap(i -> Observable.just(networkManga)); |  | ||||||
|                             } |  | ||||||
|                             return Observable.just(networkManga); |  | ||||||
|                         })) |  | ||||||
|                 .observeOn(AndroidSchedulers.mainThread()) |                 .observeOn(AndroidSchedulers.mainThread()) | ||||||
|                 .subscribe(adapter::addItem); |                 .flatMap(Observable::from) | ||||||
|  |                 .map(this::networkToLocalManga) | ||||||
|  |                 .toList() | ||||||
|  |                 .subscribe(adapter::addItems); | ||||||
|  | 
 | ||||||
|  |         subscriptions.add(mMangaFetchSubscription); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Manga networkToLocalManga(Manga networkManga) { | ||||||
|  |         Manga localManga = db.getMangaBlock(networkManga.url); | ||||||
|  |         if (localManga == null) { | ||||||
|  |             db.insertMangaBlock(networkManga); | ||||||
|  |             localManga = db.getMangaBlock(networkManga.url); | ||||||
|  |         } | ||||||
|  |         return localManga; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ import eu.kanade.mangafeed.R; | |||||||
| import eu.kanade.mangafeed.presenter.CatalogueListPresenter; | import eu.kanade.mangafeed.presenter.CatalogueListPresenter; | ||||||
| import eu.kanade.mangafeed.sources.Source; | import eu.kanade.mangafeed.sources.Source; | ||||||
| import eu.kanade.mangafeed.view.CatalogueListView; | import eu.kanade.mangafeed.view.CatalogueListView; | ||||||
|  | import eu.kanade.mangafeed.widget.EndlessScrollListener; | ||||||
| import uk.co.ribot.easyadapter.EasyAdapter; | import uk.co.ribot.easyadapter.EasyAdapter; | ||||||
| 
 | 
 | ||||||
| public class CatalogueListActivity extends BaseActivity implements CatalogueListView { | public class CatalogueListActivity extends BaseActivity implements CatalogueListView { | ||||||
| @ -24,7 +25,7 @@ public class CatalogueListActivity extends BaseActivity implements CatalogueList | |||||||
|     private Source source; |     private Source source; | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     protected void onCreate(Bundle savedInstanceState) { |     public void onCreate(Bundle savedInstanceState) { | ||||||
|         super.onCreate(savedInstanceState); |         super.onCreate(savedInstanceState); | ||||||
|         setContentView(R.layout.activity_catalogue_list); |         setContentView(R.layout.activity_catalogue_list); | ||||||
|         ButterKnife.bind(this); |         ButterKnife.bind(this); | ||||||
| @ -35,6 +36,12 @@ public class CatalogueListActivity extends BaseActivity implements CatalogueList | |||||||
|         presenter.initializeSource(); |         presenter.initializeSource(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public void onDestroy() { | ||||||
|  |         super.onDestroy(); | ||||||
|  |         presenter.destroySubscriptions(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public void setSource(Source source) { |     public void setSource(Source source) { | ||||||
|         this.source = source; |         this.source = source; | ||||||
|         setToolbarTitle(source.getName()); |         setToolbarTitle(source.getName()); | ||||||
| @ -44,4 +51,14 @@ public class CatalogueListActivity extends BaseActivity implements CatalogueList | |||||||
|         manga_list.setAdapter(adapter); |         manga_list.setAdapter(adapter); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public void setScrollListener() { | ||||||
|  |         manga_list.setOnScrollListener(new EndlessScrollListener() { | ||||||
|  |             @Override | ||||||
|  |             public boolean onLoadMore(int page, int totalItemsCount) { | ||||||
|  |                 presenter.getMangasFromSource(page); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -9,4 +9,5 @@ public interface CatalogueListView extends BaseView { | |||||||
|     Intent getIntent(); |     Intent getIntent(); | ||||||
|     void setSource(Source source); |     void setSource(Source source); | ||||||
|     void setAdapter(EasyAdapter adapter); |     void setAdapter(EasyAdapter adapter); | ||||||
|  |     void setScrollListener(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,69 @@ | |||||||
|  | package eu.kanade.mangafeed.widget; | ||||||
|  | 
 | ||||||
|  | import android.widget.AbsListView; | ||||||
|  | 
 | ||||||
|  | public abstract class EndlessScrollListener implements AbsListView.OnScrollListener { | ||||||
|  |     // The minimum amount of items to have below your current scroll position | ||||||
|  |     // before loading more. | ||||||
|  |     private int visibleThreshold = 5; | ||||||
|  |     // The current offset index of data you have loaded | ||||||
|  |     private int currentPage = 0; | ||||||
|  |     // The total number of items in the dataset after the last load | ||||||
|  |     private int previousTotalItemCount = 0; | ||||||
|  |     // True if we are still waiting for the last set of data to load. | ||||||
|  |     private boolean loading = true; | ||||||
|  |     // Sets the starting page index | ||||||
|  |     private int startingPageIndex = 0; | ||||||
|  | 
 | ||||||
|  |     public EndlessScrollListener() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public EndlessScrollListener(int visibleThreshold) { | ||||||
|  |         this.visibleThreshold = visibleThreshold; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public EndlessScrollListener(int visibleThreshold, int startPage) { | ||||||
|  |         this.visibleThreshold = visibleThreshold; | ||||||
|  |         this.startingPageIndex = startPage; | ||||||
|  |         this.currentPage = startPage; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // This happens many times a second during a scroll, so be wary of the code you place here. | ||||||
|  |     // We are given a few useful parameters to help us work out if we need to load some more data, | ||||||
|  |     // but first we check if we are waiting for the previous load to finish. | ||||||
|  |     @Override | ||||||
|  |     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) | ||||||
|  |     { | ||||||
|  |         // If the total item count is zero and the previous isn't, assume the | ||||||
|  |         // list is invalidated and should be reset back to initial state | ||||||
|  |         if (totalItemCount < previousTotalItemCount) { | ||||||
|  |             this.currentPage = this.startingPageIndex; | ||||||
|  |             this.previousTotalItemCount = totalItemCount; | ||||||
|  |             if (totalItemCount == 0) { this.loading = true; } | ||||||
|  |         } | ||||||
|  |         // If it’s still loading, we check to see if the dataset count has | ||||||
|  |         // changed, if so we conclude it has finished loading and update the current page | ||||||
|  |         // number and total item count. | ||||||
|  |         if (loading && (totalItemCount > previousTotalItemCount)) { | ||||||
|  |             loading = false; | ||||||
|  |             previousTotalItemCount = totalItemCount; | ||||||
|  |             currentPage++; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // If it isn’t currently loading, we check to see if we have breached | ||||||
|  |         // the visibleThreshold and need to reload more data. | ||||||
|  |         // If we do need to reload some more data, we execute onLoadMore to fetch the data. | ||||||
|  |         if (!loading && (totalItemCount - visibleItemCount)<=(firstVisibleItem + visibleThreshold)) { | ||||||
|  |             loading = onLoadMore(currentPage + 1, totalItemCount); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Defines the process for actually loading more data based on page | ||||||
|  |     // Returns true if more data is being loaded; returns false if there is no more data to load. | ||||||
|  |     public abstract boolean onLoadMore(int page, int totalItemsCount); | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void onScrollStateChanged(AbsListView view, int scrollState) { | ||||||
|  |         // Don't take any action on changed | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 inorichi
						inorichi