Android - 动态视图计时问题?

Android - Dynamic View Timing Issue?

我是一名 Android 新手开发人员,我正在开发的一个 Android 小应用程序有问题,我怀疑它与动态视图创建的时间有关。这是一个小记分员应用程序,它具有动态生成的播放器按钮和文本字段,在播放器 class 中定义。以下是我如何执行此操作的摘录:

    public Player(String name, int score, int number, boolean enabled, RelativeLayout mainScreen, List<Button> presetButtonList, Editor editor, Context context) {
            super();
            this.name = name;
            this.score = score;
            this.number = number;
            this.enabled = enabled;
            this.editor = editor;

            // Get the lowest child on the mainScreen
            Integer count = mainScreen.getChildCount(), lowestChildId = null;
            Float lowestChildBottom = null;
            for (int i = 0; i < count; i++) {
                View child = mainScreen.getChildAt(i);
                if ((lowestChildId == null  || child.getY() > lowestChildBottom) && 
                        !presetButtonList.contains(child)) {
                    lowestChildId = child.getId();
                    lowestChildBottom = child.getY();
                }
            }

            playerNameText = (EditText) setTextViewDefaults(new EditText(context), name);
            playerNameText.setSingleLine();
    //      playerNameText.setMaxWidth(mainScreen.getWidth());
    //      playerNameText.setEllipsize(TextUtils.TruncateAt.END);  //TODO: Prevent names which are too long for screen
            playerNameText.addTextChangedListener(new TextWatcher() {

                  public void afterTextChanged(Editable changedText) {
                      setName(changedText.toString());
                      updateScreen();
                  }

                  public void beforeTextChanged(CharSequence changedText, int start, int count, int after) {}

                  public void onTextChanged(CharSequence changedText, int start, int before, int count) {}
               });
            RLParams = new RelativeLayout.LayoutParams(
                    RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            if (lowestChildId != null) {
                RLParams.addRule(RelativeLayout.BELOW, lowestChildId);
            } else {
                RLParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                RLParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
            }
            RLParams.setMargins(0, 10, 0, 10);      
            mainScreen.addView(playerNameText, RLParams);

class 以类似的方式进一步定义按钮等,将顶部与名称文本视图对齐。当用户单击按钮添加播放器时,我调用它,它工作正常,在屏幕下方显示第一个播放器下方的每个播放器。当我一开始加载一堆保存的玩家时,问题就来了。这是我加载播放器的位置:

public void loadData() {
        RelativeLayout mainScreen = (RelativeLayout)findViewById(R.id.relativeLayout);
        playerCount = savedData.getInt("playerCount", playerCount);
        Player player;
        String name;
        playerList.clear();
        for (int i=1; i<=playerCount; i++) {
            name = savedData.getString("name" + i, null);
            if (name != null) {
                Log.v("name", name);
                player = new Player(name, savedData.getInt("score" + i, 0), i, savedData.getBoolean("enabled" + i, false), mainScreen, presetButtonList, editor, this);             
                playerList.add(player);
                player.updateScreen();
            }
        }
        updateScreen();
    }

最后,我在应用程序启动时调用 loadData() 方法,此处:

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

    savedData = this.getPreferences(Context.MODE_PRIVATE);
    editor = savedData.edit();

    presetButtonList.add((Button)findViewById(R.id.newGame));
    presetButtonList.add((Button)findViewById(R.id.addPlayer));
    presetButtonList.add((Button)findViewById(R.id.removePlayer));

    loadData();     
}

结果呢?当有两个以上的玩家要加载时,所有玩家都会加载到同一个位置,在玩家 2 之上。

我怀疑玩家是同时生成的,因此都认为最低玩家视图是玩家 1,而不是相互检查。我试过在 onCreate() 之后触发加载,但它仍然会发生。我还尝试在每个玩家加载后在 loadData() 的 for 循环中添加 3 秒睡眠,看看是否有帮助,但没有成功。

我是不是做出了错误的假设?我做错了什么,我该如何解决?

我怀疑这里发生的事情是您试图定位没有 ID 的视图(看起来您没有在代码中的任何位置设置它们)。动态创建的视图不会自动具有 ID,因此调用 getId() 将 return NO_ID (See documentation). If you want to use an ID you will have to set it yourself using View.setId().

毕竟是时间问题。我需要等待主屏幕加载,然后才能向其添加视图。不幸的是,在 UI 线程上的所有 activity 完成之前,它永远不会加载。

因此,我需要线程。我最终将 loadData() 放在一个线程中,如下所示:

new Thread(new loadDataAsync(this)).start();



class loadDataAsync implements Runnable {

    MainActivity mainActivity;

    public loadDataAsync(MainActivity mainActivity) {
        this.mainActivity = mainActivity;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(700);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        loadData(mainActivity);         
    }
}

然后我在初始睡眠后在 UI 线程上创建播放器,以便为 UI 加载留出时间。

runOnUiThread(new Runnable() {
                Player player;
                RelativeLayout mainScreen = (RelativeLayout)findViewById(R.id.relativeLayout);
                @Override
                public void run() {
                    player = new Player(savedData.getString("name" + playerNum, null), savedData.getInt("score" + playerNum, 0), playerNum, savedData.getBoolean("enabled" + playerNum, false), mainScreen, presetButtonList, editor, mainActivity);    
                    playerList.add(player);
                    player.updateScreen();
                    mainScreen.invalidate();
                }
            });

这不是最优雅的解决方案,但它现在有效。