タブレット用プログラムの書き止め

android OS & iPadOS の記録。

Fragment [基礎] メイン、サブの高速置き換えの例外発生。

2022-10-30 18:21:18 | Android studio 日記


それぞれのフラグメント上のダブルタップがトリガーとなり
  FragmentManager().beginTransaction()
                        .replace(R.id.container, mFragment)
                        .commitNow();
で置き換えを実行する。

高速で置き換えが起こるとView構築で不具合が起こり例外が発生する。
対策は高速切り替えをさせない。遅延実行など。
折り合いがつかない場合はトリガー方法を変える。
片方をダブルタップで切り替え確認させるダイアログを表示など。色々考える。


1つの方法のナビゲーションは習得に時間がかかるので後回し。
調整を試みたがすべて効果無し。
MainFragment ⇔ SubFragmentの置き換えはやめて
MainFragment ⇔ 内部 ImageView の切り替えに変更した。

高速切り替えは問題なく実行できた。
ただ、大きなサイズの画像を切り替え表示で連続させると、1回目は表示、2回目はメモリ不足でスキップ。

SubFragmentでは何回でもメイン画像 ⇔ 元画像を切り替えられたのだが。(ちょっと大きな画像)
メモリ解放かメモリ浪費に原因があるのかもしれない。
意図的に解放させる手段を施したがあまり変わらない。


最終的にメイン画像を表示しているImageSwitcherのカレントビューをmRealImageViewとして借り受け元サイズの画像を表示させる。
今のところ不具合は無く、切り替え速度、メモリ不足のスキップは抑えられている。(前の同じ画像)
更に巨大な画像はメモリ不足になるけれども。


大雑把にそれぞれのイベントでメイン画像処理と元画像表示処理に分岐している。
大半をジェスチャークラス内でコード作成できたのでまぁいいかな。少し煩雑…。

大分省略。

    private ImageSwitcher mImageSwitcher = null;
    private MyImageView mRealImageView;


    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onDoubleTap(MotionEvent event) {// 実サイズ表示へ移行

            if ( mMainImageFlag ){
                mMainImageFlag = false;
                realDoubleTap(event);
            } else {
                mMainImageFlag = true;
                mainDoubleTap(event);
            }

            return true;
        }

        // main

        private void mainDoubleTap(MotionEvent event) {
            refreshImage();
        }

 

        // real

        private void realDoubleTap(MotionEvent event) {
            File file = new File( mFileList.getFileNameAbsolutePath( touchDisplayNo( event.getX(), event.getY() ) ) );
            if ( !file.exists() || !file.isFile() ) return;

            clearImageSwitcher();
            if ( !setRealImage(file) ) {
                mMainImageFlag = true;
                refreshImage();
            }
        }
        private boolean setRealImage(File file) {
            // 元サイズのまま mRealImageView にBitmapを設定。

            省略

            return true;
        }
        private void clearImageSwitcher() { // ImageSwitcherのカレントビューを利用する

            mRealImageView = (MyImageView) mImageSwitcher.getCurrentView();
            ((MyImageView)mImageSwitcher.getNextView()).setImageBitmap(null);
        }

        private void realDown() {
            省略
        }

        private void realScroll(float distanceX, float distanceY) {
            省略
        }

        private void realFling(float velocityX, float velocityY) {
            省略
        }
    }


ほんと行き当たりばったり^^;

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

【雑談】分数の割り算。

2022-10-28 19:07:19 | 気まぐれ言の葉

以前録画したジブリ作品を連続再生した(BGM代わりに)。
思い出ぽろぽろで分数の割り算をリンゴで考えてた。
自分もやってたなぁ~と。

今だから分数の割り算は、比率の割り算と分かっている。
子供に説明するのは難しい。
だから、後ろを上下入れ替えて掛け算^^;

大人は楽をしてはいけない。
成り立ちをキチンと説明すれば大人を尊敬してくれるというのに、「黙って言うことを聞け!」
子供心に疑心の念にはちきれそうだったわ(笑)

子供に分かるように説明となるとやっぱりリンゴかな。でも胆の説明は難しい。

10÷2=5
これを説明するには?

総数が10個のリンゴ。
2個のまとまりのグループを作ると何グループになる?

〇〇 ●● 〇〇 ●● 〇〇

5グループ

よくある説明。これが説明できるなら分数の割り算も難しくもない?


要点は【総数】からまとまり【単位】がいくつ含まれているかを例題で示せばいい。

1/3 ÷ 1/2 = ?

リンゴ1/3を半分にする。と子供が言ったら考え方を正さなくてはいけない。

リンゴ1/3 の中に リンゴ1/2 がいくつ入っているか?

