【问题标题】:Final variable alters itself in OnClickListener [Android]最终变量在 OnClickListener [Android] 中改变自身
【发布时间】:2017-05-23 16:08:39
【问题描述】:

我不是 Android 编程方面的专家,但这个让我很受不了。我只是想将结构“挑战”从片段传递给活动,没什么特别的。然后我创建了我的结构的最终版本,这很好。但是当我进入 OnClickListener 时,它不再一样了,因为它缺少 ArrayList[Score](“Score”是另一种结构)。为了说明,我有一个打印结构的函数,我可以清楚地看到在 onCreate() 中没有问题,并且它下面的 2 行不再匹配。有一阵子摸不着头脑,但我现在得寻求你的帮助,否则我的键盘会飞起来。

DetailsFragment:

public class DetailsFragment extends Fragment {

    public DetailsFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_details, container, false);

        // Get challenge details
        Bundle b = getArguments();
        Challenge challenge = (Challenge) b.getSerializable("challenge");
        Log.v("APP", "DetailsFragment : " + challenge.printToFile());

        // Buttons
        final Challenge finalC = challenge;
        Log.v("APP", finalC.printToFile());
        ((Button) rootView.findViewById(R.id.btn_Go)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.v("APP", finalC.printToFile());
                Intent intent = new Intent(getActivity(), ChallengeActivity.class);
                intent.putExtra("challenge", finalC);
                startActivity(intent);
            }
        });
        ((Button) rootView.findViewById(R.id.btn_Cancel)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getActivity().finish();
            }
        });

        // Set up layout
        if (challenge != null) {

            // Details
            ((TextView) rootView.findViewById(R.id.label_challengeName)).setText(challenge.name);
            ((TextView) rootView.findViewById(R.id.label_Distance2)).setText(String.valueOf(challenge.distance) + " m");
            ((TextView) rootView.findViewById(R.id.label_Lap2)).setText(String.valueOf(challenge.lap) + " m");
            ((TextView) rootView.findViewById(R.id.label_Objective2)).setText(challenge.printObjective());

            // Averages
            double avg = (challenge.distance * 1.0 / challenge.objective) * 3.6;
            ((TextView) rootView.findViewById(R.id.label_AvgSpeed2)).setText(String.format("%.2f", avg) + " km/h");
            int avg_sec = (int) (challenge.lap / (challenge.distance * 1.0 / challenge.objective));
            int sec = avg_sec % 60;
            int min = (avg_sec - sec) / 60;
            String obj = "";
            if (min > 0)
                obj += String.valueOf(min) + "'";
            obj += String.format("%02d", sec) + "\"";
            ((TextView) rootView.findViewById(R.id.label_AvgTime2)).setText(obj);

        }

        return rootView;

    }

}

还有日志:

01-09 12:16:26.569 23926-23926/domk.mychallenge V/APP: DetailsFragment : Course Police:2400/400:720:10-12-2016/104,127,135,130,125,138:14-12-2016/122,128,128,132,130,108:24-12-2016/126,130,133,134,130,125
01-09 12:16:26.571 23926-23926/domk.mychallenge V/APP: Course Police:2400/400:720:10-12-2016/104,127,135,130,125,138:14-12-2016/122,128,128,132,130,108:24-12-2016/126,130,133,134,130,125
01-09 12:16:36.528 23926-23926/domk.mychallenge V/APP: Course Police:2400/400:720

结构从 MainActivity 中的文件加载,然后传递给 DetailsActivity:

public class DetailsActivity extends AppCompatActivity {

    Challenge challenge;
    TabLayout tabLayout = null;
    ViewPager viewPager = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_details);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        if (tabLayout != null) {
            tabLayout.addTab(tabLayout.newTab().setText("Details"));
            tabLayout.addTab(tabLayout.newTab().setText("Scores"));
            tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        } else {
            Toast.makeText(getApplication().getBaseContext(), "Internal error", Toast.LENGTH_LONG).show();
            finish();
        }

        Bundle b = getIntent().getExtras();
        challenge = (Challenge) b.getSerializable("challenge");

        viewPager = (ViewPager) findViewById(R.id.pager);
        viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount(), challenge));
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

    }

}

PagerAdapter 如下:

public class PagerAdapter extends FragmentStatePagerAdapter {

    int mNumOfTabs;
    Challenge challenge;

    public PagerAdapter(FragmentManager fm, int NumOfTabs, Challenge challenge) {
        super(fm);
        this.mNumOfTabs = NumOfTabs;
        this.challenge  = challenge;
    }

    @Override
    public int getCount() {
        return mNumOfTabs;
    }

    @Override
    public Fragment getItem(int position) {

        Bundle bundle = new Bundle();
        bundle.putSerializable("challenge", challenge);

        switch (position) {

            case 0:
                DetailsFragment tab1 = new DetailsFragment();
                tab1.setArguments(bundle);
                return tab1;

            case 1:
                ScoresFragment tab2 = new ScoresFragment();
                tab2.setArguments(bundle);
                return tab2;

            default:
                return null;

        }
    }

}

结构Score

public class Score implements Serializable {

    Date date;
    ArrayList<Integer> laps;

