java - 如何从活动中调用片段方法?
问题描述
我希望每个人都做得很好,我是一个初学者级别的 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
解决方案
如果你想要一个好的设计,你需要:
- 创建一个视图模型。
- 在 Fragment 中请求 Activity ViewModel,这样您将拥有与 Activity 中的 ViewModel 相同的 ViewModel。
- 从 Activity 调用 ViewModel 中的方法,这将更新 LiveData
- 观察 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
推荐阅读
- android - Android Firebase 尝试使用主题在所有用户中发送通知缺少注册错误
- reactjs - 变异状态被认为是不好的做法,但是当我提交表单时如何避免变异状态?
- android - 如何使用 MVVM 架构在 Room Android 中获取数据
- java - -Xlog 选项无效
- excel - 在 Excel vba 中计算类型变量,可能吗?
- javascript - 异步函数调用后更新 Vue 数据值
- sorting - 公式按包含时间和文本的列排序,将文本放在最后,在 Google 表格中
- regex - Searching for 2 keywords on same line in Notepad++
- python-2.7 - 如何找出默认值是否用于 Datastore ndb 属性?
- ansible - 剧本中的 Ansible 嵌套变量