子供にイメージの飛躍は望めないので例題を示して導かないといけない。


1/3 ÷ 1/2 分母を6に通分する。
2/6 ÷ 3/6 リンゴの絵に切り込みを入れる。

リンゴ絵で説明する。

6等分のリンゴ2個が総数。
6等分のリンゴ3個のまとまりはいくつ?

リンゴの絵で説明すれば子供も理解できるだろう。

 

ただ、ここから先はリンゴは無し。混乱させるから。


2/6 ÷ 3/6 が 2/6 × 6/3 と同じだと検証する。きちんと説明すれば理解してくれる。


まずは分かりやすい数で説明する。

7/10 ÷ 3/10 = ?

考え方は?


例えば、
7÷3 と 70÷30 はいくつ? 両方とも 7/3 比率だから同じだけど子供には答えを出さないと理解できない。

計算させて同じだと経験させる。

(7×10)÷(3×10)と 70÷30 は同じ結果になる。

次は、

(7/10)×10 ÷(3/10)×10 も 7÷3 と同じ結果になる。


あくまでも確認でありテストの解答に書き加えると減点にされるかもしれないのでテスト用紙には書かない事。

 


7/10 ÷ 3/10 = 7÷3 = 7/3 この結果を子供に示す。

公式ではない基礎知識?

7/10 ÷ 3/10

÷ を × に変えて 後ろの分数を上下逆にするとどうなるのか確認させる。

7/10 × 10/3 分母と分子を約分して結果は 7/3 になると解説する。

7/10 × 10/3 =(7×10)/(3×10)約分→ 7/3

 

7/10 ÷ 3/10 = 7/10 × 10/3 = 7/3

7/10 ÷ 3/10 と 7/10 × 10/3 は結果は同じと認識させる。

できれば、2つ以上を確認させる。

(8/15)×15 ÷(4/15)×15 = 8÷4 = 8/4 = 2

     8/15 × 15/4(約分) = 8/4 = 2

 

色々な計算を検算し、その結果が同じだから納得した分数の割り算。

言われるがままの子供と探求心の強すぎる子供。
どっちが良いか分からないけど躓きは早く解決させた方がいい。

ほんと大切な時間を無駄にした。

そういう大人が近くに居なかったからね。

 

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Fragment [落穴] ダブルタップ連続(高速)で例外停止。

2022-10-25 13:08:05 | Android studio 日記

今、メインフラグメントでダブルタップをするとサブフラグメントに置き換えている。
サブフラグメントでダブルタップをするとメインフラグメントへ置き換えられる。
サブフラグメントでは1枚の画像を元のサイズで表示。大きければスクロールさせている。

普通と思われる速度でのダブルタップであれば例外は発生しないが高速でダブルタップを繰り返すと例外停止となる。

以前、新たにフラグメントを開くときに条件により例外停止が起こる。(遅延実行で対応。)
Viewを構築していくときに競合や不足が起こる?ため。
FragmentManager().beginTransaction().replace().commitNow();

commitNow() で時間調整をして表示させるみたいらしい。

自分の使い方が規則にのっとっている訳ではないので問題が発生しているのかもしれない。

今後の対処は
・タイマー組み込んで時間調整をする。
・フラグメントの置き換えでなくImageViewを1つ追加してViewの切り替えで対応させる。
・正当なフラグメントの切り替え。
・メモリを浪費したくない。切り替え速度は速くしたい。新しい方法を考える。

機能別にフラグメントを分けていてプログラムはスッキリしている。
できれば、フラグメントの置き換えで例外発生をなくしたい。

<追記>
Navigationを使ってフラグメントを偏移(置き換え?)させられる。
一度経験を…。かなり昔にサンプルで試したんだった。けど面倒くさかった。
要点だけ抜き出した説明を見つけたので切り替えをしてみる。

 

<追記、10/27>
フラグメントの構成。

メイン画面 ⇔ 元画像画面
  ┃
  ┣━  ⇔ サムネイル画像画面 ⇒ ディレクトリ移動画面
  ┃
  ┣━  ⇔ ディレクトリ移動画面
  ┃
  ┗━  ⇔ ブックマーク選択&編集画面

 


getSupportFragmentManager().beginTransaction() もしくは、getParentFragmentManager()
         .replace(R.id.container, mFragment).commitNow();

画面の変更はこれを使ってフラグメントを置き換えている。
メモリ消費を最小限にしたいから使い終わったものを開放して再利用させる。

この置き換え方法で最初の問題がでた。

【メイン画面 ⇔ ディレクトリ移動画面】

フラグメントの置き換えのタイミングで例外が発生。
次のフラグメント表示を遅延実行する事で例外を回避できた。

 