    public Score() {

        Calendar c = Calendar.getInstance();
        date = c.getTime();
        laps = new ArrayList<Integer>();

    }

    public Score(Date d, ArrayList<Integer> l) {

        date = d;
        laps = l;

    }

    public void newLap(int score) { laps.add(score); }

    public String printLaps() {

        String s = "";
        for (int i = 0; i < laps.size(); i++) {
            s += "Lap " + String.valueOf(i + 1) + " : " + String.valueOf(laps.get(i)) + "s";
            if (i != (laps.size() - 1))
                s += "\n";
        }

        return s;

    }

    public String printToFile() {

        String s = ":" + new SimpleDateFormat("dd-MM-yyyy").format(date) + "/";
        for (int i = 0; i < laps.size(); i++) {
            s += String.valueOf(laps.get(i));
            if (i < (laps.size() - 1))
                s += ",";
        }

        return s;
    }

    public int getTime() {

        int sum = 0;
        for (int i = 0; i < laps.size(); i++)
            sum += laps.get(i);
        return sum;

    }

}

结构Challenge

public class Challenge implements Serializable {

    String           name;
    int              distance;
    int              lap;
    int              objective;
    ArrayList<Score> scores;

    public Challenge(String n, int d, int l, int o) {
        name      = n;
        distance  = d;
        lap       = l;
        objective = o;
        scores    = new ArrayList<Score>();
    }

    public String printToFile() {
        String s = name + ":" + Integer.valueOf(distance) + "/" + Integer.valueOf(lap) + ":" + Integer.valueOf(objective);
        for (int i = 0; i < scores.size(); i++)
            s += scores.get(i).printToFile();
        return s + "\n";
    }

    public String printObjective() {

        // Default format : XX'XX"
        if (format.length() < 2)
            format = "'\"";

        String time = "";

        int sec = objective % 60;
        int min = (objective - sec) / 60;

        if (min > 0)
            time +=  String.valueOf(min) + format.charAt(0);
        time += String.format("%02d", sec) + format.charAt(1);

        return time;

    }

    public void newScore(Score s) { scores.add(s); }


    public ArrayList<Integer> getTimes() {

        ArrayList<Integer> t = new ArrayList<Integer>();

        for (int i = 0; i < scores.size(); i++)
            t.add(scores.get(i).getTime());

        return t;

    }

}

我基本上无法理解我的最终变量如何在第二和第三日志之间变化。我什至不知道在网上寻找什么,因为这看起来很愚蠢。

如果它与某种重复,我深表歉意,并希望我的英语至少可以理解......

【问题讨论】:

  • 显示DetailsFragment的完整代码。你在别处修改你的变量。
  • 这是完整的代码,不包括一些不相关的setText()...
  • 再次,Challenge 代码丢失...
  • 如果你坚持,但在那里你不会发现太多有趣的东西,它们真的很简单
  • 如果您想获得帮助,只需显示DetailsFragment 的完整代码即可。

标签: java android listener onclicklistener final


【解决方案1】:

Java 最终关键字:

java中的final关键字用于限制用户。 Java决赛 关键字可以在许多情况下使用。

final 关键字可以与 变量,一个没有值的最终变量,它被称为空白 最终变量或未初始化的最终变量。可以初始化 仅在构造函数中。空白的最终变量也可以是静态的 它将仅在静态块中初始化。我们将有 详细学习这些。我们先来学习final的基础知识 关键字。

您可能会查看 Static 之类的变量,以便在尝试获取变量时保持变量不变。

【讨论】:

  • 它是否以某种方式回答了作者的问题?
  • 据我了解,作者询问如何保持变量的值不变。当您想要引用一个常量值而不是硬编码它时,静态关键字会使用很多。所以我假设,如果您将变量初始化为静态,当您尝试获取它时,它将保留该值。
  • 不,他在问为什么变量在onClickListener内部发生了变化。
  • 我没有看到Challenge 代码,所以虽然引用保持不变,但内容却没有。查看上面的列表示例。
【解决方案2】:

final 只是阻止你重新分配变量,即一旦分配了变量,你就不能写finalC = anything。但是您(或引用同一对象的任何其他人)仍然可以更改其字段或调用更改其字段的方法:

final List<String> finalList = new ArrayList<>(Array.asList("hello"));
System.out.println(finalList);  // Prints [hello]
finalList.clear();
System.out.println(finalList);  // Prints []

这说明在变量中添加final 对变量值的可变性没有影响。

在您未显示的代码中,似乎有其他东西在类似地改变您的变量。

如果你想确保finalC 的值在onClick 被调用时没有不同,你需要复制你分配给它的东西。具体如何操作取决于您要复制的值;对于列表,它将是:

final List<String> finalList = new ArrayList<>(Array.asList("hello"));
final List<String> copyOfFinalList = new ArrayList<>(finalList);

System.out.println(finalList);        // Prints [hello]
System.out.println(copyOfFinalList);  // Prints [hello]

finalList.clear();

System.out.println(finalList);        // Prints []
System.out.println(copyOfFinalList);  // Prints [hello]

【讨论】:

  • 编辑了我的帖子,指定了数据流,但我仍然不明白任何活动何时收到不完整的结构。
猜你喜欢
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-11
相关资源
最近更新 更多