diff options
| author | Samuel Tardieu <sam@rfc1149.net> | 2014-01-11 08:16:22 +0100 |
|---|---|---|
| committer | Samuel Tardieu <sam@rfc1149.net> | 2014-01-11 08:34:09 +0100 |
| commit | a3eec43088f06c9dcaa88135c92b6757347df196 (patch) | |
| tree | b19d14d93b9bd40d93318684368ad69a18230fcf | |
| parent | 8ce9c63b11781276d5c1de7250744d4b9eea1e08 (diff) | |
| download | cgeo-a3eec43088f06c9dcaa88135c92b6757347df196.zip cgeo-a3eec43088f06c9dcaa88135c92b6757347df196.tar.gz cgeo-a3eec43088f06c9dcaa88135c92b6757347df196.tar.bz2 | |
Use RxJava instead of an AsyncTask for description rendering
| -rw-r--r-- | main/src/cgeo/geocaching/CacheDetailActivity.java | 234 |
1 files changed, 117 insertions, 117 deletions
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 4b8e821..e1760d2 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -57,6 +57,13 @@ import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; +import rx.Observable; +import rx.Observable.OnSubscribeFunc; +import rx.Observer; +import rx.Subscription; +import rx.android.observables.AndroidObservable; +import rx.concurrency.Schedulers; +import rx.subscriptions.Subscriptions; import android.R.color; import android.app.AlertDialog; @@ -1481,7 +1488,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc // cache short description if (StringUtils.isNotBlank(cache.getShortDescription())) { - new LoadDescriptionTask(cache.getShortDescription(), view.findViewById(R.id.shortdesc), null, null).execute(); + loadDescription(cache.getShortDescription(), (IndexOutOfBoundsAvoidingTextView) view.findViewById(R.id.shortdesc), null, null); } // long description @@ -1608,7 +1615,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc showDesc.setOnClickListener(null); view.findViewById(R.id.loading).setVisibility(View.VISIBLE); - new LoadDescriptionTask(cache.getDescription(), view.findViewById(R.id.longdesc), view.findViewById(R.id.loading), view.findViewById(R.id.shortdesc)).execute(); + loadDescription(cache.getDescription(), (IndexOutOfBoundsAvoidingTextView) view.findViewById(R.id.longdesc), view.findViewById(R.id.loading), view.findViewById(R.id.shortdesc)); } private void warnPersonalNoteNeedsStoring() { @@ -1649,138 +1656,131 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc * <li>loading indicator view (View, may be null)</li> * </ol> */ - private class LoadDescriptionTask extends AsyncTask<Object, Void, Void> { - private final View loadingIndicatorView; - private final IndexOutOfBoundsAvoidingTextView descriptionView; - private final String descriptionString; - private Spanned description; - private final View shortDescView; - public LoadDescriptionTask(final String description, final View descriptionView, final View loadingIndicatorView, final View shortDescView) { - assert descriptionView instanceof IndexOutOfBoundsAvoidingTextView; - this.descriptionString = description; - this.descriptionView = (IndexOutOfBoundsAvoidingTextView) descriptionView; - this.loadingIndicatorView = loadingIndicatorView; - this.shortDescView = shortDescView; - } + private void loadDescription(final String descriptionString, final IndexOutOfBoundsAvoidingTextView descriptionView, final View loadingIndicatorView, final View shortDescView) { + // The producer produces successives (without then with images) versions of the description. + final Observable<Spanned> producer = Observable.create(new OnSubscribeFunc<Spanned>() { + @Override + public Subscription onSubscribe(final Observer<? super Spanned> observer) { + try { + // Fast preview: parse only HTML without loading any images + final HtmlImageCounter imageCounter = new HtmlImageCounter(); + final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler(); + Spanned description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler); + addWarning(unknownTagsHandler, description); + observer.onNext(description); + + if (imageCounter.getImageCount() > 0) { + // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview + description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler); + addWarning(unknownTagsHandler, description); + observer.onNext(description); + } - @Override - protected Void doInBackground(Object... params) { - try { - // Fast preview: parse only HTML without loading any images - final HtmlImageCounter imageCounter = new HtmlImageCounter(); - final UnknownTagsHandler unknownTagsHandler = new UnknownTagsHandler(); - description = Html.fromHtml(descriptionString, imageCounter, unknownTagsHandler); - publishProgress(); - - boolean needsRefresh = false; - if (imageCounter.getImageCount() > 0) { - // Complete view: parse again with loading images - if necessary ! If there are any images causing problems the user can see at least the preview - description = Html.fromHtml(descriptionString, new HtmlImage(cache.getGeocode(), true, cache.getListId(), false), unknownTagsHandler); - needsRefresh = true; - } - - // If description has an HTML construct which may be problematic to render, add a note at the end of the long description. - // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though - // sometimes technically incorrect. - if (unknownTagsHandler.isProblematicDetected() && descriptionView != null) { + observer.onCompleted(); + } catch (final Exception e) { + Log.e("LoadDescriptionTask: ", e); + observer.onError(e); + } + return Subscriptions.empty(); + } + + // If description has an HTML construct which may be problematic to render, add a note at the end of the long description. + // Technically, it may not be a table, but a pre, which has the same problems as a table, so the message is ok even though + // sometimes technically incorrect. + private void addWarning(final UnknownTagsHandler unknownTagsHandler, final Spanned description) { + if (unknownTagsHandler.isProblematicDetected()) { final int startPos = description.length(); final IConnector connector = ConnectorFactory.getConnector(cache); final Spanned tableNote = Html.fromHtml(res.getString(R.string.cache_description_table_note, "<a href=\"" + cache.getUrl() + "\">" + connector.getName() + "</a>")); ((Editable) description).append("\n\n").append(tableNote); ((Editable) description).setSpan(new StyleSpan(Typeface.ITALIC), startPos, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - needsRefresh = true; - } - - if (needsRefresh) { - publishProgress(); } - } catch (final Exception e) { - Log.e("LoadDescriptionTask: ", e); - } - return null; - } - - @Override - protected void onProgressUpdate(Void... values) { - if (description == null) { - showToast(res.getString(R.string.err_load_descr_failed)); - return; } - if (StringUtils.isNotBlank(descriptionString)) { - try { - descriptionView.setText(description, TextView.BufferType.SPANNABLE); - } catch (final Exception e) { - // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412 - Log.e("Android bug setting text: ", e); - // remove the formatting by converting to a simple string - descriptionView.setText(description.toString()); - } - descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); - fixTextColor(descriptionView, descriptionString); - descriptionView.setVisibility(View.VISIBLE); - registerForContextMenu(descriptionView); + }); - hideDuplicatedShortDescription(); - } - } + AndroidObservable.fromActivity(this, producer.subscribeOn(Schedulers.threadPoolForIO())) + .subscribe(new Observer<Spanned>() { + @Override + public void onCompleted() { + if (null != loadingIndicatorView) { + loadingIndicatorView.setVisibility(View.GONE); + } + } - /** - * Hide the short description, if it is contained somewhere at the start of the long description. - */ - private void hideDuplicatedShortDescription() { - if (shortDescView != null) { - final String shortDescription = cache.getShortDescription(); - if (StringUtils.isNotBlank(shortDescription)) { - final int index = descriptionString.indexOf(shortDescription); - if (index >= 0 && index < 200) { - shortDescView.setVisibility(View.GONE); + @Override + public void onError(final Throwable throwable) { + showToast(res.getString(R.string.err_load_descr_failed)); } - } - } - } - @Override - protected void onPostExecute(Void result) { - if (null != loadingIndicatorView) { - loadingIndicatorView.setVisibility(View.GONE); - } - } + @Override + public void onNext(final Spanned description) { + if (StringUtils.isNotBlank(descriptionString)) { + try { + descriptionView.setText(description, TextView.BufferType.SPANNABLE); + } catch (final Exception e) { + // On 4.1, there is sometimes a crash on measuring the layout: https://code.google.com/p/android/issues/detail?id=35412 + Log.e("Android bug setting text: ", e); + // remove the formatting by converting to a simple string + descriptionView.setText(description.toString()); + } + descriptionView.setMovementMethod(AnchorAwareLinkMovementMethod.getInstance()); + fixTextColor(descriptionString); + descriptionView.setVisibility(View.VISIBLE); + registerForContextMenu(descriptionView); - /** - * Handle caches with black font color in dark skin and white font color in light skin - * by changing background color of the view - * - * @param view - * containing the text - * @param text - * to be checked - */ - private void fixTextColor(final TextView view, final String text) { - int backcolor; - if (Settings.isLightSkin()) { - backcolor = color.white; - - for (final Pattern pattern : LIGHT_COLOR_PATTERNS) { - final MatcherWrapper matcher = new MatcherWrapper(pattern, text); - if (matcher.find()) { - view.setBackgroundResource(color.darker_gray); - return; + hideDuplicatedShortDescription(descriptionString); + } } - } - } else { - backcolor = color.black; - for (final Pattern pattern : DARK_COLOR_PATTERNS) { - final MatcherWrapper matcher = new MatcherWrapper(pattern, text); - if (matcher.find()) { - view.setBackgroundResource(color.darker_gray); - return; + /** + * Hide the short description, if it is contained somewhere at the start of the long description. + */ + private void hideDuplicatedShortDescription(final String descriptionString) { + if (shortDescView != null) { + final String shortDescription = cache.getShortDescription(); + if (StringUtils.isNotBlank(shortDescription)) { + final int index = descriptionString.indexOf(shortDescription); + if (index >= 0 && index < 200) { + shortDescView.setVisibility(View.GONE); + } + } + } } - } - } - view.setBackgroundResource(backcolor); - } + + /** + * Handle caches with black font color in dark skin and white font color in light skin + * by changing background color of the view + * + * @param text + * to be checked + */ + private void fixTextColor(final String text) { + int backcolor; + if (Settings.isLightSkin()) { + backcolor = color.white; + + for (final Pattern pattern : LIGHT_COLOR_PATTERNS) { + final MatcherWrapper matcher = new MatcherWrapper(pattern, text); + if (matcher.find()) { + descriptionView.setBackgroundResource(color.darker_gray); + return; + } + } + } else { + backcolor = color.black; + + for (final Pattern pattern : DARK_COLOR_PATTERNS) { + final MatcherWrapper matcher = new MatcherWrapper(pattern, text); + if (matcher.find()) { + descriptionView.setBackgroundResource(color.darker_gray); + return; + } + } + } + descriptionView.setBackgroundResource(backcolor); + } + }); } private class WaypointsViewCreator extends AbstractCachingPageViewCreator<ListView> { |