その後にアプリで想定される操作負荷をすると

・長押し判定が微妙でフリングを速く繰り返していると onLongPress() がコールされる。
 onFling() では、return true;でイベント消費しているから何かしらのタイミングで回っているようだ。
 フラグ設定とかでも弾けない。長押し時間を取得して時間条件を作り誤動作を減らせた。

・ダブルタップを速く繰り返すと
 【メイン画面 ⇔ 元画像画面】
 置き換え後に例外が発生。通常のダブルタップであれば例外は発生しない。
 遅延実行を入れれば高速ダブルタップ連続実行では例外を抑えられる。
 しかし、通常ダブルタップでも遅延が入りストレスとなる。


フラグメントマネージャーでは置き換え時の整合、ジェスチャー処理が問題を抱えている。

やれることは例外処理を追加。だけど、フラグメント作成時点のView構築描写時点の例外処理…。難しい。
おそらくViewの情報が揃わず、その情報を参照してしまってクラッシュ。遅延実行で回避できている以上そういうことだろう。
commitNow() でViewの生成や追加のタイミングをある程度調整してくれるそう。それでも吸収しきれない何かがある。

今後の方針は
・デザインを変える。
・問題のないフラグメント切り替え方法を探す。
・フラグメントの理解を深める。そして新しい方法を見つける。あぁ面倒くさっ!


今、ナビゲーションを使ったフラグメント切り替えを試している。ただ、移植は難航。
色々な部分で例外発生。分からない事も多い。
同じフラグメント構成なのに同じプログラム構成なのに問題が起こる。***<追記、10/28>で説明。***
参照情報の構築タイミングが変わるためか参照時点でクラッシュが起こっているのだろう。

説明では後続フラグメントで参照内容によりコールバックを元へ送り対応しているものもあった。
やり方は理解不足でまだ使えない。

取り合えず、ナビゲーションは後回しにしてデザインを変更する。
問題の大きさでいうと高速ダブルタップ繰り返しの例外停止。

【メイン画面 ⇔ 元画像画面】

フラグメント置き換えではなく、メインフラグメントに元画像表示用のImageViewを用意して表示非表示を切り替えて対応させる。
一番簡単な対応策だけどプログラムはゴチャゴチャしてくる。
クラス定義で分離できれば見やすくなるが、ジェスチャー処理も含められるか分からない。

クラス定義はついでに考えるとして、操作での不具合を潰していく。

 

あ、今思いついた事を試してからImageViewを組み込む。
ナビゲーションの参照例外が起こっている所で参照を待たせるメソッドを噛ませる。
タイマー制限で強制終了かキャンセルを選択させるみたいな。

結果を積み重ねるのがプログラムだ。
リファレンスを全部覚えるというのはヤル気が出ない(´・ω・)

 

<追記、10/28>

NEWプロジェクトのfragment + viewmodelという雛形でナビゲーションを組み込んだ場合は発生。

NEWプロジェクトの empty activity でナビゲーションを組み込んだ場合は例外が発生しなかった。

 


    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        TextView textView = view.findViewById(R.id.textview);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });
    }

 

setOnClickListener()の場所で例外が発生する、発生しないに分かれる。

fragment + viewmodelでプロジェクトを作るとui.mainというフォルダにFragmentが入れられる。
何かしら構造が違うのかもしれない。原因は分からない。

 

  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

[余談] View.OnClickListener の例外発生。

2022-10-14 13:02:06 | Android studio 日記

クリックリスナー設定で遅延実行を使っていてViewをダブルタップすると例外発生する。

        mButtonClick = v -> {

            touchAction( v );
            mHandler.postDelayed(() -> {
                test(v.getId());
            }, 500);
        };

遅延の待ち時間にまたクリックイベントで同じところに入って来るため。
対応はフラグを立て2度目をスルーさせる。

    boolean clickFlag = false;

省略
        mButtonClick = v -> {
            if (clickFlag) return; // フラグがセットされていたら戻る
            clickFlag = true; // フラグをセット

            touchAction( v );
            mHandler.postDelayed(() -> {
                clickFlag = false; // 遅延実行が始まったらフラグをリセット
                test(v.getId());
            }, 500);
        };


touchAction( v );はview.OnClickListenerを設定したviewをアニメーションさせるメソッド。(省略)
アニメーションが完了する前に本処理メソッドに移るとアニメーションがぶつ切りになってしまう。
なので遅延実行でアニメーション完了後に本処理に移行する。
(アニメーションはタップされた確認表示。ユーザーに受け付けた意思表示で必要。)


遅延実行とイベント処理は例外処理が必須。

 

 


