简体   繁体   English

按下按钮时的随机活动

[英]Random activity when button pressed

I would like to make a game, if i press play button, random level (activity) will open.我想做一个游戏,如果我按下播放按钮,随机关卡(活动)将打开。 I got code for this: https://stackoverflow.com/a/29579373/13101103 This is working, but i would like to edit, example, all levels have 2 different answer, answer1 is fail, answer2 is pass the level, if user pass level1, and in level2 fail, than go back to mainactivity, and if start again, then the passed levels will not show again.我得到了这个代码: https://stackoverflow.com/a/29579373/13101103这是有效的,但我想编辑,例如,所有级别都有2个不同的答案,answer1是失败,answer2是通过级别,如果用户通过 level1,在 level2 失败,然后 go 回到 mainactivity,如果重新启动,则通过的级别将不会再次显示。

Example: There are 5 levels, user start random level, example level3, it passed, go to next random level, example level2, it pass, go to next... level4, it failed, go back to mainactivity, user start again, but the already passed levels will not show, only unpassed... example start level3... if passed then go to level1....示例:有5个级别,用户启动随机级别,例如级别3,它通过了,go到下一个随机级别,例如级别2,它通过,go到下一个...级别4,它失败了,Z34D1F91FB2E,514B857BZ返回到主活动但是已经通过的级别将不会显示,只有未通过...示例开始级别 3...如果通过然后 go 到级别 1...。

How can i edit this code for my solution?如何为我的解决方案编辑此代码? Can somebody give me some tips?有人可以给我一些提示吗? Because in this if i go back to mainactivity and start again, then it start with all levels... I tried to edit, but i'm stucked and not works...因为在此,如果我 go 回到 mainactivity 并重新开始,那么它会从所有级别开始......我试图编辑,但我被卡住了,无法工作......

Plus i would like to save progress when user leave the app.另外,我想在用户离开应用程序时保存进度。 In sharedpreferences how can i save the passed levels (arraylist)....?在 sharedpreferences 中,我如何保存传递的级别(arraylist)......?

MainActivity:主要活动:

enter code here

Button level1Button = findViewById(R.id.level1Button);
    level1Button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // We are creating a list, which will store the activities that haven't been opened yet
            ArrayList<Class> activityList = new ArrayList<>();
            activityList.add(Level1Activity.class);
            activityList.add(Level2Activity.class);
            activityList.add(Level3Activity.class);
            activityList.add(Level4Activity.class);
            activityList.add(Level5Activity.class);

            Random generator = new Random();
            int number = generator.nextInt(5) + 1;

            Class activity = null;

            // Here, we are checking to see what the output of the random was
            switch(number) {
                case 1:
                    activity = Level1Activity.class;
                    // We are adding the number of the activity to the list
                    activityList.remove(Level1Activity.class);
                    break;
                case 2:
                    activity = Level2Activity.class;
                    activityList.remove(Level2Activity.class);
                    break;
                case 3:
                    activity = Level3Activity.class;
                    activityList.remove(Level3Activity.class);
                    break;
                case 4:
                    activity = Level4Activity.class;
                    activityList.remove(Level4Activity.class);
                    break;
                default:
                    activity = Level5Activity.class;
                    activityList.remove(Level5Activity.class);
                    break;
            }
            // We use intents to start activities
            Intent intent = new Intent(getBaseContext(), activity);
            // `intent.putExtra(...)` is used to pass on extra information to the next activity
            intent.putExtra("ACTIVITY_LIST", activityList);
            startActivity(intent);
        }
    });

Level1Activity:一级活动:

enter code here
failbutton1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v){
            ArrayList<Class> activityList = new ArrayList<>();
            activityList.add(Level1Activity.class);
            Bundle extras = getIntent().getExtras();
            activityList = (ArrayList<Class>) extras.get("ACTIVITY_LIST");


            //Class activity = null;


            Intent intent = new Intent(Level1Activity.this, Main2Activity.class);
            intent.putExtra("ACTIVITY_LIST", activityList);
            startActivity(intent);
        }
    });

    buttonlevel1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ArrayList<Class> activityList = new ArrayList<>();
            Bundle extras = getIntent().getExtras();
            activityList = (ArrayList<Class>) extras.get("ACTIVITY_LIST");

            if(activityList.size() == 0) {
                // Do something when after all activities have been opened
                //startActivity(new Intent(Level1Activity.this, Main2Activity.class));

                //Intent intent = new Intent(Level1Activity.this, Main2Activity.class);
                //intent.putExtra("ACTIVITY_LIST", activityList);
                //startActivity(intent);
            } else {
                // Now, the random number is generated between 1 and however many
                // activities we have remaining
                Random generator = new Random();
                int number = generator.nextInt(activityList.size()) + 1;

                Class activity = null;

                // Here, we are checking to see what the output of the random was
                switch(number) {
                    case 1:
                        // We will open the first remaining activity of the list
                        activity = activityList.get(0);
                        // We will now remove that activity from the list
                        activityList.remove(0);
                        break;
                    case 2:
                        // We will open the second remaining activity of the list
                        activity = activityList.get(1);
                        activityList.remove(1);
                        break;
                    case 3:
                        // We will open the third remaining activity of the list
                        activity = activityList.get(2);
                        activityList.remove(2);
                        break;
                    case 4:
                        // We will open the fourth remaining activity of the list
                        activity = activityList.get(3);
                        activityList.remove(3);
                        break;
                    default:
                        // We will open the fifth remaining activity of the list
                        activity = activityList.get(4);
                        activityList.remove(4);
                        break;
                }

                // Note: in the above, we might not have 3 remaining activities, for example,
                // but it doesn't matter because that case wouldn't be called anyway,
                // as we have already decided that the number would be between 1 and the number of
                // activities left.


                // Starting the activity, and passing on the remaining number of activities
                // to the next one that is opened
                Intent intent = new Intent(getBaseContext(), activity);
                intent.putExtra("ACTIVITY_LIST", activityList);
                startActivity(intent);
            }
        }
    });

