0

Yeterince açıklayabileceğimi umduğum garip bir konu var. Uygulamamın iki etkinliği var: MainActivity ve SearchActivity. MainActivity üzerinde, cihazdaki veritabanından web sunucumdaki uzak bir veritabanına bir yükleme tetikleyen bir düğmem var. Uygulamayı ilk başlattığımda düğmeyi tıklarsam sorun olmaz, iyi çalışıyor. SearchActivity'ye geçersem, hiçbir şey yapmaz ve geri dönersek düğmeyi deneyin, uygulama ConcurrentModificationException ile çöker. Yerel bir veritabanının içeriğini (zaten veritabanından çıkardı ve bir ArrayList olarak parametreler aracılığıyla iş parçacığına gönderilen) gönderen bir AsyncTask var. Bunu hata ayıklamak için saatler harcadım ve hala nerede olduğunu anlayamıyorum. Herhangi bir öneri çok takdir edilecektir.Android'de ConcurrentModificationException AsyncTask

Bu kod Bu databaser her yanıtını alır ve bunları toplar BroadcastReceiver içinde kodudur

Button btnRemoteSync = (Button)findViewById(R.id.btnSync); 
    btnRemoteSync.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Intent startUpload = new Intent(getString(R.string.broadcast_search_database)); 
      startUpload.putExtra("type-id",1); 
      LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(startUpload); 
     } 
    }); 

ayrı Databaser iplikten veritabanının içeriğini istemek için, düğmesine basın üzerinde tetiklenen olduğunu özel ResponseObjects bir ArrayList. Veritabanının iş parçacığı bir BOSID değeri gönderdiğinde, AsyncTask ArrayList parametresi olarak geçirilerek başlatılır. Aşağıda

@Override 
    public void onReceive(Context context, Intent intent) { 
     String bssid = intent.getStringExtra(getString(R.string.data_bssid)); 
     if (bssid.equals("DONE")) { 
      RemoteDatabaseUploader rdb = new RemoteDatabaseUploader(getApplicationContext()); 
      rdb.execute(databases); 
     } else { 
      databases.add(new ResponseObject(getApplicationContext(), 
        bssid, 
        intent.getStringExtra(getString(R.string.data_ssid)), 
        intent.getStringExtra(getString(R.string.data_capabilities)), 
        intent.getIntExtra(getString(R.string.data_level), 0), 
        intent.getIntExtra(getString(R.string.data_frequency), 0), 
        intent.getStringExtra(getString(R.string.data_timestamp)), 
        intent.getDoubleExtra(getString(R.string.data_latitude), 0), 
        intent.getDoubleExtra(getString(R.string.data_longitude), 0))); 

     } 
    } 

AsyncTask

@Override 
protected Integer doInBackground(ArrayList<ResponseObject>... params) { 
    ArrayList<ResponseObject> entries = params[0]; 
    try { 
     URL url = new URL(insertURL); 
     for (Iterator<ResponseObject> it = entries.iterator(); it.hasNext();) { 
      ResponseObject ro = it.next(); // THIS IS WHERE THE EXCEPTION REFERENCES IN THE DEBUG OUTPUT 
      HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection(); 

      urlConnection.setRequestMethod("POST"); 
      urlConnection.setRequestProperty("USER-AGENT", "Mozilla/5.0"); 
      urlConnection.setRequestProperty("ACCEPT-LANGUAGE", "en-US,en;0.5"); 
      urlConnection.setDoOutput(true); 
      String postParams = "bssid=" + ro.BSSID 
        + "&ssid=" + ro.SSID 
        + "&capabilities=" + ro.CAPABILITIES 
        + "&level=" + String.valueOf(ro.LEVEL) 
        + "&frequency=" + String.valueOf(ro.FREQUENCY) 
        + "&timestamp=" + ro.TIMESTAMP 
        + "&lat=" + String.valueOf(ro.LAT) 
        + "&long=" + String.valueOf(ro.LON); 
      DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); 
      wr.writeBytes(postParams); 
      wr.flush(); 
      wr.close(); 
      Log.d("RemoteDatabase : ", "Post sent " + ro.BSSID + " || " + String.valueOf(urlConnection.getResponseCode())); 
     } 
    } catch (MalformedURLException e) { 
     e.printStackTrace(); 
    } catch (ProtocolException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    entries.clear(); 

    return null; 
} 


