如何从活动中调用fragments方法



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

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

所以我的问题是如何调用我的主活动中androidx.fragment.app.fragment包中的fragments方法我已经尝试了很多解决方案,甚至几天前它还在工作,但我想有些在我的应用程序中添加了更多的代码破坏了这一部分。我希望你们能帮助我。

主活动.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:15.927 26403-26403/com.myapp E/InputEventSender:异常调度完成信号。2021-11-10 19:15.92826403-26403/com.myapp E/MessageQueue JNI:MessageQueue异常回调:handleReceiveCallback 2021-11-10 19:19:15.92926403-26403/com.myapp E/MessageQueue JNI:java.lang.NullPointerException:尝试调用虚拟方法"void"空对象引用上的com.app.sfragments.OneFragment.increment()'网址:com.myapp.MainActivity.onKeyUp(MainActivity.java:53)在android.view.KeyEvent.dispatch(KeyEvent.java:2885)在android.app.Activity.dispatchKeyEvent(Activity.java:4175)在androidx.core.app.ComponentActivity.superDispatchKeyEvent(ComponentActivity.java:122)位于androidx.core.view.KeyEventDispatcher.dispatchKeyEvent(KeyEventDisptcher.java:84)位于androidx.core.app.ComponentActivity.dispatchKeyEvent(ComponentActivity.java:140)位于androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:599)位于androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrappr.java:59)在androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent(AppCompatDeleateImpl.java:3068)网址:com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:410)在android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:6091)在android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:55959)在android.view.ViewRootImpl$InputStage.delive(ViewRootImpl.java:5542)在android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5509)在android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5475)在android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5627)在android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5483)在android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5684)在android.view.ViewRootImpl$InputStage.delive(ViewRootImpl.java:5546)在android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5509)在android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5475)在android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5483)在android.view.ViewRootImpl$InputStage.delive(ViewRootImpl.java:5546)在android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5509)在android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5475)在android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5660)在android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:5820)在android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:3210)在android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:2752)在android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:2743)在android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:3187)在android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:143)在android.os.MessageQueue.naturePollOnce(本机方法)在android.os.MessageQueue.next(MessageQueue.java:335)在android.os.Looper.loop(Looper.java:193)在android.app.ActivityThread.main(ActivityThreads.java:7861)位于java.lang.reflect.Method.ioke(本机方法)网址:com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:600)网址:com.android.internal.os.ZygoteInit.main(ZygoteNit.java:967)2021-11-10 19:19:15.929 26403-26403/com.myapp D/AndroidRuntime:关闭VM 2021-11-10 19:15.932 26403-26403/com.myappE/AndroidRuntime:致命异常:main流程:com.myapp,PID:26403java.lang.NullPointerException:尝试在null对象上调用虚拟方法"void com.myapp.frages.OneFragment.increment()"参考网址:com.myapp.MainActivity.onKeyUp(MainActivity.java:53)在android.view.KeyEvent.dispatch(KeyEvent.java:2885)在android.app.Activity.dispatchKeyEvent(Activity.java:4175)在androidx.core.app.ComponentActivity.superDispatchKeyEvent(ComponentActivity.java:122)位于androidx.core.view.KeyEventDispatcher.dispatchKeyEvent(KeyEventDisptcher.java:84)位于androidx.core.app.ComponentActivity.dispatchKeyEvent(ComponentActivity.java:140)位于androidx.appcompat.app.AppCompatActivity.dispatchKeyEvent(AppCompatActivity.java:599)位于androidx.appcompat.view.WindowCallbackWrapper.dispatchKeyEvent(WindowCallbackWrappr.java:59)在androidx.appcompat.app.AppCompatDelegateImpl$AppCompatWindowCallback.dispatchKeyEvent(AppCompatDeleateImpl.java:3068)网址:com.android.internal.policy.DecorView.dispatchKeyEvent(DecorView.java:410)在android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:6091)在android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:55959)在android.view.ViewRootImpl$InputStage.delive(ViewRootImpl.java:5542)在android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5509)在android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5475)在android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5627)在android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5483)在android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5684)在android.view.ViewRootImpl$InputStage.delive(ViewRootImpl.java:5546)在android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5509)在android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5475)在android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5483)在android.view.ViewRootImpl$InputStage.delive(ViewRootImpl.java:5546)在android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5509)在android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5475)在android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5660)在android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:5820)在android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:3210)在android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:2752)在android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:2743)在android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:3187)在android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:143)在android.os.MessageQueue.naturePollOnce(本机方法)在android.os.MessageQueue.next(MessageQueue.java:335)在android.os.Looper.loop(Looper.java:193)在android.app.ActivityThread.main(ActivityThreads.java:7861)位于java.lang.reflect.Method.ioke(本机方法)网址:com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:600)网址:com.android.internal.os.ZygoteInit.main(ZygoteNit.java:967)2021-11-10 19:19:15.970 26403-26403/com.duadhikr I/流程:发送信号PID:26403 SIG:9

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

  1. 创建ViewModel
  2. 询问片段中的活动ViewModel,这样您将获得与"活动"中的ViewModel相同的ViewModel
  3. 从"活动"调用ViewModel中的方法,该方法将更新LiveData
  4. 观察片段中的LiveData

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

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

最新更新