level2, level3.... is same just different id-s level2, level3.... 相同,只是 id-s 不同

I'd suggest using the Singleton pattern to handle passing data between activities.我建议使用Singleton 模式来处理活动之间的数据传递。

You can pass the list by intent's putExtra() or by SharedPreferences but with a Singleton class, it looks much better and easier to manipulate your data because they are encapsulated .您可以通过意图的putExtra()SharedPreferences传递列表,但使用Singleton class,看起来更好更容易操作您的数据,因为它们是封装的。 So much so in your situation where you want to save your levels' states (eg when they are already completed).在您想要保存关卡状态的情况下(例如,当它们已经完成时)非常重要。

However, if you really insist on using SharedPreferences to save the list then I suggest converting it to Json by using Gson .但是,如果您真的坚持使用SharedPreferences来保存列表,那么我建议您使用Gson Json (Check below my answer on how to implement this.) (在我的回答下面查看如何实现这一点。)

As I said, I'd use the Singleton pattern to avoid creating unnecessary boilerplate code and to encapsulate the levels' states.正如我所说,我会使用Singleton模式来避免创建不必要的样板代码并封装关卡的状态。

LevelManager class (the singleton) LevelManager class (单例)

final class LevelManager {

    // constants
    private static final String LEVELS_SHARED_PREFERENCES_NAME = "app_name.LEVELS";

    // variables
    private static LevelManager instance;
    private List<Class> levels;
    private SharedPreferences sharedPreferences;

    private LevelManager(Context context) {
        sharedPreferences =
                context.getSharedPreferences(LEVELS_SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        levels = new ArrayList<>();
        initializeList();
    }

    private void initializeList() {
        // Initialize levels, ie. add levels that are not yet completed/passed
        // Check in SharedPreferences if level has already been completed
        boolean alreadyPassed;

        alreadyPassed = sharedPreferences.getBoolean(Level1Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level1Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level2Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level2Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level3Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level3Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level4Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level4Activity.class);

        alreadyPassed = sharedPreferences.getBoolean(Level5Activity.class.getSimpleName(), false);
        if (!alreadyPassed) levels.add(Level5Activity.class);
    }

    static LevelManager getInstance(Context context) {
        if (instance == null) {
            instance = new LevelManager(context);
        }
        return instance;
    }

    Class getRandomLevel() {
        if (levels.isEmpty()) {
            return null; // Return null if all levels are already completed
        }
        Collections.shuffle(levels);
        return levels.get(0);
    }

    void saveLevelState(Class levelClass, boolean passed) {
        sharedPreferences.edit().putBoolean(levelClass.getSimpleName(), passed).apply();
        if (passed) {
            // Remove level from list if user passed it so that it won't
            // be included in next levels
            levels.remove(levelClass);
        }
    }

    void reset() {
        // Clears all entries in SharedPreferences and re-initialize list
        sharedPreferences.edit().clear().apply();
        initializeList();
    }

}


Inside onCreate in MainActivity MainActivity 中的 onCreate 内部

// Get LevelManager singleton instance
final LevelManager levelManager = LevelManager.getInstance(this);

Button startButton = findViewById(R.id.startButton);
startButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Get next random level
        Class levelToStart = levelManager.getRandomLevel();

        // If all levels are already completed
        if (levelToStart == null) {
            Toast.makeText(MainActivity.this, "All levels are completed!",
                    Toast.LENGTH_LONG).show();
            return;
        }

        Intent intent = new Intent(MainActivity.this, levelToStart);
        startActivity(intent);
    }
});

// I added a new button to reset all levels
Button resetButton = findViewById(R.id.resetButton);
resetButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Use the method reset() from LevelManager to restart everything
        levelManager.reset();
        Toast.makeText(MainActivity.this, "All levels have been reset!",
                Toast.LENGTH_LONG).show();
    }
});