DÜZENLEME için doInBackground kodudur - Bir yayın tuşuna gönderilir başka bir kod bölümüne, aşağı sorunu takip görünmektedir . Düğme kesinlikle sadece bir kez gönderir (Log.d kullanarak kontrol edildi) ancak veritabanında alınan iki kez alır. Bunu düzeltmeye çalışıyorum.

+0

ConcurrentModificationException öğesinin ne olduğunu biliyor musunuz? Başka bir iş parçacığında yinelemek için neden bir iş parçacığı listeye bir öğe eklemek sorun olabilir biliyor musunuz? –

+0

@AndyTurner Bu hatanın ne olduğunu biliyorum, ancak bunu bir iş parçacığında değiştirmemeli ve bir diğerinde yinelememeliyiz - yineleme, Veritabanının yalnızca listenin tamamlandığı ana iş parçacığına "Bitti" gönderdiğinde başlamalıdır. – Brae

cevap

2

Biraz zaman geçti ama bunu nasıl çözdüğümü eklemeyi unuttuğumun farkına vardım.

Buradaki sorun, bazı Android cihazların bir yayının birden fazla kopyasını göndermesiydi. Test için bir HTC cep telefonu kullanıyordum ve belli bir nedenle tüm yayınların 2 kopyasını gönderiyorlar. Kodumun çalışma şekli, aynı veri üzerinde çalışan 2 özdeş iş parçacığıyla sonuçlanan bir yayınlama iş parçacığı oluşturuyordu. Bunlar tamamlandığında, her biri "Bitti" yayınını gönderiyordu, bu da 4 tanesi ana iş parçacığı tarafından alındı. Külliyen dağınıklık. Her yayına benzersiz bir ID belirteci ekledikten sonra alıcı ucundaki değerleri kaydetmem gerektiğinden, aynı kimlik iki kez alındığında ikinci kez hiçbir işlem yapılmayacaktı.

1

Lütfen bir async görevinin onPreExecute() yöntemine bir ilerleme çubuğu ekleyin ve onPostExecute() öğesinde onu reddedin. Async görevini tamamlamak için çok fazla zaman harcıyorum ve düğmeden önce düğmeye tekrar dokunursunuz. async görevinin tamamlanması.

+0

İstisna, ilk defa basmaya başladığım an gerçekleşir. Tam sebebi için iki kere basmamaya dikkat ettim. Muhtemelen bir ilerleme çubuğu eklemeliyim, ama bu sadece ağ programlaması için uni kursundan beri rahatsız olmadı. Teknik olarak, ağ bölümünün doğru zamanda yapmam durumunda işe yaradığı için bu hatayı düzeltmem gerekmiyor, ama benden rahatsız oluyor – Brae

+0

Sanırım searchActivity'den geri döndükten sonra düğmeye dokundun mu?Bir önceki asenkronize görevin tamamlandığından veya yapılmamasını nasıl sağlayabiliriz? Normalde ilerleme çubuğu kullandığımız async görevinin tamamlanmasına kadar kullanıcı eyleminden kaçınmak için. –

+0

Evet, ancak düğme basılmadan önce oluşturulan AsyncTask'ın başka bir örneği olmamalıdır (aslında Log.d'yi kullanarak kontrol ettiğim gibi olmadığını biliyorum). Asıl gönderiye bir değişiklik yaptım - Sanırım sorunu neredeyse takip ettim. BroadcastReceiver veritabanı isteği için bir kez gönderilen rağmen iki kez tespit gibi görünüyor – Brae