我有一个ListView,我在Android中加载MySQL DataBase中的所有项目并显示这些项目。由于列表需要更新,在活动中我使用Asynctask函数每15秒刷新一次并更新ListView。还有一个滚动条,因为可能有很多项目,这里是错误发生的地方。如果我通过滚动条上下移动它会很顺利。但是,如果我使用滚动条并且活动尝试访问数据库以加载更新的项目,则应用程序将停止。
这是日志:
06-23 15:36:32.867: E/AndroidRuntime(7788): FATAL EXCEPTION: main
06-23 15:36:32.867: E/AndroidRuntime(7788): java.lang.IndexOutOfBoundsException: Invalid index 14, size is 0
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.util.ArrayList.get(ArrayList.java:304)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.SimpleAdapter.bindView(SimpleAdapter.java:147)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.SimpleAdapter.createViewFromResource(SimpleAdapter.java:126)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.SimpleAdapter.getView(SimpleAdapter.java:114)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.obtainView(AbsListView.java:2445)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.ListView.makeAndAddView(ListView.java:1769)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.ListView.fillUp(ListView.java:706)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.ListView.fillGap(ListView.java:645)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5530)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.scrollIfNeeded(AbsListView.java:3509)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.widget.AbsListView.onTouchEvent(AbsListView.java:3906)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.View.dispatchTouchEvent(View.java:7340)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2179)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1914)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2185)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1928)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2113)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1466)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.app.Activity.dispatchTouchEvent(Activity.java:2468)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2061)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.View.dispatchPointerEvent(View.java:7525)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3368)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3300)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4392)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4370)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4474)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4442)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4493)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer.doCallbacks(Choreographer.java:555)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer.doFrame(Choreographer.java:523)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.os.Handler.handleCallback(Handler.java:615)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.os.Handler.dispatchMessage(Handler.java:92)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.os.Looper.loop(Looper.java:137)
06-23 15:36:32.867: E/AndroidRuntime(7788): at android.app.ActivityThread.main(ActivityThread.java:4895)
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.lang.reflect.Method.invokeNative(Native Method)
06-23 15:36:32.867: E/AndroidRuntime(7788): at java.lang.reflect.Method.invoke(Method.java:511)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
06-23 15:36:32.867: E/AndroidRuntime(7788): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
06-23 15:36:32.867: E/AndroidRuntime(7788): at dalvik.system.NativeStart.main(Native Method)
感谢您的帮助
编辑:以下是我每隔15秒刷新Listview的代码: @override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.all_candidatos);
StrictMode.ThreadPolicy policy = new StrictMode. ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy);
boolean isReachable = false;
try{
isReachable = InetAddress.getByName("192.168.1.41").isReachable(200);
} catch (Exception e){
Log.e("InetAddress", e.getMessage());
}finally {
if (isReachable) {
new CargarCandidatos().execute();
timer();
}else{
Toast.makeText(getApplicationContext(), R.string.errorserver, Toast.LENGTH_LONG).show();
}
}
setListAdapter(adapter);
candidatosList = new ArrayList<HashMap<String, String>>();
}
//
//
public void timer(){
new CountDownTimer(tiempo, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
candidatosList.clear();
new CargarCandidatos().execute();
timer();
}
}.start();}
class CargarCandidatos extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
if(!isFinishing()){
super.onPreExecute();
pDialog = new ProgressDialog(Monitorizacion.this);
pDialog.setMessage("Monitorizando ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
}
protected String doInBackground(String... args) {
try {
monitorizar();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();}
return null;
}
protected void onPostExecute(String file_url) {
pDialog.dismiss();
runOnUiThread(new Runnable() {
public void run() {
adapter = new SimpleAdapter(
Monitorizacion.this, candidatosList,
R.layout.list_item, new String[] { TAG_NSERIE,
TAG_DNI, TAG_NOMBRE, TAG_TEST, TAG_PREGUNTA, TAG_BATERIA,TAG_CORRECTAS, TAG_ERRORES},
new int[] { R.id.id, R.id.dni, R.id.nombre, R.id.test, R.id.pregunta, R.id.bateria, R.id.correctas, R.id.fallos});
adapter.notifyDataSetChanged();
setListAdapter(adapter);
}
});
}
}
public void monitorizar() throws Exception{
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
JSONObject json = jParser.makeHttpRequest(url_candidatos, "GET", params);
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
candidatos = json.getJSONArray(TAG_CANDIDATOS);
for (int i = 0; i < candidatos.length(); i++) {
JSONObject c = candidatos.getJSONObject(i);
String nserie = c.getString(TAG_NSERIE);
String dni = c.getString(TAG_DNI);
String nombre = c.getString(TAG_NOMBRE);
String test = c.getString(TAG_TEST);
String pregunta = c.getString(TAG_PREGUNTA);
String bateria = c.getString(TAG_BATERIA);
String correctas = c.getString(TAG_CORRECTAS);
String errores = c.getString(TAG_ERRORES);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_NSERIE, nserie);
map.put(TAG_DNI, dni);
map.put(TAG_NOMBRE, nombre);
map.put(TAG_TEST, test);
map.put(TAG_PREGUNTA, pregunta);
map.put(TAG_BATERIA, bateria);
map.put(TAG_CORRECTAS, correctas);
map.put(TAG_ERRORES, errores);
candidatosList.add(map);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
编辑: 问题是,如果我向上或向下滚动Listview,并且在那时调用asynctask函数来访问数据库,则会发生错误并且应用程序停止。
Michael Butscher解决方案: 根据我的理解,我用Michael Butscher给出的建议解决了这个问题:
public void timer(){
new CountDownTimer(tiempo, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
new CargarCandidatos().execute();
timer();
}
}.start();}
class CargarCandidatos extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
if(!isFinishing()){
super.onPreExecute();
pDialog = new ProgressDialog(Monitorizacion.this);
pDialog.setMessage("Monitorizando ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
}
protected String doInBackground(String... args) {
try {
monitorizar();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();}
return null;
}
protected void onPostExecute(String file_url) {
pDialog.dismiss();
runOnUiThread(new Runnable() {
public void run() {
adapter = new SimpleAdapter(
Monitorizacion.this, candidatosList,
R.layout.list_item, new String[] { TAG_NSERIE,
TAG_DNI, TAG_NOMBRE, TAG_TEST, TAG_PREGUNTA, TAG_BATERIA,TAG_CORRECTAS, TAG_ERRORES},
new int[] { R.id.id, R.id.dni, R.id.nombre, R.id.test, R.id.pregunta, R.id.bateria, R.id.correctas, R.id.fallos});
adapter.notifyDataSetChanged();
setListAdapter(adapter);
}
});
}
}
public void monitorizar() throws Exception{
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
JSONObject json = jParser.makeHttpRequest(url_candidatos, "GET", params);
ArrayList<HashMap<String, String>> temp;
temp = new ArrayList<HashMap<String, String>>();
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
candidatos = json.getJSONArray(TAG_CANDIDATOS);
for (int i = 0; i < candidatos.length(); i++) {
JSONObject c = candidatos.getJSONObject(i);
String nserie = c.getString(TAG_NSERIE);
String dni = c.getString(TAG_DNI);
String nombre = c.getString(TAG_NOMBRE);
String test = c.getString(TAG_TEST);
String pregunta = c.getString(TAG_PREGUNTA);
String bateria = c.getString(TAG_BATERIA);
String correctas = c.getString(TAG_CORRECTAS);
String errores = c.getString(TAG_ERRORES);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_NSERIE, nserie);
map.put(TAG_DNI, dni);
map.put(TAG_NOMBRE, nombre);
map.put(TAG_TEST, test);
map.put(TAG_PREGUNTA, pregunta);
map.put(TAG_BATERIA, bateria);
map.put(TAG_CORRECTAS, correctas);
map.put(TAG_ERRORES, errores);
temp.add(map);
candidatosList = temp;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
答案 0 :(得分:1)
在onPostExecute()
中,您创建了一个获取candidatosList
作为数据的适配器。 SimpleAdapter
现在预计只有在事后立即调用notifyDataSetChanged()
时才会更改此数据(更改和调用仅在主线程上发生)。
在您的计时器的onFinish()
中,您拨打candidatosList.clear()
(onFinish()
在主线程上运行,这样就可以了)但您没有拨打notifyDataSetChanged()
。
更好的方法:
根本不要致电candidatosList.clear()
,而是在ArrayList
开头创建一个新的temp
(例如名为“monitorizar()
”),并填写收到的数据,作为monitorizar()
设置candidatosList = temp
的最后一步。为了在所有情况下都能正常工作,candidatosList
应该声明volatile
(因为它被多个线程使用)。