Andriod studio大作业,毕业设计------完整项目(1)

Andriod studio大作业,毕业设计------完整项目

汉字小测试app

想看完整教程和成果展示关注哔哩哔哩up主: Alvin_Han233

写在前面:作者本人澳洲大学毕业,下半年再出去读研,回国隔离的时候太无聊就录了一个这个项目的demo,结果我没想到的是要代码的人还挺多。我也是百忙(我现在既工作又上学)之中抽出了点时间做的视频,写的文章。喜欢的话关注一波up (ღ( ´・ᴗ・` ))。这个app是在本人大四上学期的时候做的,隔得时间有点久,可能有些生疏。但up保证这个app的代码绝对无bug,能跑通!

1. 首先六个page,六个activity:
-MainActivity就是主页;
-GameActivity就进入了quiz的界面;
-SettingActivity是设置难中易的界面;
-TwitterActivity是点完post to 推t之后的界面;
-HighscoreActivity是高分页(这里我用了一点数据库SQL语言-- 我们的作业要求);
-ResultActivity是每次玩完的得分展示。

此外每次的得分都可以post到推t上,我们需要创建一个resource folder,把Dummy(此项目用的账号)的Token,key都放进这个文件中,才能用推*这个功能。这块代码我不会发的(别打我)没经过老师允许,不能发这个。

MainActivity:
在主页中,我们可以点击跳转到setting,play,highscore页,下面的instruction用了dialog实现的。
level的设置----在settingpage中用了一个intent,再把button点击的level放进intent中,key就叫"level",mainactivity就得到了level。

package com.example.educationalapp;

import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private String level;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Bundle levelData = getIntent().getExtras();
        if (levelData == null) {
            return;
        }

        // get the level from setting page
        level = levelData.getString("level", "Medium");
        TextView currentLevel = findViewById(R.id.CurrentLevel);
        currentLevel.setText(level);  // update the text, display the level
    }

    // To enable the menu, in mainActivity add the following callback to inflate the menu
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

    // go to setting page
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (item.getItemId() == R.id.add_item) {
            Intent intent = new Intent(this, SettingActivity.class);
            startActivity(intent);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    // if clicking on play button, go to Game page
    public void onClickPlay(View view) {
        Intent intent = new Intent(MainActivity.this, GameActivity.class);
        intent.putExtra("level", level);
        setResult(RESULT_OK, intent);
        startActivity(intent);
    }

    // go to high score page
    public void onClickhs(View view) {
        Intent intent = new Intent(this, HighScoreActivity.class);
        startActivity(intent);
    }

    // show the instructions
    public void instructions(View v) {
        AlertDialog dialog = new AlertDialog.Builder(this).create();
        dialog.setTitle("Instructions");
        dialog.setMessage("Here is the instruction" +
                "\n\n>1.  You need click setting button to select difficulty of the quiz" +
                "\n\n> 2. You have 50 seconds to finish the quiz. Once timeing up, the app will automatically display result page." +
                "\n\n> 3. After the quiz, you can send to twitter or not." +
                "\n\n> 4. Clicking high score button to show history high score.");
        dialog.setButton(AlertDialog.BUTTON_POSITIVE, "Dismiss",
                (dialog1, which) -> dialog1.dismiss());
        dialog.show();
    }
}

SettingActivity
setting activity 中用 level = button.getText().toString();来探测user按了哪个键,再把level放进intent里。

package com.example.educationalapp;

import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

public class SettingActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_setting);

        Button medium_btn = findViewById(R.id.medium_btn);

        ActionBar actionBar = getSupportActionBar();
        assert actionBar != null;
        // set the behaviour sa same as bottom back button
        actionBar.setDisplayShowHomeEnabled(true);
        actionBar.setDisplayUseLogoEnabled(true);
        actionBar.setDisplayHomeAsUpEnabled(true);
        Intent intent = getIntent();
        boolean default1 = intent.getBooleanExtra("default", false);

        if (default1) {    // the default level is medium
            onClickLevel(medium_btn);
        }

    }

    // using the bardware "Back" button to cancel adding a new item
    @Override
    public void onBackPressed() {
        Toast.makeText(this, "Nothing pressed", Toast.LENGTH_SHORT).show();
        super.onBackPressed();
    }

    // if clicking a level, jump to home page
    public void onClickLevel(View view) {
        Button button = (Button) view;
        String level;
        level = button.getText().toString();
        Intent intent = new Intent(SettingActivity.this, MainActivity.class);
        intent.putExtra("level", level);
        setResult(RESULT_OK, intent);
        startActivity(intent);
    }
}

GameActivity
之后就是最复杂的GameActivity了

  1. 我编写(网上抄的)了一个可以产生随机且不重复的函数randomCommon 来产生0-10上的一个数。我的题库一共有30道,序号0-9是easy的题;10-19是medium的题;20-29是hard的题。如果用户按了easy,那么第一个index就是从0开始数,显示的题是0+random number;如果用户按了medium,那么第一个index就是从10开始数,显示的题是10+random number;hard同理。听懂的打1[doge]
  2. 我把所有的题和答案都放进了xml中,因为老师说这样项目执行效率更高 (我虽然不知道为什么效率更高,但我知道照老师说的做分数更高),开始的时候我是把题和答案放进了Game.java这个file中,但我后来改了。
  3. count down timer(倒计时器)我是用的andriod studio自带的倒计时器,我设置了计时器的时间间隔,一个计时多久。onFinish中,若时间到了,就跳转到ResultPage。我编写了一个updateCountDownText函数用了更新倒计时的字体,最后十秒的时候字体会变红。
  4. Question.java中getCoorectAnswer用来得到QuestionNum对应的答案;Game.java中checkCorrect用来判断我选的答案是否正确,正确的话mScore+1
  5. updateQuestion中调用两个函数:showMainImage和showRadioButtonAnswers。看名字你们也知道他们是干嘛的吧。怎么使选项也是随机的呢?????我们之前写的choiceSequence又排上用场了! .getChoice得到的是一个二维数组,先用QuestionNum规定是哪道题,再用随机产生的id来指定是哪个选项
  6. 此外,本项目还有一个亮点!我这个app用了sensor。做题的时候长按屏幕就会返回home页,Android有很多gesture的包

上代码!

package com.example.educationalapp;

import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.squareup.seismic.ShakeDetector;

import java.util.Locale;

public class GameActivity extends AppCompatActivity implements ShakeDetector.Listener {
    private final Game game = new Game();

    private static final long COUNTDOWN_IN_MILLIES = 50000;  // Pre-defined time
    private ColorStateList textColorDefaultCd;
    private CountDownTimer countDownTimer;
    private long timeLeftInMillis;
    private TextView textViewCountDown;

    private ImageView mQuizImage;
    private String mAnswer;
    private int mScore = 0;
    private int mQuizNum = 1;
    private int QuestionNum;
    private int initialNum;
    private TextView mQuizNumView;

    private int index;

    private final Questions mQuestions = new Questions();  // mQuestion is object; Question is class
    private String[] mCorrectAnswer;
    private String[] mImage;
    // initialize 2-dimension string array
    private final String[][] mChoice = {{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"},{"a", "a", "a"}};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);

        Bundle levelData = getIntent().getExtras();
        if (levelData == null) {
            return;
        }

        // randomize the question's sequence
        int[] questionSequence = randomCommon(0,11,10);

        // select difficulty based on clicked button
        String level = levelData.getString("level", "Medium");
        initialNum = game.mQuestionSelect(level);

        // the current question number
        QuestionNum = initialNum + questionSequence[index] - 1;

        mQuizNumView = findViewById(R.id.quiznum_textview);
        textViewCountDown = findViewById(R.id.text_view_countedown);
        mQuizImage = findViewById(R.id.quiz_image);

        // get string resource from XML
        // get string from xml: mchoices, mAnswers, mImages
        String[] mChoices_3items = getResources().getStringArray(R.array.mChoice);
        mCorrectAnswer = getResources().getStringArray(R.array.mCorrectAnswer);
        mImage = getResources().getStringArray(R.array.mImage);

        // split mChoice into three choices by comma
        // the pass one choice array into mChoice
        for (int i = 0; i < 30; i ++) {
            mChoice[i] = mChoices_3items[i].split(",");
        }

        textColorDefaultCd = textViewCountDown.getTextColors();
        updateQuestion();
        Button submit = findViewById(R.id.button_submit);

        // once this activity is called, start counting down
        timeLeftInMillis = COUNTDOWN_IN_MILLIES;

        // shake detecter
        // it will implement hearShake()
        SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        ShakeDetector shakeDetector = new ShakeDetector(this);
        shakeDetector.start(sensorManager);

        startCountDown();   // start count down once create this activity


        submit.setOnClickListener(v -> {  // Quiz logic

            if (game.checkCorrect(mAnswer, QuestionNum,mCorrectAnswer)) {   // call the method by object
                displayToastCorrectAnswer();
                mScore++;
            } else {
                displayToastWrongAnswer();
            }

            SystemClock.sleep(500);
            int numQuestion = mQuestions.getLength(mImage) / 3 - 1;  // this number is 9 always

            // index % 10 is the index in every 10 question; recall that QuestionNum is 0-30
            if (game.checkLast(numQuestion, index % 10)) {    // if approach the last quetion (call the method by object)
                pauseCountDown();

                // jump into Result Activity
                Intent intent_result = new Intent(GameActivity.this, ResultActivity.class);
                intent_result.putExtra("totalQuestions", mQuestions.getLength(mImage) / 3);
                intent_result.putExtra("finalScore", mScore);
                startActivity(intent_result);

                index = 0;   // initialize all into zero
                mQuizNum = 0;
                mScore = 0;
            } else {
                // if not the last question index + 1
                index++;
                QuestionNum = initialNum + questionSequence[index] - 1;
                mQuizNum++;

                updateQuestion();  // if game reach at the last question, the app wont update display
                Log.i("TestRandom", String.valueOf(QuestionNum));  // it is good to include in code review
            }
        });

        // sensor programming
        // learn from: https://developer.android.com/training/gestures/detector
        mQuizImage.setOnTouchListener(new View.OnTouchListener() {
            GestureDetector gestureDetector = new GestureDetector(getApplicationContext(), new GestureDetector.SimpleOnGestureListener() {
                @Override
                public void onLongPress(MotionEvent e) {
                    pauseCountDown();
                    Intent intent_home = new Intent(GameActivity.this, MainActivity.class);  // Long press to go to home page
                    startActivity(intent_home);
                    super.onLongPress(e);
                }
            });

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                gestureDetector.onTouchEvent(event);
                return false;
            }
        });

    }

    // generate random and unique integer array, range from 1-10 (minus 1 later)
    public static int[] randomCommon(int min, int max, int n){

        int[] result = new int[n];
        int count = 0;
        while(count < n) {
            int num = (int) (Math.random() * (max - min)) + min;   // generate random integer inside the range
            boolean flag = true;
            for (int j = 0; j < n; j++) {   // if the generated integer is not inside the list, append it into list
                if(num == result[j]){
                    flag = false;
                    break;
                }
            }
            if(flag){
                result[count] = num;
                count++;
            }
        }
        return result;
    }


    // implement shakeListener
    // android studio is not sensitive, you have to shake it very very very strong to see the result
    @Override
    public void hearShake() {
        Toast.makeText(getApplicationContext(), "The answer is " + mQuestions.getCoorectAnswer(mCorrectAnswer,QuestionNum), Toast.LENGTH_SHORT).show();   // shake to show the answer
    }


    // clock pause function
    private void pauseCountDown() {
        countDownTimer.cancel();
    }

    // startDown(method)
    private void startCountDown() {
        countDownTimer = new CountDownTimer(timeLeftInMillis, 1000) {  // the first parameter is the limitation of countdown; the second parameter is the time interval
            @Override
            public void onTick(long millisUntilFinished) {
                timeLeftInMillis = millisUntilFinished; // assign the boundary
                updateCountDownText();
            }

            @Override
            public void onFinish() {    // if time up, jump to other activity and stop the clock
                timeLeftInMillis = 0;
                updateCountDownText();
                Toast.makeText(GameActivity.this, "Times up", Toast.LENGTH_LONG).show();

                // if times up jump into result page and while store the result
                Intent intent_result = new Intent(GameActivity.this, ResultActivity.class);
                intent_result.putExtra("totalQuestions", mQuestions.getLength(mImage) / 3);
                intent_result.putExtra("finalScore", mScore);
                startActivity(intent_result);
                SystemClock.sleep(500);
            }
        }.start();  //start countdown immediately once creating it.
    }

    // this method is used to update count down timer
    private void updateCountDownText() {
        int minutes = (int) (timeLeftInMillis / 1000) / 60;   // this is minutes
        int seconds = (int) (timeLeftInMillis / 1000) % 60;   // this is seconds

        String timeFormatted = String.format(Locale.getDefault(), "%02d:%02d", minutes, seconds);
        textViewCountDown.setText(timeFormatted);  // update the text

        if (timeLeftInMillis < 10000) {   // if the time is less than 10 second, text turns red
            textViewCountDown.setTextColor(Color.RED);
        } else {
            textViewCountDown.setTextColor(textColorDefaultCd);
        }
    }

    // 2 methods below to show if answer is correct or not
    private void displayToastCorrectAnswer() {
        Toast.makeText(GameActivity.this, "Perfect!", Toast.LENGTH_SHORT).show();
    }
    private void displayToastWrongAnswer() {
        Toast.makeText(GameActivity.this, "Oh nooo!", Toast.LENGTH_SHORT).show();
    }

    // method to update the display
    private void updateQuestion() {
        LinearLayout answer_layout = findViewById(R.id.answer_layout);
        answer_layout.removeAllViews();  // before view the new question we need remove the old questions
        mAnswer = "";

        mQuizNumView.setText(mQuizNum + "/" + mQuestions.getLength(mImage) / 3);    // display the number of current quiz

        showRadioButtonAnswers(QuestionNum);  // call the defined function to update the answers
        showMainImage();  // display chinese character
        ScrollView sv = findViewById(R.id.scrollView);
        sv.smoothScrollTo(0, 0);
    }

    // method to show the image
    private void showMainImage() {
        String img = mQuestions.getImage(mImage,QuestionNum);  // get the image names
        mQuizImage.setImageResource(getResources().getIdentifier(img, "drawable", getPackageName()));   // display the characters
    }

    // method to show radio button answers
    private void showRadioButtonAnswers(int qnum) {
        int choiceIndex;
        final LinearLayout answerLayout = findViewById(R.id.answer_layout);
        RadioGroup rg = new RadioGroup(this);
        rg.setOrientation(RadioGroup.VERTICAL);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,  // HEIGHT
                LinearLayout.LayoutParams.WRAP_CONTENT   // WIDTH
        );
        rg.setLayoutParams(lp);
        rg.setPadding(0, 0, 0, 0);   // to ensure the choices are in the center

        final RadioButton[] rb1 = new RadioButton[3];  // create a RadioButton array, 3 value button

        int[] choiceSequence = randomCommon(0,4,3);   // randomize the question's sequence, generate a random choice sequence

        for (int i = 0; i <= 2; i++) {
            rb1[i] = new RadioButton(this);
            choiceIndex = choiceSequence[i] - 1;   // generate random choice index, select random choice from one string array
            rb1[i].setText(mQuestions.getChoice(mChoice,qnum)[choiceIndex]);  // set the three choices side radio button
            rb1[i].setTextColor(Color.BLACK);
            rb1[i].setTextSize(25);
            rb1[i].setId(i);
            rb1[i].setWidth(900);
            rg.addView(rb1[i]);  // add into Radio button view group
        }

        rg.setOnCheckedChangeListener((group, id) -> {
            id = choiceSequence[id] - 1;   // here is my very very smart move!!! specify the id into random consequence
            mAnswer = mQuestions.getChoice(mChoice,QuestionNum)[id];
        });
        answerLayout.addView(rg);  //the method make layout add to linear
    }

    // if hardware press the back button, stop the watch.
    @Override
    protected void onPause() {
        super.onPause();
        pauseCountDown();
    }
}

这篇文章就这么多了,大家喜欢的话,三联一波,咱们下篇再见!

你可能感兴趣的:(android,android,studio,java)