Browse Source

Dropping async task for bonsai in image downloading

master
anthony restaino 7 years ago
parent
commit
3c133748e9
  1. 2
      app/build.gradle
  2. 3
      app/src/main/java/acr/browser/lightning/app/AppComponent.java
  3. 53
      app/src/main/java/acr/browser/lightning/async/AsyncExecutor.java
  4. 37
      app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java
  5. 142
      app/src/main/java/acr/browser/lightning/view/ImageDownloader.java

2
app/build.gradle

@ -66,7 +66,7 @@ dexcount { @@ -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"

3
app/src/main/java/acr/browser/lightning/app/AppComponent.java

@ -7,6 +7,7 @@ import acr.browser.lightning.activity.ReadingActivity; @@ -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 { @@ -76,4 +77,6 @@ public interface AppComponent {
void inject(SuggestionsAdapter suggestionsAdapter);
void inject(ImageDownloader imageDownloader);
}

53
app/src/main/java/acr/browser/lightning/async/AsyncExecutor.java

@ -1,53 +0,0 @@ @@ -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");
}
}
}

37
app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java

@ -35,6 +35,7 @@ import com.anthonycr.bonsai.SingleSubscriber; @@ -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; @@ -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, @@ -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, @@ -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, @@ -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, @@ -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());
}

142
app/src/main/java/acr/browser/lightning/async/ImageDownloadTask.java → app/src/main/java/acr/browser/lightning/view/ImageDownloader.java

@ -1,69 +1,91 @@ @@ -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> {
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;
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;
/**
* An ImageDownloader that creates image
* loading requests on demand.
*/
public class ImageDownloader {
private static final String TAG = "ImageDownloader";
@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> { @@ -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> { @@ -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> { @@ -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> { @@ -129,28 +152,11 @@ public class ImageDownloadTask extends AsyncTask<Void, Void, Bitmap> {
Utils.close(fos);
}
}
if (mIcon == null) {
return mDefaultBitmap;
} else {
return mIcon;
}
}
@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);
}
});
if (icon == null) {
return defaultBitmap;
} else {
return icon;
}
mWeb.setBitmap(fav);
}
}
Loading…
Cancel
Save