1、创建四个Fragment:Title,Question,Win,Lose
2、在res下创建一个导航图表nav,用连线表示出四个页面之间的逻辑关系:
3、给title页面添加一个图标,并且在gradle中添加dataBinding 和依赖:
buildFeatures{
dataBinding = true;
}
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
4、开始做Title页面:
Calculation Test
title image
Enter
High Score:%d
5、做Question页面:
0
1
2
3
4
5
6
7
8
9
C
OK
=
\?
Score:%d
Your Answer:
6、做win和lose页面:
lose image
win image
You Lose!
You Win!
Your Score:%d
New Record:%d
Back
7、需要创建一个ViewModel:
...
public class MyViewModel extends AndroidViewModel {
private SavedStateHandle handle;
private static String KEY_HIGH_SCORE = "key_high_score";
private static String KEY_LEFT_NUMBER = "key_left_number";
private static String KEY_RIGHT_NUMBER = "key_right_number";
private static String KEY_OPERATOR = "key_operator";
private static String KEY_ANSWER = "key_answer";
private static String SAVE_SHP_DATA_NAME = "save_shp_data_name";
private static String KEY_CURRENT_SCORE = "key_current_score";
boolean win_flag = false;
public MyViewModel(@NonNull Application application,SavedStateHandle handle){
super(application);
if (!handle.contains(KEY_HIGH_SCORE)){
SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME, Context.MODE_PRIVATE);
handle.set(KEY_HIGH_SCORE,shp.getInt(KEY_HIGH_SCORE,0));
handle.set(KEY_LEFT_NUMBER,0);
handle.set(KEY_RIGHT_NUMBER,0);
handle.set(KEY_OPERATOR,"+");
handle.set(KEY_ANSWER,0);
handle.set(KEY_CURRENT_SCORE,0);
}
this.handle = handle;
}
MutableLiveDatagetLeftNumber(){
return handle.getLiveData(KEY_LEFT_NUMBER);
}
MutableLiveDatagetRightNumber(){
return handle.getLiveData(KEY_RIGHT_NUMBER);
}
MutableLiveDatagetOperator(){
return handle.getLiveData(KEY_OPERATOR);
}
MutableLiveDatagetHighScore(){
return handle.getLiveData(KEY_HIGH_SCORE);
}
MutableLiveDatagetCurrentScore(){
return handle.getLiveData(KEY_CURRENT_SCORE);
}
MutableLiveDatagetAnswer(){
return handle.getLiveData(KEY_ANSWER);
}
void generator(){
int LEVEL = 20;
Random random = new Random();
int x,y;
x = random.nextInt(LEVEL) + 1;
y = random.nextInt(LEVEL) + 1;
if (x % 2 == 0){
getOperator().setValue(Integer.valueOf("+"));
if (x > y){
getAnswer().setValue(x);
getLeftNumber().setValue(y);
getRightNumber().setValue(x - y);
}
else {
getAnswer().setValue(y);
getLeftNumber().setValue(x);
getRightNumber().setValue(y - x);
}
}
else {
getOperator().setValue(Integer.valueOf("-"));
if (x > y){
getAnswer().setValue(x - y);
getLeftNumber().setValue(x);
getRightNumber().setValue(y);
}
else {
getAnswer().setValue(y - x);
getLeftNumber().setValue(y);
getRightNumber().setValue(x);
}
}
}
@SuppressWarnings("ConstantConditions")
void save(){
SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME,Context.MODE_PRIVATE);
SharedPreferences.Editor editor = shp.edit();
editor.putInt(KEY_HIGH_SCORE,getHighScore().getValue());
editor.apply();
}
@SuppressWarnings("ConstantConditions")
void answerCorrect(){
getCurrentScore().setValue(getCurrentScore().getValue() + 1);
if (getCurrentScore().getValue() > getHighScore().getValue()){
getHighScore().setValue(getCurrentScore().getValue());
win_flag = true;
}
generator();
}
}
8、做数据绑定:
fragment_title:
...
fragment_question:
...
...
...
fragment_win:
...
...
fragment_lose:
...
...
9、写fragment里面的代码:
TitleFragment:
...
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
MyViewModel myViewModel;
myViewModel = new ViewModelProvider(requireActivity(),new SavedStateViewModelFactory(requireActivity().getApplication(),this)).get(MyViewModel.class);
FragmentTitleBinding binding;
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_title,container,false);
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
binding.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
NavController controller = Navigation.findNavController(view);
controller.navigate(R.id.action_titleFragment_to_questionFragment);
}
});
return binding.getRoot();
// Inflate the layout for this fragment
//return inflater.inflate(R.layout.fragment_title, container, false);
}
}
QuestionFragment:
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final MyViewModel myViewModel;
myViewModel = new ViewModelProvider(requireActivity(),new SavedStateViewModelFactory(requireActivity().getApplication(),this)).get(MyViewModel.class);
myViewModel.generator();
final FragmentQuestionBinding binding;
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_question,container,false);
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
final StringBuilder builder = new StringBuilder();//创建一个可变的字符串
View.OnClickListener listener = new View.OnClickListener() {
@SuppressLint("NonConstantResourceId")
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.button0:
builder.append("0");break;
case R.id.button1:
builder.append("1");break;
case R.id.button2:
builder.append("2");break;
case R.id.button3:
builder.append("3");break;
case R.id.button4:
builder.append("4");break;
case R.id.button5:
builder.append("5");break;
case R.id.button6:
builder.append("6");break;
case R.id.button7:
builder.append("7");break;
case R.id.button8:
builder.append("8");break;
case R.id.button9:
builder.append("9");break;
case R.id.button_clear:
builder.setLength(0);break;
}
if (builder.length() == 0){
binding.textView9.setText(getString(R.string.input_indicator));
}else {
binding.textView9.setText(builder.toString());
}
}
};
binding.button0.setOnClickListener(listener);
binding.button1.setOnClickListener(listener);
binding.button2.setOnClickListener(listener);
binding.button3.setOnClickListener(listener);
binding.button4.setOnClickListener(listener);
binding.button5.setOnClickListener(listener);
binding.button6.setOnClickListener(listener);
binding.button7.setOnClickListener(listener);
binding.button8.setOnClickListener(listener);
binding.button9.setOnClickListener(listener);
binding.buttonClear.setOnClickListener(listener);
binding.buttonSubmit.setOnClickListener(new View.OnClickListener() {
@SuppressWarnings("ConstantConditions")
@Override
public void onClick(View view) {
if(builder.length() == 0){//没有输入的情况下
Toast.makeText(getActivity(), getString(R.string.input_null_message), Toast.LENGTH_SHORT).show();
return;
}
else if (Integer.valueOf(builder.toString()).intValue() == myViewModel.getAnswer().getValue()){
myViewModel.answerCorrect();
builder.setLength(0);
binding.textView9.setText(R.string.answer_correct_message);
// builder.append(getString(R.string.answer_correct_message));
}
else {
NavController controller = Navigation.findNavController(view);
if (myViewModel.win_flag){
controller.navigate(R.id.action_questionFragment_to_winFragment);
myViewModel.win_flag = false;
myViewModel.save();
}else {
controller.navigate(R.id.action_questionFragment_to_loseFragment);
}
}
}
});
return binding.getRoot();
}
}
WinFragment:
...
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
MyViewModel myViewModel = new ViewModelProvider(requireActivity(),new SavedStateViewModelFactory(requireActivity().getApplication(),this)).get(MyViewModel.class);
FragmentWinBinding binding;
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_win,container,false);
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
binding.button11.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
NavController controller = Navigation.findNavController(view);
controller.navigate(R.id.action_winFragment_to_titleFragment);
}
});
return binding.getRoot();
}
}
LoseFragment:
...
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
MyViewModel myViewModel = new ViewModelProvider(requireActivity(),new SavedStateViewModelFactory(requireActivity().getApplication(),this)).get(MyViewModel.class);
FragmentLoseBinding binding;
binding = DataBindingUtil.inflate(inflater,R.layout.fragment_lose,container,false);
binding.setData(myViewModel);
binding.setLifecycleOwner(requireActivity());
binding.button10.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
NavController controller = Navigation.findNavController(view);
controller.navigate(R.id.action_loseFragment_to_titleFragment);
}
});
return binding.getRoot();
}
}
10、MainActivity:
package com.example.calculationtest;
import ...
public class MainActivity extends AppCompatActivity {
NavController controller;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//controller = findNavController(this,R.id.fragment);
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
controller = navHostFragment.getNavController();
NavigationUI.setupActionBarWithNavController(this,controller);
}
@Override
public boolean onSupportNavigateUp() {
if (Objects.requireNonNull(controller.getCurrentDestination()).getId() == R.id.questionFragment){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.quit_dialog_title));
builder.setPositiveButton(R.string.dialog_positive_message, (dialogInterface, i) -> controller.navigateUp());
builder.setNegativeButton(R.string.dialog_negative_message, (dialogInterface, i) -> {
});
AlertDialog dialog = builder.create();
dialog.show();
}else {
controller.navigate(R.id.titleFragment);
}
return super.onNavigateUp();
}
@Override
public void onBackPressed() {
onSupportNavigateUp();
}
}
11、MyViewModel:
package com.example.calculationtest;
import ...
public class MyViewModel extends AndroidViewModel {
SavedStateHandle handle;
private static String KEY_HIGH_SCORE ="key_high_score";
private static String KEY_LEFT_NUMBER="key_left_number";
private static String KEY_RIGHT_NUMBER="key_right_number";
private static String KEY_OPERATOR = "key_operator";
private static String KEY_ANSWER= "key_answer";
private static String SAVE_SHP_DATA_NAME = "save_shp_data_name";
private static String CURRENT_SCORE = "current_score";
boolean win_flag = false;
// private String current = getApplication().getResources().getString(R.string.KEY_CURRENT_SCORE);
public MyViewModel(@NonNull Application application, SavedStateHandle handle) {
super(application);
if(!handle.contains(KEY_HIGH_SCORE)){
SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME, Context.MODE_PRIVATE);
handle.set(KEY_HIGH_SCORE,shp.getInt(KEY_HIGH_SCORE,0));
handle.set(KEY_LEFT_NUMBER,0);
handle.set(KEY_RIGHT_NUMBER,0);
handle.set(KEY_OPERATOR,"+");
handle.set(KEY_ANSWER,0);
handle.set(CURRENT_SCORE, 0);
/*
handle.set(application.getString(R.string.KEY_CURRENT_SCORE),0 );
*/
}
this.handle = handle;
}
public MutableLiveDatagetLeftNumber(){
return handle.getLiveData(KEY_LEFT_NUMBER);
}
public MutableLiveDatagetRightNumber(){
return handle.getLiveData(KEY_RIGHT_NUMBER);
}
public MutableLiveDatagetOperator(){
return handle.getLiveData(KEY_OPERATOR);
}
public MutableLiveDatagetHighScore(){
return handle.getLiveData(KEY_HIGH_SCORE);
}
public MutableLiveDatagetCurrentScore(){
return handle.getLiveData(CURRENT_SCORE);
}
public MutableLiveDatagetAnswer(){
return handle.getLiveData(KEY_ANSWER);
}
void generator(){
int LEVEL = 20;
Random random = new Random();
int x,y;
x = random.nextInt(LEVEL) + 1;
y = random.nextInt(LEVEL) + 1;
if(x%2 == 0 ){
getOperator().setValue("+");
if(x>y){
getAnswer().setValue(x);
getLeftNumber().setValue(y);
getRightNumber().setValue(x - y);
}else {
getAnswer().setValue(y);
getLeftNumber().setValue(x);
getRightNumber().setValue(y - x);
}
}
else{
getOperator().setValue("-");
if (x > y){
getAnswer().setValue(x - y);
getLeftNumber().setValue(x);
getRightNumber().setValue(y);
}else{
getAnswer().setValue(y - x);
getLeftNumber().setValue(y);
getRightNumber().setValue(x);
}
}
}
void save(){
SharedPreferences shp = getApplication().getSharedPreferences(SAVE_SHP_DATA_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = shp.edit();
editor.putInt(KEY_HIGH_SCORE, getHighScore().getValue());
editor.apply();
}
void answerCorrect() {
getCurrentScore().setValue(getCurrentScore().getValue() + 1);
if (getCurrentScore().getValue() > getHighScore().getValue()) {
getHighScore().setValue(getCurrentScore().getValue());
win_flag = true;
}
generator();
}
}
12、对一些需要汉化的资源进行汉化:
简易口算测试APP