我有一個使用單個活動和多個片段方法的應用程式,我使用 NavController 進行導航。不幸的是,當導航到在任何類中包含 a 的RunnableFragment 時,正在創建該 Fragment 的兩個相同實體,我不明白為什么。
這是主要活動的代碼:
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
public static DB_SQLite_Helper sqLite_DB;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
getSupportActionBar().hide();
setContentView(view);
sqLite_DB = new DB_SQLite_Helper(this);
}
}
nav_graph 中的 Home-Fragment 是FR_Menu您可以在此處看到的 Fragment:
public class FR_Menu extends Fragment implements View.OnClickListener{
private FragmentMenuBinding binding;
public FR_Menu() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentMenuBinding.inflate(inflater, container, false);
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
binding.buttonExit.setOnClickListener(this);
binding.buttonTest.setOnClickListener(this);
return binding.getRoot();
}
@Override
public void onClick(View view) {
if(view.getId() == R.id.button_test) {
Navigation.findNavController(getView()).navigate(FR_MenuDirections.actionFRMenuToTest());
}
if(view.getId() == R.id.button_exit) {
getActivity().finishAndRemoveTask();
}
}
}
在這里,我只有一個OnClickListener并使用行中的 navController 導航到帶有 Runnables 的片段Navigation.findNavController(getView()).navigate(FR_MenuDirections.actionFRMenuToTest());。到現在為止還挺好。現在創建了帶有 Runnable 的 Fragment,稱為Test。在這里你可以看到這個片段的代碼:
public class Test extends Fragment {
private Handler handler = new Handler();
int helpCounterRun =0;
private boolean viewHasBeenCreated = false;
private FragmentTestBinding binding;
public Test() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentTestBinding.inflate(inflater, container, false);
viewHasBeenCreated = true;
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
countDownTime();
return binding.getRoot();
}
private void updateScreen() {
Log.e("LogTag", "Method updateScreen - this: " this);
}
private void countDownTime(){
handler.postDelayed(new Runnable() {
@Override
public void run() {
helpCounterRun ;
Log.e("LogTag", "Method run - helpCounterRun: " helpCounterRun);
Log.e("LogTag", "Method run - this: " this);
if(viewHasBeenCreated) {
countDownTime();
}
}
}, 100);
updateScreen();
}
}
onCreate在and方法旁邊,onCreateView這個 Fragment 有 2 個基本方法。在該updateScreen方法中,當前的 Fragment 被列印到控制臺。并且在該countDownTime方法中創建了一個 Runnable 并helpCounterRun增加了一個輔助變數。輔助變數的值和 Runnable 的當前實體被列印到控制臺。輸出如下所示:
2022-04-18 10:01:33.742 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 1
2022-04-18 10:01:33.743 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@78ea3f9
2022-04-18 10:01:33.745 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{706103f} (335e5b64-5e97-4f3d-ac1b-8f5a1fcc559c)}
2022-04-18 10:01:34.277 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 1
2022-04-18 10:01:34.278 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@9c893ee
2022-04-18 10:01:34.278 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{5140689} (c513c6da-fb15-4273-bea2-dfd89382d9e8) id=0x7f08013e}
2022-04-18 10:01:34.294 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 2
2022-04-18 10:01:34.305 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@f8db08f
2022-04-18 10:01:34.306 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{706103f} (335e5b64-5e97-4f3d-ac1b-8f5a1fcc559c)}
2022-04-18 10:01:34.382 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 2
2022-04-18 10:01:34.382 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@8b9ef1c
2022-04-18 10:01:34.382 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{5140689} (c513c6da-fb15-4273-bea2-dfd89382d9e8) id=0x7f08013e}
2022-04-18 10:01:34.414 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 3
2022-04-18 10:01:34.414 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@9ad8725
2022-04-18 10:01:34.415 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{706103f} (335e5b64-5e97-4f3d-ac1b-8f5a1fcc559c)}
2022-04-18 10:01:34.503 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 3
2022-04-18 10:01:34.503 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@9ae00fa
2022-04-18 10:01:34.504 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{5140689} (c513c6da-fb15-4273-bea2-dfd89382d9e8) id=0x7f08013e}
2022-04-18 10:01:34.531 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 4
2022-04-18 10:01:34.562 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@ebec6ab
2022-04-18 10:01:34.562 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{706103f} (335e5b64-5e97-4f3d-ac1b-8f5a1fcc559c)}
2022-04-18 10:01:34.611 25086-25086/com.example.game E/LogTag: Method run - helpCounterRun: 4
2022-04-18 10:01:34.611 25086-25086/com.example.game E/LogTag: Method run - this: com.example.game.Test$1@b04e108
2022-04-18 10:01:34.611 25086-25086/com.example.game E/LogTag: Method updateScreen - this: Test{5140689} (c513c6da-fb15-4273-bea2-dfd89382d9e8) id=0x7f08013e}
您可以從該updateScreen方法的輸出中看到,該 Fragment 的 2 個實體已創建并同時運行。一個具有 idTest{706103f} (335e5b64-5e97-4f3d-ac1b-8f5a1fcc559c)和另一個Test{5140689} (c513c6da-fb15-4273-bea2-dfd89382d9e8) id=0x7f08013e},因此輔助變數helpCounter在遞增之前以相同的值列印 2 次。
我的問題是為什么會這樣。我沒有看到我的代碼的任何部分明確創建了 Fragment 的 2 個實體Test。您是否知道這種奇怪行為的原因可能是什么以及我該如何解決?
提醒:沒有人知道為什么會這樣嗎?
uj5u.com熱心網友回復:
當您呼叫時setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE),您會強制您的活動進行配置更改- 從縱向更改為橫向。默認情況下,Android 將銷毀您的活動(以及其中的所有片段)并以您請求的方向重新創建它。
這就是您收到訊息的原因Method updateScreen - getActivity(): null- 由于您的配置更改,Fragment 連同它所在的 Activity 已被完全銷毀。
countDownTime()但是,即使您的片段視圖被破壞,您也永遠不會停止一遍又一遍地呼叫。這意味著您已經創建了永久記憶體泄漏。
您已經在跟蹤 Fragment 的視圖是否是通過您viewHasBeenCreated的. 這也是洗掉任何尚未通過使用運行的呼叫的適當位置falseonDestroyView()postDelayedremoveCallbacksAndMessages()
@Override
public void onDestroyView() {
super.onDestroyView();
// Reset your variable to false
viewHasBeenCreated = false;
// And clean up any postDelayed callbacks that are waiting to fire
handler.removeCallbacksAndMessages(null);
}
請注意,您不需要手動跟蹤viewHasBeenCreated- 您可以使用它getView() != null來執行相同的檢查,但通過確保您確實清理了您的Handlerin onDestroyView(),您根本不需要進行此檢查,因為您可以保證只在創建視圖時運行。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/468310.html