それとView.Animation。touchAction( v )の書き換え。
今まで何となく形にしてたものを手順通りに組む。
以前の適当の方がプログラム短くてスッキリしてる。
爆弾も残る。ので、安全を担保。

10/15、修正しました。
複数の場所でフラグ操作するのではなく単一メソッド内でスルー判断させ分かり易くするため。

 

省略

    private boolean clickFlag = false; 消去

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        省略

        mButtonClick = v -> {
            if (clickFlag) return;

            touchAction( v );
        };

        mButton = view.findViewById(R.id.button);
        mButton.setOnClickListener(mButtonClick);
    }

    private final Handler mHandler = new Handler();
    private View mView = null; // 追加

    private void touchAction( View view ) {
        clickFlag = true;

        // 追加。 複数の場所でフラグ操作でなく単一メソッド内でスルー判断させる

        if ( mView == null ) mView = view;
        else if ( mView.getAnimation().hasStarted() ) // アニメーションが始まったらスルーさせる
            return;

        ///////////////

        Animation ActionB = AnimationUtils.loadAnimation( requireContext(), R.anim.scale_down_animation_set); // 小さく
        ActionB.setAnimationListener(new Animation.AnimationListener() { // アニメーション終了通知取得

            @Override
            public void onAnimationStart(Animation animation) { }

            @Override
            public void onAnimationEnd(Animation animation) { // 小さくなり切ったら次の元に戻るアニメーションを動かす

                Animation ActionB = AnimationUtils.loadAnimation( requireContext(), R.anim.scale_up_animation_set); // 大きさを戻す
                ActionB.setAnimationListener(new Animation.AnimationListener() { // アニメーション終了通知取得

                    @Override
                    public void onAnimationStart(Animation animation) { }

                    @Override
                    public void onAnimationEnd(Animation animation) { // 元に戻ったら本体の処理を始める
                        mHandler.post(MyFragment.this::move); // メインスレッドのViewにアクセスするメソッドを呼ぶにはハンドラーを使う
                        clickFlag = false;
                        mView = null;
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) { }
                });
                view.startAnimation( ActionB );
            }

            @Override
            public void onAnimationRepeat(Animation animation) { }
        });
        view.startAnimation(ActionB);
    }

 

やはり、ゴチャゴチャして嫌いだ。

 


過去記事が見つからなかったので追加。
場所は res:anim:scale_down_animation_set.xml

【scale_down_animation_set.xml】

< set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="@android:anim/decelerate_interpolator">

        < scale
            android:fromXScale="1.0"
            android:toXScale="0.7"
            android:fromYScale="1.0"
            android:toYScale="0.7"
            android:pivotX="50%"
            android:pivotY="50%"
            android:fillAfter="true"
            android:duration="150" />

</set>


【scale_up_animation_set.xml】

< set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="@android:anim/decelerate_interpolator">

        < scale
            android:fromXScale="0.7"
            android:toXScale="1.0"
            android:fromYScale="0.7"
            android:toYScale="1.0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:fillAfter="true"
            android:duration="150" />

</set>


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Fragment [問題発生] DoubleTap で例外停止。

2022-10-10 01:07:02 | Android studio 日記

対応「遅延処理でサブフラグメントを開く。」

 

メインフラグメントでダブルタップをして、サブフラグメントに置き換える動作で例外発生した。

今まで何日も問題なく移動して作業してメインに戻っていたのに…。
いきなり例外停止が発生した。原因が分からない。

Try-catch で捕まえてるし、極端に短い内容だけど停止する。
ダブルタップでサブフラグメントを開くものをロングプレスで開くように変更した。
問題なくフラグメントは置き換えられ、またメインに戻る。ホントに問題ない。
ダブルタップに戻すとサブが開いて画像表示完了→ 例外停止。

意味わからん。
問題ないBookmarkリストを表示するフラグメントをダブルタップで開くようにする。
例外停止…。ダブルタップのシステム処理に問題があるのだろう。

データの授受の仕方。イベントの受け取り方法の仕方。
考え付く方法を試した。時々、正常に行って戻ってくる。
やっと解放される~。ビルドし直すと例外停止。orz。

打つ手なし。
ボーっとしていて、ダブルタップで情報だけ集めて別の場所からサブフラグメントを開くか…。
だけどタイミング取れないよな~。
ん?タイミング?タイミング…。

昔、早すぎて突っ込んでクラッシュとか聞いたな~。
Hundler で遅延実行はよく使ってるしダメ元で試すか…。

200ミリ秒遅延。ビルドアップ。

クソ!
動きやがった。問題なし⁉
エミュレータの問題か?

原因は分からず仕舞い。様子見…。
あぁぁ疲れた!精神的ダメージ大きい。
二日分返せ。

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする