我是Android的新手,我遇到了一些麻烦。我创造了2个微调器。第一个用于获取YEARS并动态填充第一个微调器。根据用户选择的年份,第二个微调器将关闭并获取特定年份的Car Makes(福特,本田等)并动态更新第二个微调器。当我启动应用程序时,第一个微调器使用年份正确填充,但是当我选择一年时,选择不会被选中。我一直在阅读,我90%肯定我的所有代码都是正确的,但我认为其中一些是在错误的地方。例如,我应该更多地使用onCreate方法吗?我应该用不同的方法分割每个微调器吗?任何人都可以告诉我我做错了什么或者你是否特别好,重新格式化它以便它可以工作?这是我的代码。
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
final Spinner year=(Spinner)findViewById(R.id.spinner_year);
final Spinner make=(Spinner)findViewById(R.id.spinner_make);
final ArrayList<String> year_options = new ArrayList<String>();
final ArrayList<String> make_options = new ArrayList<String>();
/*
* ASYNC TASK CLASSES
*/
class populateYear extends AsyncTask<URL, Void, NodeList> {
protected NodeList doInBackground(URL... urls) {
NodeList yearList = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(urls[0].openStream());
Element docEle = doc.getDocumentElement();
yearList = docEle.getElementsByTagName("menuItem");
} catch (Exception e) {
System.out.println(e);
}
return yearList;
}
protected void onPostExecute(NodeList yearList) {
if (yearList != null && yearList.getLength() > 0) {
for (int i = 0; i < yearList.getLength(); i++) {
Node node = yearList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) node;
NodeList nodeList = e.getElementsByTagName("text");
year_options.add(nodeList.item(0).getChildNodes().item(0).getNodeValue());
}
}
} else {
System.exit(1);
}
}
}
class populateMake extends AsyncTask<String, Void, NodeList> {
protected NodeList doInBackground(String... strings) {
NodeList makeList = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
//Building a URL with "strings[0]" being equal to the year that we pass to the class.
URL url = new URL("http://www.fueleconomy.gov/ws/rest/vehicle/menu/make?year=" + strings[0]);
Document doc = db.parse(url.openStream());
Element docEle = doc.getDocumentElement();
makeList = docEle.getElementsByTagName("menuItem");
} catch (Exception e) {
System.out.println(e);
}
return makeList;
}
protected void onPostExecute(NodeList makeList) {
if (makeList != null && makeList.getLength() > 0) {
for (int i = 0; i < makeList.getLength(); i++) {
Node node = makeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) node;
NodeList nodeList = e.getElementsByTagName("text");
make_options.add(nodeList.item(0).getChildNodes().item(0).getNodeValue());
}
}
} else {
System.exit(1);
}
}
}
/*
* END OF ASYNC TASK CLASSES
*/
final ArrayAdapter<String> yearAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item,year_options);
//Filling the YEAR SPINNER
URL xmlURL = null;
try {
xmlURL = new URL("http://www.fueleconomy.gov/ws/rest/vehicle/menu/year");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Parse the XML and use the value by calling the AsyncTaskClass
new populateYear().execute(xmlURL);
//Setting the Year Adapter
year.setAdapter(yearAdapter);
final ArrayAdapter<String> makeAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item,make_options);
//Disabling the MAKE spinner onLoad. Will be enabled later when user picks a year.
make.setEnabled(false);
//Setting the Make Adapter
make.setAdapter(makeAdapter);
//Adding the listener for when someone selects a YEAR
year.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
year.setSelection(position);
String selectedYear=year_options.get(position).toString();
resetMake(selectedYear);
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
public void resetMake(String selectedYear) {
//Clear the ArrayList belonging to MAKE so you can add new data based on the YEAR selection
make_options.clear();
new populateMake().execute(selectedYear);
//Clear the makeAdapter and then add the new makes bases on the YEAR selection.
makeAdapter.clear();
for(int i=0; i < make_options.size(); i++) {
makeAdapter.add(make_options.get(i));
}
makeAdapter.notifyDataSetChanged();
make.setEnabled(true);
}
}
答案 0 :(得分:1)
AsyncTask
的意思是它从UI
线程异步运行,以便应用程序可以继续运行。这意味着当您启动任务时,函数中的其余代码将继续运行。因此,当您输入public void resetMake(String selectedYear) {
AsyncTask
次运行时,该功能中的其余代码也会运行,这意味着您的Adapter
会在下载新数据之前尝试填充。
有几种方法可以解决这个问题。在将任务执行到该任务的onPostExecute()
之后,您可以在该函数中移动所有代码。
protected void onPostExecute(NodeList makeList) {
if (makeList != null && makeList.getLength() > 0) {
for (int i = 0; i < makeList.getLength(); i++) {
Node node = makeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) node;
NodeList nodeList = e.getElementsByTagName("text");
make_options.add(nodeList.item(0).getChildNodes().item(0).getNodeValue());
}
}
//Clear the makeAdapter and then add the new makes bases on the YEAR selection.
makeAdapter.clear();
for(int i=0; i < make_options.size(); i++) {
makeAdapter.add(make_options.get(i));
}
makeAdapter.notifyDataSetChanged();
make.setEnabled(true);
} else {
System.exit(1);
}
}
这样做只会使你的功能
public void resetMake(String selectedYear) {
//Clear the ArrayList belonging to MAKE so you can add new data based on the YEAR selection
make_options.clear();
new populateMake().execute(selectedYear);
因此,您可以将其移至第一个onItemSelected()
的{{1}},然后取消此功能。
注意我没有检查此代码是否完整,因此您可能会遇到语法错误,需要移动大括号等等,以便进行编译。
附加说明
通常,您会在Spinner
中初始化Views
,但您可以将其声明为成员变量,通常不需要将它们onCreate()
。这也将使您的代码更具可读性。所以你班级的开头看起来像这样:
final