首页 > 解决方案 > 如何从活动中调用片段方法?

问题描述

我希望每个人都做得很好,我是一个初学者级别的 Android 开发人员,我正在制作一个计数器 Android 应用程序,它可以使用我们设备上的音量键递增和递减。无论用户按下音量增大或减小按钮(长按)多长时间,应用程序都会增加或减少一次。

我已经在一个活动中实现了这个功能,几天后我想添加底部导航栏,所以我添加了片段并且也在 android.app.Fragment 包中实现了这一点,但由于某种原因在我的代码中我不得不改变在这个包 androidx.fragment.app.Fragment 中。

所以我的问题是如何从我的主 Activity 调用来自 androidx.fragment.app.Fragment 包的 Fragments 方法?我已经尝试了很多解决方案,即使它在几天前还可以工作,但是我猜有些在我的应用程序中添加更多代码破坏了这部分。我希望你们帮助我。

MainActivity.java

import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MenuItem;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;

import com.myapp.fragments.OneFragment;
import com.myapp.fragments.TwoFragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;


public class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {

    final Fragment fragment1 = new OneFragment();
    final Fragment fragment2 = new TwoFragment();
    final FragmentManager fm = getSupportFragmentManager();
    BottomNavigationView bottomNavigationView;
    Fragment active = fragment1;

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


        fm.beginTransaction().add(R.id.frame_layout, fragment2, "2").hide(fragment2).commit();
        fm.beginTransaction().add(R.id.frame_layout, fragment1, "1").commit();

        bottomNavigationView = findViewById(R.id.bottom_navigation_bar);
        bottomNavigationView.setOnNavigationItemSelectedListener(this);

        //End of onCreate()
    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        return true;
    }


    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        FragmentManager fm =getSupportFragmentManager();
        OneFragment oneFragment = (OneFragment) fm.findFragmentByTag("OneFragment");
        if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
            oneFragment.increment();
        }
        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            oneFragment.decrement();
        }
        return true;
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        int itemId = item.getItemId();
        if (itemId == R.id.one_fragment) {
            item.setChecked(true);
            fm.beginTransaction().hide(active).show(fragment1).commit();
            active = fragment1;
        } else if (itemId == R.id.two_fragment) {
            item.setChecked(true);
            fm.beginTransaction().hide(active).show(fragment2).commit();
            active = fragment2;
        }
        return false;

    }

    //End of MainActivity
}

One Fragment 的布局很简单,所以我认为我不必共享它,并且 java 中的代码也很简单,所以我共享代码仅用于递增,递减方法相同只是减少。

OneFragment.java

public void increment() {
    //if progress is less than or greater than goal - 1 than only increment the progress and update the progress bar
    if (progress <= goal - 1) {
        progress++;
        updateProgressBar();
    }

    //If quantity goes beyond the maximum limit of the count which is 9,999 to 10,000 return with this toast
    if (quantity > MAXIMUM_LIMIT) {
        Toast.makeText(getActivity(), "Cannot go beyond 10,000! Take a break", Toast.LENGTH_SHORT).show();
        return;
    }

    //If all the above condition does meet and not meet then increment quantity by 1
    quantity++;

    //If the user has switch on for vibration then do vibrate else don't
    if (vibrateToggleButton.isChecked()) {
        // this type of vibration requires API 29
        final VibrationEffect vibrationEffect;

        //This will vibrate in a modern way in devices which is greater or equal to Android 10 version Q API level 29
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {

            // create vibrator effect with the constant EFFECT_CLICK
            vibrationEffect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
            // it is safe to cancel other vibrations currently taking place
            vibrator.cancel();
            vibrator.vibrate(vibrationEffect);
        } else {
            //This will vibrate in a old way in devices which is lesser to Android 10 version Q API level 29
            //minimum requirement of this app is marshmallow version API 23 so this old vibration will run in those devices

            // it is safe to cancel other vibrations currently taking place
            vibrator.cancel();
            vibrator.vibrate(30);
        }
    }
    //Update the views
    display(quantity, goal);
}

一旦按下音量按钮,应用程序就会崩溃,我会得到这个 NullPointerException,如果不能正常使用,这在使用片段时很常见。递增一会出现递增问题,递减会出现递减问题##

2021-11-10 19:19:15.927 26403-26403/com.myapp E/InputEventSender:异常调度完成信号。2021-11-10 19:19:15.928 26403-26403/com.myapp E/MessageQueue-JNI:MessageQueue 回调中的异常:handleReceiveCallback 2021-11-10 19:19:15.929 26403-26403/com.myapp E/MessageQueue- JNI:java.lang.NullPointerException:尝试在 android 的 com.myapp.MainActivity.onKeyUp(MainActivity.java:53) 的空对象引用上调用虚拟方法“void com.app.fragments.OneFragment.increment()”。 view.KeyEvent.dispatch(KeyEvent.java:2885) at android.app.Activity.dispatchKeyEvent(Activity.java:4175) at androidx.core.app.ComponentActivity.superDispatchKeyEvent(ComponentActivity.java:122) at androidx.core.view .KeyEventDispatcher.dispatchKeyEvent(KeyEventDispatcher.java:84) 在 androidx.core.app.ComponentActivity。RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:600) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967) 2021-11-10 19:19:15.970 26403-26403/com.duadhikr I/过程:发送信号。PID:26403 SIG:9

标签: javaandroidandroid-studioandroid-fragmentsandroid-activity

解决方案


如果你想要一个好的设计,你需要:

  1. 创建一个视图模型。
  2. 在 Fragment 中请求 Activity ViewModel,这样您将拥有与 Activity 中的 ViewModel 相同的 ViewModel。
  3. 从 Activity 调用 ViewModel 中的方法,这将更新 LiveData
  4. 观察 Fragment 中的 LiveData。

https://developer.android.com/topic/libraries/architecture/viewmodel https://developer.android.com/topic/libraries/architecture/livedata

这是两个片段之间共享的示例。 https://developer.android.com/topic/libraries/architecture/viewmodel#sharing


推荐阅读