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

android OS & iPadOS の記録。

Fragment+ViewModel [基礎] 【MyImageView.java】

2022-09-24 10:12:45 | Android studio 日記

 

基礎クラス。
Bitmap,Drawableを設定した後に画像サイズを取得したいので継承クラスを作った。


【MyImageView.java】
public class MyImageView extends androidx.appcompat.widget.AppCompatImageView {
    public MyImageView(Context context, AttributeSet attrs, int defStyle){
        super(context, attrs, defStyle);
    }
    public MyImageView(Context context, AttributeSet attrs){
        super(context, attrs);
    }
    public MyImageView(Context context){
        super(context);
    }

    private int myImageWidth = 0;
    private int myImageHeight = 0;

    @Override
    public void setImageBitmap(Bitmap bm) {
        if (bm != null) {
            myImageWidth = bm.getWidth();
            myImageHeight = bm.getHeight();
        } else {
            myImageWidth = 0;
            myImageHeight = 0;
        }
        super.setImageBitmap(bm);
    }
    @Override
    public void setImageDrawable(Drawable drawable) {
        if (drawable != null) {
            myImageWidth = drawable.getIntrinsicWidth();
            myImageHeight = drawable.getIntrinsicHeight();
        } else {
            myImageWidth = 0;
            myImageHeight = 0;
        }
        super.setImageDrawable(drawable);
    }
    public int getImageWidth() {
        return myImageWidth;
    }
    public int getImageHeight() {
        return myImageHeight;
    }
}

 


Fragment+ViewModel [基礎] GestureDetectorの組み込み。

2022-09-23 14:44:40 | Android studio 日記

フラグメントで SimpleOnGestureListener を使いたい。

前回、onTouch()をアクティビティからフラグメントに引っ張った。
その MotionEvent を SimpleOnGestureListener に渡す。ちょっと回りくどいけど。

 

【MainActivity.java】
【MyMainData.java】
【MainViewModel.java】は前回のまま。

 

【MainFragment.java】

public class MainFragment extends Fragment implements View.OnTouchListener {
    private MainViewModel mViewModel;

    // 追加部分
    private GestureDetectorCompat mDetector = null;
    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

  // 一部省略

        @Override
        public boolean onDown(MotionEvent event) {
            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent event) {

            mViewModel.getPathName().setValue("SingleTap");
            return true;
        }

    }
    // ------

    public static MainFragment newInstance(String path) {

        MainFragment mainFragment = new MainFragment();// インスタンス生成

        Bundle args = new Bundle();// Bundle にパラメータを設定
        args.putString("test", path);
        mainFragment.setArguments(args);

        return mainFragment;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    @SuppressLint({"FragmentLiveDataObserve", "UseRequireInsteadOfGet"})
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);


        // 追加。GestureDetectorのインスタンス化
        mDetector = new GestureDetectorCompat(requireContext(), new MyGestureListener());

 

        mViewModel = new ViewModelProvider((ViewModelStoreOwner) requireContext()).get(MainViewModel.class);

        //lambda
        final Observer< String> nameObserver = newName -> {
            TextView text = view.findViewById(R.id.message);
            text.setText(newName);
        };
        mViewModel.getPathName().observe((LifecycleOwner) requireContext(), nameObserver);

        Bundle args = getArguments();// Bundle にパラメータを取得
        if(args != null ){
            String path = args.getString("test");
            mViewModel.getPathName().setValue(path);
        }


        final Observer< String> dataObserver = newName -> {
            TextView text = view.findViewById(R.id.message);
            text.setText(newName);
        };
        mViewModel.getMainData().getTextData1().observe(requireActivity(), dataObserver);
        mViewModel.getMainData().getTextData1().setValue("live data 1");
    }


    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return mDetector.onTouchEvent(event); // GestureDetectorへMotionEventを渡している
    }

}

 

mDetector = new GestureDetectorCompat(requireContext(), new MyGestureListener());
 GestureDetectorをインスタンス化して、
mDetector.onTouchEvent(event)で
 MotionEventを GestureDetectorに渡している。


前回と同じにタップすると表示が変わる。
データ参照と更新は行われている。

とりあえず、エラーは出ない。

 

また、画像表示は先延ばし^^;

 


Fragment+ViewModel [基礎] ViewModelの共有化。

2022-09-23 13:06:07 | Android studio 日記

各フラグメントから共有データを取り出せるかテストする。


結果はデータをViewModelに集約できる事が分かった。
Observerを使う目安がまだよく分からないが意識しておく。

 


【MainActivity.java】は前回のまま。


【MyMainData.java】を新設。LiveDataの使用基準はよく分からない。

public class MyMainData {

    // LiveData になる宣言。
    private MutableLiveData< String> textData1 = null;
    public MutableLiveData< String> getTextData1() {
        if (textData1 == null) {
            textData1 = new MutableLiveData< String>("text data 1");
        }
        return textData1;
    }

    // LiveData にならない宣言。
    private String textData2 = "text data 2";

    public String getTextData2() {
        return textData2;
    }
    public void setTextData2(String textData2) {
        this.textData2 = textData2;
    }
}