Inside of onCreate on each Level Activity每个 Level Activity 的 onCreate 内部

// Get LevelManager
final LevelManager levelManager = LevelManager.getInstance(this);

// I created two buttons to simulate pass and fail
Button pass = findViewById(R.id.passButton);
Button fail = findViewById(R.id.failButton);

pass.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Save state (Don't forget to change 'N' below)
        levelManager.saveLevelState(LevelNActivity.class, true);

        // Get next level
        Class levelToStart = levelManager.getRandomLevel();

        // Check if all are levels already completed
        if (levelToStart == null) {
            Toast.makeText(LevelNActivity.this, "Completed all levels",
                    Toast.LENGTH_LONG).show();
            finish(); // Must implement to avoid going back to previous level (ie. Activity)
            return;
        }

        Intent intent = new Intent(LevelNActivity.this, levelToStart);
        startActivity(intent);
        finish();
    }
});

fail.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        finish();
    }
});


As you can see, you can simply use the finish() method if the user failed the level whereas you use the code below to proceed to the next level:如您所见,如果用户未通过该级别,您可以简单地使用finish()方法,而您使用下面的代码进入下一个级别:

// Get LevelManager
LevelManager levelManager = LevelManager.getInstance(this);

// Set that the user passed this level (Change 'N' to the current level we are in)
levelManager.saveLevelState(LevelNActivity.class, true);

// Get next level
Class nextLevel = levelManager.getRandomLevel();

// If all levels are completed then 'nextLevel' will be null
if (nextLevel == null) {
    // ...
}

// Start next level and finish current
Intent intent = new Intent(this, nextLevel);
startActivity(intent);
finish();

Note: To avoid calling finish() explicitly when starting the next level, you can put android:noHistory="true" in your levels' activity tag inside your manifest file.注意:为避免在开始下一个关卡时显式调用finish() ,您可以将android:noHistory="true"放在清单文件中关卡的活动标签中。



How to save list to SharedPreferences by converting it to Json using Gson如何通过使用 Gson 将列表转换为 Json 来将列表保存到 SharedPreferences

To actually use Gson , you'll have to add implementation 'com.google.code.gson:gson:2.8.6' inside your app gradle dependencies. To actually use Gson , you'll have to add implementation 'com.google.code.gson:gson:2.8.6' inside your app gradle dependencies.

Also, there's a problem on Gson when parsing Class objects to Json : You need to create your own serializer and deserializer for these objects and register it to your GsonBuilder .此外,在将Class对象解析为Json Gson时,Gson 存在问题:您需要为这些对象创建自己的序列化器和序列化器并将其注册到您的GsonBuilder

ClassAdapter class (this is where we create our own custom serializer and deserializer for Class objects) ClassAdapter class (这是我们为 Class 对象创建自己的自定义序列化器和反序列化器的地方)

public class ClassAdapter implements JsonSerializer<Class>, JsonDeserializer<Class> {

    @Override
    public JsonElement serialize(Class src, Type typeOfSrc, JsonSerializationContext context) {
        // Get our class 'src' name
        return new JsonPrimitive(src.getName());
    }

    @Override
    public Class deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        try {
            // Get class
            return Class.forName(json.getAsString());
        } catch (ClassNotFoundException e) {
            // If class could not be found or did not exists, handle error here...
            e.printStackTrace();
        }
        return null;
    }

}

Here's a sample usage of saving a list to SharedPreferences by Json using Gson :这是Json使用Gson将列表保存到SharedPreferences的示例用法:

// Create new GsonBuilder and register our adapter for Class objects
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Class.class, new ClassAdapter());

// Initialize our list of levels (ie. classes)
List<Class> classes = new ArrayList<>();
classes.add(Level1Activity.class);
classes.add(Level2Activity.class);
classes.add(Level3Activity.class);
classes.add(Level4Activity.class);
classes.add(Level5Activity.class);

// Create Gson from GsonBuilder and convert list to json
Gson gson = gsonBuilder.create();
String json = gson.toJson(classes);

// Save json to SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("app_name", MODE_PRIVATE);
sharedPreferences.edit().putString("levels", json).apply();

And to retrieve the list back:并检索列表:

// Retrieve json from SharedPreferences
SharedPreferences sharedPreferences = getSharedPreferences("app_name", MODE_PRIVATE);
String json = sharedPreferences.getString("levels", null);

// Handle here if json doesn't exist yet
if (json == null) {
    // ...
}

// Create new GsonBuilder and register our adapter for Class objects
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Class.class, new ClassAdapter());

// Create Gson from GsonBuilder and specify type of list
Gson gson = gsonBuilder.create();
Type type = new TypeToken<ArrayList<Class>>(){}.getType();

// Convert json to list
List<Class> classes = gson.fromJson(json, type);

I hope you gained valuable tips to tackle this problem, And as always, happy coding!我希望你获得了解决这个问题的宝贵技巧,并且一如既往地快乐编码!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM