【问题标题】:Have a single instance of a Class有一个类的单个实例
【发布时间】:2017-01-11 11:20:01
【问题描述】:

概述

我有一个游戏,它使用ViewPager 来显示玩家可以购买的许多地雷。


问题

我创建了一个User 类来帮助我在其中存储所有用户的信息。

其中一个值是gold,用于购买地雷。 事实是,我不知道在哪里创建用户(怀疑MainActivity以及如何从MineFragment访问这个新用户的信息,其中是ViewPager中每一页的代码。

注意:我不想将用户对象传递给片段或任何其他类。我希望能够创建单个用户的实例,然后能够从我的代码中的任何位置访问该用户的所有数据,但在这种情况下,我关心从片段(Minefragment)访问它们。


用户

public class User {

private String mName;
private int mGold;
private int mExperience;
private int mExperienceLevel;

public User(String name){
    mName = name;
    mGold = 0;
    mExperience = 0;
    mExperienceLevel = 1;
}

// Getters & Setters
[...]

}


我的片段

public class MineFragment extends Fragment {
// Store instance variables
[...]

private User mUser;

private Button mineUnlockButton;
private View overlay;

[...]

// Store instance variables based on arguments passed
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    [...]

    // HARD CODED VALUES
    mUser = new User("Leonardo");
    mUser.setGold(2000);
}

// Inflate the view for the fragment based on layout XML
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(mLayout, container, false);

    [...]

    // Unlock Button
    mineUnlockButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            if(mUser.getGold() >= mUnlockCost) {
                overlay.setVisibility(View.GONE); // Remove overlay and button
                mineUnlockButton.setVisibility(View.GONE);
                System.out.println("Gold: " + mUser.getGold() + " | Cost: " + mUnlockCost);
                mUser.setGold(mUser.getGold() - mUnlockCost); // Update user's gold
                System.out.println("Gold: " + mUser.getGold());
                System.out.println("### Mine Purchased ###");

            } else { // Not enough money
                Toast.makeText(getContext(), "Not enough money to purchase", Toast.LENGTH_SHORT).show();
            }
        }
    });

    return view;
}

}


主片段

public class MainActivity extends AppCompatActivity {

FragmentPagerAdapter adapterViewPager;
ViewPager viewPager;

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

    viewPager = (ViewPager) findViewById(R.id.vpPager);
    adapterViewPager = new MineAdapter(getSupportFragmentManager());
    viewPager.setAdapter(adapterViewPager);

}

}

这是 GitHub 上的 project,您可以在其中找到 MainActivityUser 类、MineFragment 以及一些其他内容(如果需要)。

【问题讨论】:

  • 请在您的问题中提供minimal reproducible example 的问题。我们不应该去 github 来理解你在问什么
  • 完成@cricket_007
  • 那么你想将一个User从Activity传递给Fragment作为参数?您是否尝试过使用户对象可序列化?并通过 Fragment 参数传递它?
  • 不,我不想将任何东西传递给 Fragment。我希望能够从片段中访问用户的数据,我认为 Fred_Grott 做对了,或者至少我认为它更接近我想要做的事情,我只是不知道如何去做他发布的内容。 @cricket_007

标签: android


【解决方案1】:

您需要使用单例模式将您的数据存储在一个单一的地方。

我从您的代码中得到的是,您的游戏中有多个levels,每个level 都需要最少数量的golds 才能解锁它们。

这是 200 金币的测试数据的样子:-

模型类

让我们从 Level 类开始 -lavel 有名称和最低金阈值

    public class LevelModel {

        private String levelName;
        private int unlockCost;

        public String getLevelName() {
            return levelName;
        }

        public int getUnlockCost() {
            return unlockCost;
        }

        public LevelModel(String levelName, int unlockCost) {
            this.levelName = levelName;
            this.unlockCost = unlockCost;
        }
    }

接下来是用户类,所有字段都是不言自明的

public class User {
    private String userName;
    private int gold;
    private int experience;
    private int experienceLevel = 1;

    /**
     * @param userName
     * @param gold
     * @param experience
     * @param experienceLevel
     */
    public User(String userName, int gold, int experience, int experienceLevel) {
        this.userName = userName;
        this.gold = gold;
        this.experience = experience;
        this.experienceLevel = experienceLevel;
    }

    //Setters

    public void setGold(int gold) {
        this.gold = gold;
    }

    public void setExperience(int experience) {
        this.experience = experience;
    }

    public void setExperienceLevel(int experienceLevel) {
        this.experienceLevel = experienceLevel;
    }

    //Getters

    public String getUserName() {
        return userName;
    }

    public int getGold() {
        return gold;
    }

    public int getExperience() {
        return experience;
    }

    public int getExperienceLevel() {
        return experienceLevel;
    }
}

现在您需要一个地方来存储、更新和访问您的游戏数据,这个类将充当 Singleton 类来保存您的所有游戏数据。

public class CenterRepository {

    public void setCurrentUser(User currentUser) {
        this.currentUser = currentUser;
    }

    private User currentUser;
    ArrayList<LevelModel> listOfLavels = new ArrayList<>();
    private static CenterRepository singletonInstance;

    private CenterRepository() {
    }

    public static CenterRepository getSingletonInstance() {
        if (null == singletonInstance) {
            singletonInstance = new CenterRepository();
        }
        return singletonInstance;
    }

    public User getCurrentUser() {
        return currentUser;
    }


    public ArrayList<LevelModel> getListOfLavels() {
        return listOfLavels;
    }
}

现在第二部分如何访问和更新来自 ViewPager 的数据。我已经增强了您的视图寻呼机以使用视图而不是片段

MineAdapter 已更新**

package com.fet.minebeta.ui;

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.fet.minebeta.R;
import com.fet.minebeta.data.CenterRepository;

/**
 * Created by FET on 08/09/2016.
 * All rights reserved.
 * Please contact @fettucciari.leonardo@gmail.com
 */
public class MineAdapter extends PagerAdapter {
    private Context mContext;
    private LayoutInflater mLayoutInflater;

    public MineAdapter(Context context) {
        mContext = context;
        mLayoutInflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {

        //Fill Data directly from Repository
        return CenterRepository.getSingletonInstance().getListOfLavels().size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((FrameLayout) object);
    }

    @Override
    public Object instantiateItem(ViewGroup container, final int position) {

        final View itemView = mLayoutInflater.inflate(R.layout.carousal_page, container,
                false);

        switch (position) {
            case 0:
                itemView.setBackgroundResource(R.color.iron);
                break;
            case 1:
                itemView.setBackgroundResource(R.color.coal);
                break;
            case 2:
                itemView.setBackgroundResource(R.color.gold);
                break;
        }

        //Mine Name
        ((TextView) itemView.findViewById(R.id.mineName)).setText(
                CenterRepository.getSingletonInstance().getListOfLavels().get(position).getmName());

        //Mine Cost
        ((TextView) itemView.findViewById(R.id.mineCost)).setText("" +
                CenterRepository.getSingletonInstance().getListOfLavels().get(position).getUnlockCost());

        //Mine Cost
        ((TextView) itemView.findViewById(R.id.mineDropRate)).setText("" +
                CenterRepository.getSingletonInstance().getListOfLavels().get(position).getDropRate());

        //Mineral Name
        ((TextView) itemView.findViewById(R.id.mineMineral)).setText(
                CenterRepository.getSingletonInstance().getListOfLavels().get(position).getMineral().getName());

        //Mineral Drop Rate
        ((TextView) itemView.findViewById(R.id.mineDropRate)).setText("" +
                CenterRepository.getSingletonInstance().getListOfLavels().get(position).getMineral().getValue());

        // Unlock Button
        itemView.findViewById(R.id.unlockButton).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (CenterRepository.getSingletonInstance().getCurrentUser().getGold() >=
                        CenterRepository.getSingletonInstance().getListOfLavels().get(position).getUnlockCost()) {

                    //If User has more gold than cost to unlock hide lock image and buy it

                    CenterRepository.getSingletonInstance().getCurrentUser().setGold(
                            CenterRepository.getSingletonInstance().getCurrentUser().getGold()
                                    - CenterRepository.getSingletonInstance().getListOfLavels().get(position).getUnlockCost()); // Update user's gold

                    Toast.makeText(mContext,
                            "Reduced " + CenterRepository.getSingletonInstance().getListOfLavels().get(position).getUnlockCost() +
                                    "\n Updated Gold " + CenterRepository.getSingletonInstance()
                                    .getCurrentUser().getGold(), Toast.LENGTH_LONG).show();

                } else {

                    // Not enough money
                    Toast.makeText(mContext, "Not enough money to purchase You need " +
                            (CenterRepository.getSingletonInstance().getListOfLavels().get(position).getUnlockCost()
                                    - CenterRepository.getSingletonInstance().getCurrentUser().getGold()) + "More", Toast.LENGTH_SHORT).show();
                }

            }
        });

        container.addView(itemView);

        return itemView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((FrameLayout) object);
    }
}

这里需要注意的一点是 carousal 页面有 FrameLayout 作为 rootlayout 。如果您打算使用任何其他更新 addview 并相应地删除视图功能

carousal_page.xml **更新您不需要为每种矿物单独布局

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/mineName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/activity_horizontal_margin"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:text="COAL MINE"
        android:textColor="@android:color/white"
        android:textSize="25sp" />


    <TextView
        android:id="@+id/mineCost"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="5"
        android:gravity="center"
        android:text="1000"
        android:textColor="@android:color/white"
        android:textSize="50sp" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="3"
        android:paddingEnd="100dp"
        android:paddingStart="100dp">

        <TextView
            android:id="@+id/mineMineral"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignTop="@+id/mineDropRate"
            android:text="COAL"
            android:textAlignment="center"
            android:textColor="@android:color/white"
            android:textSize="25sp" />

        <TextView
            android:id="@+id/mineDropRate"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:text="1"
            android:textAlignment="center"
            android:textColor="@android:color/white"
            android:textSize="25sp" />

    </RelativeLayout>
</LinearLayout>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/unlockButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Unlock" />

</RelativeLayout>

模型类是如此松散耦合,您可以将它移动到任何地方并且它工作得很好。

更新了测试数据的活动类**

public class MainActivity extends AppCompatActivity {

    PagerAdapter adapterViewPager;
    ViewPager viewPager;

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

        //  Add Test User from Activity
        CenterRepository.getSingletonInstance().setCurrentUser(new User("FET", 200, 20, 10));

        //Add Test Mines
        CenterRepository.getSingletonInstance().getListOfLavels().add(new Mine("Iron", new Mineral("Iron Mineral", 1), 100, 2));
        CenterRepository.getSingletonInstance().getListOfLavels().add(new Mine("Coal", new Mineral("Coal Mineral", 3), 200, 2));
        CenterRepository.getSingletonInstance().getListOfLavels().add(new Mine("Gold", new Mineral("Gold Mineral", 2), 300, 2));

        viewPager = (ViewPager) findViewById(R.id.vpPager);
        viewPager.setAdapter(new MineAdapter(this));

        Toast.makeText(getApplicationContext(), "Current Credits " + CenterRepository.getSingletonInstance()
                .getCurrentUser().getGold(), Toast.LENGTH_LONG).show();


    }


}

【讨论】:

  • 哇,非常感谢您的详细回答!我只是不明白我应该如何实例化适配器,资源 ID 是什么?以及我应该如何设置整个代码,因为我基本上已经完成了你所说的所有操作,但是我看不到地雷,我应该在哪里创建它们?
  • 移除布局id参数。 Adpater 正在膨胀存储在 CenterRepository 的 listOfLavels 中的数据,您需要用一些虚拟数据填充 lisOfLavels 并且 adpter 可以正常工作。
  • 嗯嗯完成了。但是现在,正如您所说,您将片段与视图交换,我如何编辑每个视图的布局?之前布局文件夹中有 3 种不同的布局,现在呢?
  • 视图寻呼机正在实例化项目中添加视图。您可以按项目 view.findViewById(R.id.viewid) 查找视图。看看怎么做stackoverflow.com/questions/18710561/…
  • 我还需要测试,但是你的答案在这里最全,也很详细,所以我给你赏金,但是当我测试它时,我会在这里给你回复! @HiteshSahu
【解决方案2】:

这不是一个糟糕的开始......

由于这可能是您唯一的游戏初始化类,您需要将其设为单例。 Java 中的一个技巧是,如果将类更改为枚举并创建一个名为 INSTANCE 的字段

在 onCreate 调用中的 MainActivity 中使用

用户实例

这将使用您在 User 类中的默认值初始化游戏。比您可以访问 User 类和字段的所有方法。

【讨论】:

  • 我不明白为什么单例是答案
  • 他想初始化一次用户类来访问游戏的变量和方法。
  • @FredGrott 我该怎么办
  • 你应该提出另一个问题或开始一个聊天室。
【解决方案3】:

在您的用户类中创建一个代表正在玩游戏的人的静态用户:

    public class User {

    public static User user = new User("Name Here");

    private String mName;
    private int mGold;
    private int mExperience;
    private int mExperienceLevel;

    public User(String name){
        mName = name;
        mGold = 0;
        mExperience = 0;
        mExperienceLevel = 1;
    }
    // Getters & Setters
    [...]

使用例如访问它:

    User.user.setGold(User.user.getGold() + 1);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-25
    相关资源
    最近更新 更多