我是一名Android新手开发者,我正在开发一个小型Android应用程序的问题,我怀疑这与动态视图创建的时间有关。它是一个小记分员应用程序,它具有动态生成的播放器按钮和文本字段,在Player类中定义。以下是我如何做到这一点的摘录:
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);
该类以类似的方式进一步定义按钮等,将顶部与名称文本视图对齐。当用户点击按钮添加播放器时我会调用它,并且它可以正常工作,在屏幕下方显示第一个播放器下面的每个播放器。当我在开始时加载一堆已保存的玩家时会出现问题。这是我加载球员的地方:
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秒睡眠以查看是否有帮助,但没有运气。
我做出错误的假设吗?我做错了什么,我该如何解决?
答案 0 :(得分:0)
我怀疑这里发生的事情是您尝试定位没有ID的视图(看起来您没有在代码中的任何位置设置它们)。动态创建的视图不会自动拥有ID,因此对getId()
的调用将返回NO_ID
(See documentation)。如果您想使用ID,则必须使用View.setId()自行设置。
答案 1 :(得分:0)
毕竟这是个时间问题。我需要等待主屏幕加载才能添加视图。不幸的是,在UI线程上的所有活动都完成之前,它永远不会加载。
因此,我需要线程化。我最终将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();
}
});
不是最优雅的解决方案,但现在可以使用。