Dropping async task for bonsai in image downloading
This commit is contained in:
parent
0819d35711
commit
3c133748e9
@ -66,7 +66,7 @@ dexcount {
|
||||
dependencies {
|
||||
|
||||
// support libraries
|
||||
def supportLibVersion = '25.3.0'
|
||||
def supportLibVersion = '25.3.1'
|
||||
compile "com.android.support:palette-v7:$supportLibVersion"
|
||||
compile "com.android.support:appcompat-v7:$supportLibVersion"
|
||||
compile "com.android.support:design:$supportLibVersion"
|
||||
|
@ -7,6 +7,7 @@ import acr.browser.lightning.activity.ReadingActivity;
|
||||
import acr.browser.lightning.activity.TabsManager;
|
||||
import acr.browser.lightning.activity.ThemableBrowserActivity;
|
||||
import acr.browser.lightning.activity.ThemableSettingsActivity;
|
||||
import acr.browser.lightning.view.ImageDownloader;
|
||||
import acr.browser.lightning.browser.BrowserPresenter;
|
||||
import acr.browser.lightning.constant.BookmarkPage;
|
||||
import acr.browser.lightning.constant.HistoryPage;
|
||||
@ -76,4 +77,6 @@ public interface AppComponent {
|
||||
|
||||
void inject(SuggestionsAdapter suggestionsAdapter);
|
||||
|
||||
void inject(ImageDownloader imageDownloader);
|
||||
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
package acr.browser.lightning.async;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
/**
|
||||
* Created 9/27/2015 Anthony Restaino
|
||||
*/
|
||||
public class AsyncExecutor implements Executor {
|
||||
|
||||
private static final String TAG = AsyncExecutor.class.getSimpleName();
|
||||
private static final AsyncExecutor INSTANCE = new AsyncExecutor();
|
||||
private final Queue<Runnable> mQueue = new ArrayDeque<>(1);
|
||||
private final ExecutorService mExecutor = Executors.newFixedThreadPool(4);
|
||||
|
||||
private AsyncExecutor() {}
|
||||
|
||||
@NonNull
|
||||
public static AsyncExecutor getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public synchronized void notifyThreadFinish() {
|
||||
if (mQueue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Runnable runnable = mQueue.remove();
|
||||
execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
mExecutor.shutdownNow();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(@NonNull Runnable command) {
|
||||
try {
|
||||
mExecutor.execute(command);
|
||||
} catch (RejectedExecutionException ignored) {
|
||||
mQueue.add(command);
|
||||
Log.d(TAG, "Thread was enqueued");
|
||||
}
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@ import com.anthonycr.bonsai.SingleSubscriber;
|
||||
import com.squareup.otto.Bus;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -44,8 +45,7 @@ import acr.browser.lightning.R;
|
||||
import acr.browser.lightning.activity.ReadingActivity;
|
||||
import acr.browser.lightning.activity.TabsManager;
|
||||
import acr.browser.lightning.app.BrowserApp;
|
||||
import acr.browser.lightning.async.AsyncExecutor;
|
||||
import acr.browser.lightning.async.ImageDownloadTask;
|
||||
import acr.browser.lightning.view.ImageDownloader;
|
||||
import acr.browser.lightning.browser.BookmarksView;
|
||||
import acr.browser.lightning.bus.BookmarkEvents;
|
||||
import acr.browser.lightning.constant.Constants;
|
||||
@ -74,6 +74,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
|
||||
|
||||
@Inject PreferenceManager mPreferenceManager;
|
||||
|
||||
private ImageDownloader mImageDownloader;
|
||||
|
||||
private TabsManager mTabsManager;
|
||||
|
||||
private UIController mUiController;
|
||||
@ -124,7 +126,9 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
|
||||
mWebpageBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme);
|
||||
mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme);
|
||||
mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) :
|
||||
ThemeUtils.getIconLightThemeColor(context);
|
||||
ThemeUtils.getIconLightThemeColor(context);
|
||||
|
||||
mImageDownloader = new ImageDownloader(mWebpageBitmap);
|
||||
}
|
||||
|
||||
private TabsManager getTabsManager() {
|
||||
@ -222,7 +226,9 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
|
||||
mWebpageBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_webpage, darkTheme);
|
||||
mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme);
|
||||
mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) :
|
||||
ThemeUtils.getIconLightThemeColor(activity);
|
||||
ThemeUtils.getIconLightThemeColor(activity);
|
||||
|
||||
mImageDownloader = new ImageDownloader(mWebpageBitmap);
|
||||
}
|
||||
|
||||
private void updateBookmarkIndicator(final String url) {
|
||||
@ -389,14 +395,31 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
|
||||
|
||||
ViewCompat.jumpDrawablesToCurrentState(row);
|
||||
|
||||
HistoryItem web = mBookmarks.get(position);
|
||||
final HistoryItem web = mBookmarks.get(position);
|
||||
holder.txtTitle.setText(web.getTitle());
|
||||
if (web.isFolder()) {
|
||||
holder.favicon.setImageBitmap(mFolderBitmap);
|
||||
} else if (web.getBitmap() == null) {
|
||||
holder.favicon.setImageBitmap(mWebpageBitmap);
|
||||
new ImageDownloadTask(holder.favicon, web, mWebpageBitmap, BrowserApp.get(context))
|
||||
.executeOnExecutor(AsyncExecutor.getInstance());
|
||||
holder.favicon.setTag(web.getUrl().hashCode());
|
||||
|
||||
final String url = web.getUrl();
|
||||
final WeakReference<ImageView> imageViewReference = new WeakReference<>(holder.favicon);
|
||||
mImageDownloader.newImageRequest(url)
|
||||
.subscribeOn(Schedulers.worker())
|
||||
.observeOn(Schedulers.main())
|
||||
.subscribe(new SingleOnSubscribe<Bitmap>() {
|
||||
@Override
|
||||
public void onItem(@Nullable Bitmap item) {
|
||||
ImageView imageView = imageViewReference.get();
|
||||
Object tag = imageView != null ? imageView.getTag() : null;
|
||||
if (tag != null && tag.equals(url.hashCode())) {
|
||||
imageView.setImageBitmap(item);
|
||||
}
|
||||
|
||||
web.setBitmap(item);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
holder.favicon.setImageBitmap(web.getBitmap());
|
||||
}
|
||||
|
@ -1,69 +1,91 @@
|
||||
package acr.browser.lightning.async;
|
||||
package acr.browser.lightning.view;
|
||||
|
||||
import android.app.Application;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.anthonycr.bonsai.Schedulers;
|
||||
import com.anthonycr.bonsai.Single;
|
||||
import com.anthonycr.bonsai.SingleAction;
|
||||
import com.anthonycr.bonsai.SingleSubscriber;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import acr.browser.lightning.app.BrowserApp;
|
||||
import acr.browser.lightning.constant.Constants;
|
||||
import acr.browser.lightning.database.HistoryItem;
|
||||
import acr.browser.lightning.utils.Utils;
|
||||
|
||||
public class ImageDownloadTask extends AsyncTask<Void, Void, Bitmap> {
|
||||
/**
|
||||
* An ImageDownloader that creates image
|
||||
* loading requests on demand.
|
||||
*/
|
||||
public class ImageDownloader {
|
||||
|
||||
private static final String TAG = ImageDownloadTask.class.getSimpleName();
|
||||
@NonNull private final WeakReference<ImageView> mFaviconImage;
|
||||
@NonNull private final Application mContext;
|
||||
@NonNull private final HistoryItem mWeb;
|
||||
private final String mUrl;
|
||||
@NonNull private final Bitmap mDefaultBitmap;
|
||||
private static final String TAG = "ImageDownloader";
|
||||
|
||||
public ImageDownloadTask(@NonNull ImageView bmImage,
|
||||
@NonNull HistoryItem web,
|
||||
@NonNull Bitmap defaultBitmap,
|
||||
@NonNull Application context) {
|
||||
// Set a tag on the ImageView so we know if the view
|
||||
// has gone out of scope and should not be used
|
||||
bmImage.setTag(web.getUrl().hashCode());
|
||||
this.mFaviconImage = new WeakReference<>(bmImage);
|
||||
this.mWeb = web;
|
||||
this.mUrl = web.getUrl();
|
||||
this.mDefaultBitmap = defaultBitmap;
|
||||
this.mContext = context;
|
||||
@Inject Application mApp;
|
||||
|
||||
@NonNull private Bitmap mDefaultBitmap;
|
||||
|
||||
public ImageDownloader(@NonNull Bitmap defaultBitmap) {
|
||||
mDefaultBitmap = defaultBitmap;
|
||||
BrowserApp.getAppComponent().inject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new image request for the given url.
|
||||
* Emits the bitmap associated with that url, or
|
||||
* the default bitmap if none was found.
|
||||
*
|
||||
* @param url the url for which to retrieve the bitmap.
|
||||
* @return a single that emits the bitmap that was found.
|
||||
*/
|
||||
@NonNull
|
||||
public Single<Bitmap> newImageRequest(@Nullable final String url) {
|
||||
return Single.create(new SingleAction<Bitmap>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull SingleSubscriber<Bitmap> subscriber) {
|
||||
Bitmap favicon = retrieveBitmap(mApp, mDefaultBitmap, url);
|
||||
|
||||
Bitmap paddedFavicon = Utils.padFavicon(favicon);
|
||||
|
||||
subscriber.onItem(paddedFavicon);
|
||||
subscriber.onComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Bitmap doInBackground(Void... params) {
|
||||
Bitmap mIcon = null;
|
||||
private static Bitmap retrieveBitmap(@NonNull Application app,
|
||||
@NonNull Bitmap defaultBitmap,
|
||||
@Nullable String url) {
|
||||
|
||||
// unique path for each url that is bookmarked.
|
||||
if (mUrl == null) {
|
||||
return mDefaultBitmap;
|
||||
if (url == null) {
|
||||
return defaultBitmap;
|
||||
}
|
||||
File cache = mContext.getCacheDir();
|
||||
final Uri uri = Uri.parse(mUrl);
|
||||
if (uri.getHost() == null || uri.getScheme() == null) {
|
||||
return mDefaultBitmap;
|
||||
|
||||
Bitmap icon = null;
|
||||
File cache = app.getCacheDir();
|
||||
final Uri uri = Uri.parse(url);
|
||||
|
||||
if (uri.getHost() == null || uri.getScheme() == null || Constants.FILE.startsWith(uri.getScheme())) {
|
||||
return defaultBitmap;
|
||||
}
|
||||
|
||||
final String hash = String.valueOf(uri.getHost().hashCode());
|
||||
final File image = new File(cache, hash + ".png");
|
||||
final String urlDisplay = uri.getScheme() + "://" + uri.getHost() + "/favicon.ico";
|
||||
if (Constants.FILE.startsWith(uri.getScheme())) {
|
||||
return mDefaultBitmap;
|
||||
}
|
||||
|
||||
// checks to see if the image exists
|
||||
if (!image.exists()) {
|
||||
FileOutputStream fos = null;
|
||||
@ -79,12 +101,12 @@ public class ImageDownloadTask extends AsyncTask<Void, Void, Bitmap> {
|
||||
in = connection.getInputStream();
|
||||
|
||||
if (in != null) {
|
||||
mIcon = BitmapFactory.decodeStream(in);
|
||||
icon = BitmapFactory.decodeStream(in);
|
||||
}
|
||||
// ...and cache it
|
||||
if (mIcon != null) {
|
||||
if (icon != null) {
|
||||
fos = new FileOutputStream(image);
|
||||
mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
fos.flush();
|
||||
Log.d(Constants.TAG, "Downloaded: " + urlDisplay);
|
||||
}
|
||||
@ -97,9 +119,10 @@ public class ImageDownloadTask extends AsyncTask<Void, Void, Bitmap> {
|
||||
}
|
||||
} else {
|
||||
// if it exists, retrieve it from the cache
|
||||
mIcon = BitmapFactory.decodeFile(image.getPath());
|
||||
icon = BitmapFactory.decodeFile(image.getPath());
|
||||
}
|
||||
if (mIcon == null) {
|
||||
|
||||
if (icon == null) {
|
||||
InputStream in = null;
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
@ -113,12 +136,12 @@ public class ImageDownloadTask extends AsyncTask<Void, Void, Bitmap> {
|
||||
in = connection.getInputStream();
|
||||
|
||||
if (in != null) {
|
||||
mIcon = BitmapFactory.decodeStream(in);
|
||||
icon = BitmapFactory.decodeStream(in);
|
||||
}
|
||||
// ...and cache it
|
||||
if (mIcon != null) {
|
||||
if (icon != null) {
|
||||
fos = new FileOutputStream(image);
|
||||
mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
fos.flush();
|
||||
}
|
||||
|
||||
@ -129,28 +152,11 @@ public class ImageDownloadTask extends AsyncTask<Void, Void, Bitmap> {
|
||||
Utils.close(fos);
|
||||
}
|
||||
}
|
||||
if (mIcon == null) {
|
||||
return mDefaultBitmap;
|
||||
|
||||
if (icon == null) {
|
||||
return defaultBitmap;
|
||||
} else {
|
||||
return mIcon;
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap bitmap) {
|
||||
super.onPostExecute(bitmap);
|
||||
AsyncExecutor.getInstance().notifyThreadFinish();
|
||||
final Bitmap fav = Utils.padFavicon(bitmap);
|
||||
final ImageView view = mFaviconImage.get();
|
||||
if (view != null && view.getTag().equals(mWeb.getUrl().hashCode())) {
|
||||
Schedulers.main().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
view.setImageBitmap(fav);
|
||||
}
|
||||
});
|
||||
}
|
||||
mWeb.setBitmap(fav);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user