背景
我遇到了一個涉及更新 Android 專案中的 Fragment 的問題。該應用程式為 D&D 玩家擲骰子。與 Java Math.random 方法相比,該專案使用Random.Org的 API來提供更大的亂數生成熵。
該應用程式顯示一個帶有視圖分頁器的選項卡布局,它在三個選項卡之間切換 - 一個用于滾動單個骰子,一個用于滾動一組骰子,一個用于顯示滾動歷史和日志資訊。Roll Die 位于位置 0,Roll Set 位于位置 1,History 位于位置 2。View Pager 使用 FragmentPagerAdapter。
History 包含兩個 TextView,我使用它們來顯示滾動結果和記錄資料,以確保與 API 的連接順利進行。資料通過兩個介面從 RollDie 和 RollSet 片段傳遞到 Main Activity。然后介面方法將資料發送到 FragmentPagerAdapter,FragmentPagerAdapter 又通過 bundle 將兩個 String ArrayLists 傳遞給 History 片段。
問題
我的問題是“歷史記錄”選項卡似乎僅在加載單個模具卷選項卡后才更新。當我擲出一個骰子然后檢查歷史頁面時,相關的 TextView 會按應有的方式顯示。但是,當我滾動一組時,歷史頁面不會更新,直到我回傳單個骰子滾動選項卡。
對此問題的任何幫助將不勝感激。相關代碼貼在下面。
來自 API 的代碼可以在Github上找到。我還遺漏了我撰寫的兩個類,稱為 Die 和 DieSet - 它們運行良好,我認為這已經足夠長了。如果有人認為這會有所幫助,我很樂意發布這些課程。
與 API 密鑰相關的代碼以及一些 IDE 生成的注釋已被省略。
主要活動
public class MainActivity extends AppCompatActivity implements DieRollFragment.RollFragmentListener, DieSetFragment.SetFragmentListener{
private static String[] key;
TabLayout tabLayout;
ViewPager viewPager;
PagerAdapter pagerAdapter;
protected void onStart() {
super.onStart();
userKeyDialog();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout = findViewById(R.id.navTabs);
viewPager = findViewById(R.id.viewPager);
pagerAdapter = new PagerAdapter(getSupportFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT, tabLayout.getTabCount());
viewPager.setAdapter(pagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
private void userKeyDialog(){
//OMITTED FOR PRIVACY REASONS
}
public static String getKey() {
//OMITTED FOR PRIVACY REASONS
}
//DieRollFragment Interface Methods
@Override
public void rollResultsUpdate(String input) {
pagerAdapter.setResults(input);
}
@Override
public void rollLogsUpdate(String input) {
pagerAdapter.setLogs(input);
}
//DieSetFragment Interface Methods
@Override
public void setResultsUpdate(String input) {
pagerAdapter.setResults(input);
}
@Override
public void setLogsUpdate(String input) {
pagerAdapter.setLogs(input);
}
}
FragmentPagerAdapter
public class PagerAdapter extends FragmentPagerAdapter {
int numOfTabs;
ArrayList<String> results;
ArrayList<String> logs;
public PagerAdapter(FragmentManager fm, int behavior, int numOfTabs) {
super(fm, behavior);
this.numOfTabs = numOfTabs;
results = new ArrayList<>();
logs = new ArrayList<>();
}
@NonNull
@Override
public Fragment getItem(int position) {
switch(position){
case(1):
return DieSetFragment.newInstance(getKey());
case(2):
return RollHistoryFragment.newInstance(results, logs);
case(0):
default:
return DieRollFragment.newInstance(getKey());
}
}
@Override
public CharSequence getPageTitle(int position){
String title;
switch(position){
case(1):
title = "Roll Set";
return title;
case(2):
title = "Results";
return title;
case(0):
default:
title = "Roll Die";
return title;
}
@Override
public int getCount() {
return 3;
}
public void setResults(String input) {
results.add(input);
}
public void setLogs(String input) {
logs.add(input);
}
}
滾動歷史片段
public class RollHistoryFragment extends Fragment{
TextView results, logs;
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
ArrayList<String> inputResults, inputLogs;
Button clearLogs;
public RollHistoryFragment() {
// Required empty public constructor
}
public static RollHistoryFragment newInstance(ArrayList<String> inputResults, ArrayList<String> inputLogs) {
RollHistoryFragment fragment = new RollHistoryFragment();
Bundle args = new Bundle();
args.putStringArrayList(ARG_PARAM1, inputResults);
args.putStringArrayList(ARG_PARAM2, inputLogs);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
inputResults = getArguments().getStringArrayList(ARG_PARAM1);
inputLogs = getArguments().getStringArrayList(ARG_PARAM2);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_roll_history, container, false);
results = view.findViewById(textViewResults);
results.setMovementMethod(new ScrollingMovementMethod());
logs = view.findViewById(textViewLogs);
logs.setMovementMethod(new ScrollingMovementMethod());
clearLogs = view.findViewById(buttonClear);
clearLogs.setOnClickListener(view1 -> {
results.setText("");
logs.setText("");
});
updateResults(inputResults);
updateLogs(inputLogs);
return view;
}
public void updateResults(ArrayList<String> input){
for (String s : input) results.append(s "\n");
}
public void updateLogs (ArrayList<String> input){
for (String s : input) logs.append(s "\n");
}
}
模輥片段
public class DieRollFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private String key;
private RollFragmentListener listener;
public DieRollFragment() {
// Required empty public constructor
}
public static DieRollFragment newInstance(String key){
DieRollFragment fragment = new DieRollFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, key);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
key = getArguments().getString(ARG_PARAM1);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_die_roll, container, false);
ImageButton rollD4 = view.findViewById(R.id.rollD4);
ImageButton rollD6 = view.findViewById(R.id.rollD6);
ImageButton rollD8 = view.findViewById(R.id.rollD8);
ImageButton rollD10 = view.findViewById(R.id.rollD10);
ImageButton rollD12 = view.findViewById(R.id.rollD12);
ImageButton rollD20 = view.findViewById(R.id.rollD20);
ImageButton rollD100 = view.findViewById(R.id.rollD100);
rollD4.setOnClickListener(view1 -> {
Die d4 = new Die(4, key);
int result = d4.makeRoll();
showAlert(result);
listener.rollResultsUpdate("Roll = " result);
listener.rollLogsUpdate(d4.getLog());
});
rollD6.setOnClickListener(view12 -> {
Die d6 = new Die(6, key);
int result = d6.makeRoll();
showAlert(result);
listener.rollResultsUpdate("Roll = " result);
listener.rollLogsUpdate(d6.getLog());
});
rollD8.setOnClickListener(view13 -> {
Die d8 = new Die(8, key);
int result = d8.makeRoll();
showAlert(result);
listener.rollResultsUpdate("Roll = " result);
listener.rollLogsUpdate(d8.getLog());
});
rollD10.setOnClickListener(view14 -> {
Die d10 = new Die(10, key);
int result = d10.makeRoll();
showAlert(result);
listener.rollResultsUpdate("Roll = " result);
listener.rollLogsUpdate(d10.getLog());
});
rollD12.setOnClickListener(view15 -> {
Die d12 = new Die(12, key);
int result = d12.makeRoll();
showAlert(result);
listener.rollResultsUpdate("Roll = " result);
listener.rollLogsUpdate(d12.getLog());
});
rollD20.setOnClickListener(view16 -> {
Die d20 = new Die(20, key);
int result = d20.makeRoll();
showAlert(result);
listener.rollResultsUpdate("Roll = " result);
listener.rollLogsUpdate(d20.getLog());
});
rollD100.setOnClickListener(view17 -> {
Die d100 = new Die(100, key);
int result = d100.makeRoll();
showAlert(result);
listener.rollResultsUpdate("Roll = " result);
listener.rollLogsUpdate(d100.getLog());
});
return view;
}
public interface RollFragmentListener{
void rollResultsUpdate(String input);
void rollLogsUpdate(String input);
}
private void showAlert(int result){
new AlertDialog.Builder(Objects.requireNonNull(getContext()))
.setTitle("You rolled a: ")
.setMessage(Integer.toString(result))
.show();
}
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if(context instanceof RollFragmentListener){
listener = (RollFragmentListener) getContext();
} else throw new RuntimeException(context.toString() " must implement RollFragmentListener");
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
}
模架片段
public DieSetFragment() {
// Required empty public constructor
}
public static DieSetFragment newInstance(String key) {
DieSetFragment fragment = new DieSetFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, key);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_die_set, container, false);
assert container != null;
editNumD4 = view.findViewById(R.id.editNumD4);
editNumD6 = view.findViewById(R.id.editNumD6);
editNumD8 = view.findViewById(R.id.editNumD8);
editNumD10 = view.findViewById(R.id.editNumD10);
editNumD12 = view.findViewById(R.id.editNumD12);
editNumD20 = view.findViewById(R.id.editNumD20);
diceSetList = new ArrayList<>();
ImageButton buttonRollSet = view.findViewById(R.id.buttonRollSet);
buttonRollSet.setOnClickListener(view1 -> rollSet(mParam1));
return view;
}
public interface SetFragmentListener{
void setResultsUpdate(String input);
void setLogsUpdate(String input);
}
public void rollSet(String key){
int numD4 = Integer.parseInt(editNumD4.getText().toString());
int numD6 = Integer.parseInt(editNumD6.getText().toString());
int numD8 = Integer.parseInt(editNumD8.getText().toString());
int numD10 = Integer.parseInt(editNumD10.getText().toString());
int numD12 = Integer.parseInt(editNumD12.getText().toString());
int numD20 = Integer.parseInt(editNumD20.getText().toString());
for(int i = 0; i<numD4; i ){
Die d4 = new Die(4,key);
diceSetList.add(d4);
}
for(int i = 0; i<numD6; i ){
Die d6 = new Die(6,key);
diceSetList.add(d6);
}
for(int i = 0; i<numD8; i ){
Die d8 = new Die(8,key);
diceSetList.add(d8);
}
for(int i = 0; i<numD10; i ){
Die d10 = new Die(10,key);
diceSetList.add(d10);
}
for(int i = 0; i<numD12; i ){
Die d12 = new Die(12,key);
diceSetList.add(d12);
}
for(int i = 0; i<numD20; i ){
Die d20 = new Die(20,key);
diceSetList.add(d20);
}
DieSet dieSet = new DieSet(diceSetList,key);
int result = dieSet.rollTotal();
listener.setLogsUpdate(dieSet.getLOG());
listener.setResultsUpdate("Set Roll = " result);
showAlert(result);
diceSetList.clear();
}
public void showAlert(int result){
new AlertDialog.Builder(Objects.requireNonNull(getContext()))
.setTitle("You rolled a: ")
.setMessage(Integer.toString(result))
.show();
}
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if(context instanceof SetFragmentListener){
listener = (SetFragmentListener) getContext();
} else throw new RuntimeException(context.toString() "must implement SetFragmentListener");
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
}
uj5u.com熱心網友回復:
經過一番作業,我找到了一個簡單的解決方案。
我從 History 片段的 onCreateView 中洗掉了對我的更新方法的呼叫,并添加了 onResume。
然后我在 onResume 中添加了一個 if 陳述句,它檢查 ArrayLists inputResults 和 inputLogs 是否不為空,然后呼叫 updateResults 和 updateLogs。然后我清除 inputResults 和 inputLogs。
修改后的代碼如下:
public void onResume() {
super.onResume();
if (inputResults != null && inputLogs != null){
updateResults(inputResults);
updateLogs(inputLogs);
}
inputResults.clear();
inputLogs.clear();
}
現在一切都按預期作業!我認為這個問題的回答令我滿意,但我不是 Android 王牌,所以如果有人對我如何改進這件事有任何建議,我愿意接受建議!
其他一些最后的注意事項:我從已棄用的 ViewPager 切換到 ViewPager2。因此,頁面配接器現在擴展了 FragmentStateAdapter。這在功能方面沒有太大變化,但使 MainActivity 代碼看起來更整潔一些。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/419194.html
標籤:
