diff --git a/app/build.gradle b/app/build.gradle index 3b6b5348..00215bae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "jp.juggler.subwaytooter" minSdkVersion 21 targetSdkVersion 25 - versionCode 87 - versionName "0.8.7" + versionCode 88 + versionName "0.8.8" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActMain.java b/app/src/main/java/jp/juggler/subwaytooter/ActMain.java index c1784c70..ccd38648 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActMain.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ActMain.java @@ -138,6 +138,9 @@ public class ActMain extends AppCompatActivity @Override protected void onDestroy(){ super.onDestroy(); + for(Column c: app_state.column_list){ + c.removeAllColumnViewHolder(); + } } static final String STATE_CURRENT_PAGE = "current_page"; diff --git a/app/src/main/java/jp/juggler/subwaytooter/Column.java b/app/src/main/java/jp/juggler/subwaytooter/Column.java index 96a556e5..e1a950f7 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Column.java +++ b/app/src/main/java/jp/juggler/subwaytooter/Column.java @@ -786,6 +786,10 @@ class Column implements StreamReader.Callback { if( cvh == it.next() ) it.remove(); } } + + void removeAllColumnViewHolder( ){ + _holder_list.clear(); + } boolean hasMultipleViewHolder(){ return _holder_list.size() > 1; diff --git a/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java b/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java index d28e2521..f72b6d25 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java @@ -43,6 +43,7 @@ class ColumnViewHolder @Nullable Column column; @Nullable private ItemListAdapter status_adapter; + int page_idx; private final TextView tvLoading; private final MyListView listView; @@ -226,6 +227,7 @@ class ColumnViewHolder loading_busy = true; try{ this.column = column; + this.page_idx = page_idx; log.d( "onPageCreate [%d] %s",page_idx, column.getColumnName( true ) ); @@ -437,6 +439,7 @@ class ColumnViewHolder Uri uri = Uri.parse( url ); return Utils.createResizedBitmap( log, activity, uri, false, resize_max ); + }catch(Throwable ex){ ex.printStackTrace(); } @@ -751,9 +754,25 @@ class ColumnViewHolder final Runnable proc_restoreScrollPosition = new Runnable() { @Override public void run(){ activity.handler.removeCallbacks( proc_restoreScrollPosition ); - if( column == null ) return; + + if( isPageDestroyed() ){ + log.d( "restoreScrollPosition [%d], page is destroyed."); + return; + } + + if( column == null ){ + log.d( "restoreScrollPosition [%d], column==null",page_idx); + return; + } + + if( column .is_dispose.get() ){ + log.d( "restoreScrollPosition [%d], column is disposed",page_idx); + return; + } if( column.hasMultipleViewHolder() ){ + log.d( "restoreScrollPosition [%d] %s , column has multiple view holder. retry later.", page_idx, column.getColumnName( true )); + // タブレットモードでカラムを追加/削除した際に発生する。 // このタイミングでスクロール位置を復元してもうまくいかないので延期する activity.handler.post( proc_restoreScrollPosition ); @@ -761,11 +780,26 @@ class ColumnViewHolder } ScrollPosition sp = column.scroll_save; - if( sp == null ) return; + if( sp == null ){ + log.d( "restoreScrollPosition [%d] %s , column has no saved scroll position.", page_idx, column.getColumnName( true )); + return; + } + column.scroll_save = null; - if( listView.getVisibility() == View.VISIBLE ){ + if( listView.getVisibility() != View.VISIBLE ){ + log.d( "restoreScrollPosition [%d] %s , listView is not visible. saved position %s,%s is dropped." + , page_idx, column.getColumnName( true ) + ,sp.pos + ,sp.top + ); + }else{ + log.d( "restoreScrollPosition [%d] %s , listView is visible. resume %s,%s" + , page_idx, column.getColumnName( true ) + ,sp.pos + ,sp.top + ); sp.restore( listView ); } @@ -774,12 +808,29 @@ class ColumnViewHolder private void saveScrollPosition(){ - if( column != null && ! column.is_dispose.get() ){ - if( listView.getVisibility() == View.VISIBLE ){ - column.scroll_save = new ScrollPosition( listView ); - }else{ - column.scroll_save = new ScrollPosition( 0, 0 ); - } + + if( column == null ){ + log.d( "saveScrollPosition [%d] , column==null",page_idx ); + + }else if( column.is_dispose.get() ){ + log.d( "saveScrollPosition [%d] , column is disposed",page_idx ); + + }else if( listView.getVisibility() != View.VISIBLE ){ + + column.scroll_save = new ScrollPosition( 0, 0 ); + log.d( "saveScrollPosition [%d] %s , listView is not visible, save %s,%s" + , page_idx, column.getColumnName( true ) + ,column.scroll_save.pos + ,column.scroll_save.top + ); + }else{ + + column.scroll_save = new ScrollPosition( listView ); + log.d( "saveScrollPosition [%d] %s , listView is visible, save %s,%s" + , page_idx, column.getColumnName( true ) + ,column.scroll_save.pos + ,column.scroll_save.top + ); } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.java b/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.java index 2f3bc613..955368f5 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ItemViewHolder.java @@ -323,7 +323,10 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener { tvName.setText( status.account.display_name ); ivThumbnail.setCornerRadius( activity.pref, 16f ); - ivThumbnail.setImageUrl( access_info.supplyBaseUrl( status.account.avatar_static ) ); + ivThumbnail.setImageUrl( + access_info.supplyBaseUrl( status.account.avatar_static ) + ,access_info.supplyBaseUrl( status.account.avatar ) + ); tvContent.setText( status.decoded_content ); // if( status.decoded_tags == null ){ diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/Utils.java b/app/src/main/java/jp/juggler/subwaytooter/util/Utils.java index ab952735..1eefa8d1 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/Utils.java +++ b/app/src/main/java/jp/juggler/subwaytooter/util/Utils.java @@ -772,6 +772,8 @@ public class Utils { }finally{ src.recycle(); } + }catch(SecurityException ex){ + log.e(ex,"maybe we need pick up image again."); }catch( Throwable ex ){ ex.printStackTrace(); } diff --git a/app/src/main/java/jp/juggler/subwaytooter/view/MyNetworkImageView.java b/app/src/main/java/jp/juggler/subwaytooter/view/MyNetworkImageView.java index 27901341..8d4270ac 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/view/MyNetworkImageView.java +++ b/app/src/main/java/jp/juggler/subwaytooter/view/MyNetworkImageView.java @@ -15,7 +15,10 @@ import android.view.ViewGroup; import android.support.v7.widget.AppCompatImageView; import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.BaseTarget; +import com.bumptech.glide.request.target.GlideDrawableImageViewTarget; import com.bumptech.glide.request.target.SimpleTarget; import com.bumptech.glide.request.target.Target; @@ -60,14 +63,26 @@ public class MyNetworkImageView extends AppCompatImageView { // 表示したい画像のURL private String mUrl; + private boolean mIsUrlGif; public void setImageUrl( String url ){ - mUrl = url; + setImageUrl( url, null ); + } + + public void setImageUrl( String url, String gif_url ){ + // if( gif_url != null && mCornerRadius <= 0f && ! gif_url.equals( url ) ){ + // mUrl = gif_url; + // mIsUrlGif = true; + // }else + { + mUrl = url; + mIsUrlGif = false; + } loadImageIfNecessary(); } // 非同期処理のキャンセル - MyTarget mTarget; + BaseTarget< ? > mTarget; private void cancelLoading(){ if( mTarget != null ){ @@ -98,7 +113,7 @@ public class MyNetworkImageView extends AppCompatImageView { return; } - if( mTarget != null && mUrl.equals( mTarget.url ) ){ + if( mTarget != null && mUrl.equals( ( (UrlTarget) mTarget ).getUrl() ) ){ // すでにリクエストが発行済みで、リクエストされたURLが同じなら何もしない return; } @@ -125,10 +140,18 @@ public class MyNetworkImageView extends AppCompatImageView { return; } - mTarget = Glide.with( getContext() ) - .load( mUrl ) - .asBitmap() - .into( new MyTarget( mUrl, desiredWidth, desiredHeight ) ); + if( mIsUrlGif ){ + mTarget = Glide.with( getContext() ) + .load( mUrl ) + .into( new MyTargetGif( mUrl ) ); + + }else{ + mTarget = Glide.with( getContext() ) + .load( mUrl ) + .asBitmap() + .into( new MyTarget( mUrl, desiredWidth, desiredHeight ) ); + + } }catch( Throwable ex ){ ex.printStackTrace(); // java.lang.IllegalArgumentException: @@ -139,10 +162,92 @@ public class MyNetworkImageView extends AppCompatImageView { } } - private class MyTarget extends SimpleTarget< Bitmap > { + private interface UrlTarget { + @NonNull String getUrl(); + } + + private class MyTargetGif extends GlideDrawableImageViewTarget implements UrlTarget { @NonNull final String url; + @Override @NonNull public String getUrl(){ + return url; + } + + MyTargetGif( @NonNull String url ){ + super( MyNetworkImageView.this, GlideDrawable.LOOP_FOREVER ); + this.url = url; + } + + @Override public void onLoadFailed( Exception e, Drawable errorDrawable ){ + try{ + // このViewは別の画像を表示するように指定が変わっていた + if( ! url.equals( mUrl ) ) return; + + e.printStackTrace(); + if( mErrorImageId != 0 ) setImageResource( mErrorImageId ); + }catch( Throwable ex ){ + ex.printStackTrace(); + // java.lang.NullPointerException: + // at jp.juggler.subwaytooter.view.MyNetworkImageView$1.onLoadFailed(MyNetworkImageView.java:147) + // at com.bumptech.glide.request.GenericRequest.setErrorPlaceholder(GenericRequest.java:404) + // at com.bumptech.glide.request.GenericRequest.onException(GenericRequest.java:548) + // at com.bumptech.glide.load.engine.EngineJob.handleExceptionOnMainThread(EngineJob.java:183) + } + } + + @Override public void onResourceReady( + final GlideDrawable resource + , final GlideAnimation< ? super GlideDrawable > glideAnimation + ){ + try{ + // このViewは別の画像を表示するように指定が変わっていた + if( ! url.equals( mUrl ) ) return; + + super.onResourceReady( resource, glideAnimation ); + + // }else if( mCornerRadius <= 0f ){ + // setImageBitmap( bitmap ); + // }else{ + // RoundedBitmapDrawable d = RoundedBitmapDrawableFactory + // .create( getResources(), bitmap ); + // d.setCornerRadius( mCornerRadius ); + // setImageDrawable( d ); + // } + + }catch( Throwable ex ){ + ex.printStackTrace(); + } + } + + /** + * Sets the given {@link android.graphics.drawable.Drawable} on the view using + * {@link android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}. + * + * @param drawable {@inheritDoc} + */ + @Override + public void setDrawable( Drawable drawable ){ + + // if( mCornerRadius > 0f ){ + // RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create( getResources(), bitmap ); + // d.setCornerRadius( mCornerRadius ); + // setImageDrawable( d ); + // } + + view.setImageDrawable( drawable ); + } + + } + + private class MyTarget extends SimpleTarget< Bitmap > implements UrlTarget { + + @NonNull final String url; + + @Override @NonNull public String getUrl(){ + return url; + } + MyTarget( @NonNull String url, int desiredWidth, int desiredHeight ){ super( desiredWidth, desiredHeight ); this.url = url; @@ -173,9 +278,7 @@ public class MyNetworkImageView extends AppCompatImageView { // このViewは別の画像を表示するように指定が変わっていた if( ! url.equals( mUrl ) ) return; - if( bitmap == null ){ - setDefaultImageOrNull(); - }else if( mCornerRadius <= 0f ){ + if( mCornerRadius <= 0f ){ setImageBitmap( bitmap ); }else{ RoundedBitmapDrawable d = RoundedBitmapDrawableFactory @@ -183,6 +286,11 @@ public class MyNetworkImageView extends AppCompatImageView { d.setCornerRadius( mCornerRadius ); setImageDrawable( d ); } + + // if( glideAnimation != null ){ + // glideAnimation.animate( ) + // } + }catch( Throwable ex ){ ex.printStackTrace(); }