【MainViewModel.java】 MyMainDataクラスをインスタンス化。

public class MainViewModel extends ViewModel {

//  LiveData になる
    private MutableLiveData< String> targetPath = null;
    public MutableLiveData< String> getPathName() {
        if (targetPath == null) {
            targetPath = new MutableLiveData< String>();
        }
        return targetPath;
    }


//  LiveData にならない
    private final MyMainData mainData = new MyMainData();
    public MyMainData getMainData() {
        return mainData;
    }
}

 

【MainFragment.java】 一部を抜粋。

    @SuppressLint({"FragmentLiveDataObserve", "UseRequireInsteadOfGet"})
    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mViewModel = new ViewModelProvider((ViewModelStoreOwner) requireContext()).get(MainViewModel.class);

        //lambda
        final Observer< String> nameObserver = newName -> {
            TextView text = view.findViewById(R.id.message);
            text.setText(newName);
        };
        mViewModel.getPathName().observe((LifecycleOwner) requireContext(), nameObserver);

        Bundle args = getArguments();// Bundle にパラメータを取得
        if(args != null ){
            String path = args.getString("test");
            mViewModel.getPathName().setValue(path);
        }


        // 追加。MyMainDataのtextData1の値をsetValue("live data 1")で更新。
        final Observer< String> dataObserver = newName -> {
            TextView text = view.findViewById(R.id.message);
            text.setText(newName);// 更新値を目視確認
        };
        mViewModel.getMainData().getTextData1().observe(requireActivity(), dataObserver);
        mViewModel.getMainData().getTextData1().setValue("live data 1");

    }


    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // タップされたらMyMainDataのtextData2の値を取り出しMainViewModelのtargetPathを更新させてる
        mViewModel.getPathName().setValue(mViewModel.getMainData().getTextData2());
        return false;
    }


とりあえず、エラーは出ない。

画像表示は次?

 


Fragment+ViewModel を使ったImageViewerの基幹。

2022-09-20 16:11:03 | Android studio 日記
テンプレートに書き足してテストする。

アクティビティとフラグメントのデータ渡し部分を確認する。


【MainActivity.java】
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState == null) {
MainFragment mFragment = MainFragment.newInstance("filepath");
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, mFragment)
.commitNow();

View view = (View)findViewById(R.id.container);
view.setOnTouchListener((MainFragment)mFragment);//フラグメントへタッチイベント通知。
}
}
}

 

//implements View.OnTouchListener で通知を受け取る準備。

【MainFragment.java】
public class MainFragment extends Fragment implements View.OnTouchListener {

    private MainViewModel mViewModel;

    public static MainFragment newInstance(String path) {
        MainFragment mainFragment = new MainFragment();// インスタンス生成

        Bundle args = new Bundle();// Bundle にパラメータを設定
        args.putString("test", path);
        mainFragment.setArguments(args);

        return mainFragment;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

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

        Bundle args = getArguments();// Bundle にパラメータを取得
        if(args != null ){
            String path = args.getString("test");
            TextView text = view.findViewById(R.id.message);
            text.setText(path);
        }


        mViewModel = new ViewModelProvider(this).get(MainViewModel.class);//ViewModel設定

        final Observer< String> nameObserver = new Observer< String>() {//LiveData設定
            @Override
            public void onChanged(@Nullable final String newName) {
                TextView text = view.findViewById(R.id.message);
                text.setText(newName);
            }
        };
        mViewModel.getPathName().observe(this, nameObserver);

    }


    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mViewModel.getPathName().setValue("ファイルパス");//テスト。タップで受け渡しができていれば文字が変わる。
        return false;
    }

}


【MainViewModel.java】
public class MainViewModel extends ViewModel {

    private MutableLiveData< String> targetPath;//LiveData

    public MutableLiveData< String> getPathName() {
        if (targetPath == null) {
            targetPath = new MutableLiveData< String >();
        }
        return targetPath;
    }

}


とりあえず、データの受け渡しは意外と楽そう。
タッチイベントも送信側と受信側の準備をする。という事で問題ない。

過去の日記を見ると七転八倒しているな^^;
何事も積み重ねである(笑)


次は複数のフラグメントを移動して、Assetsフォルダに用意した画像をそれぞれ表示する。

 






テンプレート(Fragment+ViewModel)

2022-09-20 15:35:22 | Android studio 日記
2021.2.1で用意されているテンプレートを使ってみる。

------
ViewModel は、ライフサイクルを意識した方法で UI 関連のデータを保存し管理するためのクラスです。
ViewModel クラスを使用すると、画面の回転などの構成の変更後にデータを引き継ぐことができます。
------ developerから引用。


UI 関連のデータは、recyclerView のリストデータやビットマップも入る?
別のFragmentでも共有できるらしいのでViewModelは覚えた方が良い。

また、ViewModelの中でLiveDataを使うことでライフサイクルの変化でも上手いことやって最新のデータを管理してくれるらしい。
Fragment間で。
メモリリークも起こらないというので合わせて覚える。説明は難解だけど使って試すしかない。