2012-03-19 10 views
7

Używam AsyncTask ustawić moje przedmioty i rzeczy, w postExecute zgłoszę zsynchronizowany sposób, w którym robię toZawartość adaptera zmieniła ale ListView nie odbierać powiadomienia - Z AsyncTask

mAllResultsAdapter.setItems(mAllResultsItem); 
mAllResultsAdapter.notifyDataSetChanged(); 
mListView.invalidate(); 
mListView.requestLayout(); 

W większości przypadków, gdy pobieram nowe dane i aktualizuję listę/adapter, to po prostu działa i jest całkiem niezły. Ale jakoś to się załamuje, czy ktoś może mi pomóc z tym problemem.

Oto mój dziennik awarii.

03-19 14:15:02.170: E/AndroidRuntime(23242): FATAL EXCEPTION: main 
03-19 14:15:02.170: E/AndroidRuntime(23242): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131034153, class android.widget.ListView) with Adapter(class com....tracebuzz.allresults.AllResultsAdapter)] 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.ListView.layoutChildren(ListView.java:1556) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.AbsListView.onLayout(AbsListView.java:1993) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.View.layout(View.java:9606) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewGroup.layout(ViewGroup.java:3879) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.FrameLayout.onLayout(FrameLayout.java:400) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.View.layout(View.java:9606) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewGroup.layout(ViewGroup.java:3879) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.RelativeLayout.onLayout(RelativeLayout.java:912) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.View.layout(View.java:9606) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewGroup.layout(ViewGroup.java:3879) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.FrameLayout.onLayout(FrameLayout.java:400) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.View.layout(View.java:9606) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewGroup.layout(ViewGroup.java:3879) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1542) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1403) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.LinearLayout.onLayout(LinearLayout.java:1314) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.View.layout(View.java:9606) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewGroup.layout(ViewGroup.java:3879) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.widget.FrameLayout.onLayout(FrameLayout.java:400) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.View.layout(View.java:9606) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewGroup.layout(ViewGroup.java:3879) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewRoot.performTraversals(ViewRoot.java:1288) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.view.ViewRoot.handleMessage(ViewRoot.java:2066) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.os.Handler.dispatchMessage(Handler.java:99) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.os.Looper.loop(Looper.java:132) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at android.app.ActivityThread.main(ActivityThread.java:4126) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at java.lang.reflect.Method.invokeNative(Native Method) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at java.lang.reflect.Method.invoke(Method.java:491) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) 
03-19 14:15:02.170: E/AndroidRuntime(23242): at dalvik.system.NativeStart.main(Native Method) 

Powinienem zaktualizować mój kod z moim kodem, więc oto jest.

public class AllResultsActivity extends TBActivity{ 

public String identifier, 
       feedIdentifier, 
       apiKey, 
       tagID, 
       titleName; 

private ProcesReuest procesReuest; 

public ArrayList<Integer> tempIDHolder = new ArrayList<Integer>(); 
public ArrayList<AllResultsItem> mAllResultsItem; 
public AllResultsAdapter mAllResultsAdapter; 
public ListView mListView; 
private Context mContext; 
private ViewFlipper mViewFlipper; 
private TextView mTitleText; 
private int itemsForLoad = 50; 
private boolean firstRun = true; 

private ProgressBar mLoadItemsIndicator; 
private int visibleThreshold = 5; 
private int mPage = 1; 
private int previousTotal = 0; 
private boolean loading = true; 
private SharedPreferences mSettings; 
private Editor mEdit; 
private View footerView; 
private int itemHolder; 


@Override 
public void onBackPressed() { 
    super.onBackPressed(); 
    procesReuest.cancel(true); 
    AllResultsActivity.this.finish(); 
} 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    this.requestWindowFeature(Window.FEATURE_NO_TITLE); 
    this.setContentView(R.layout.all_results_view); 
    super.onCreate(savedInstanceState); 
    getExtras(); 
    mContext = this; 
    itemsForLoad = 50; 

    loadItems(apiKey); 
    initListview(); 
} 

private void initListview() { 
    mAllResultsItem = new ArrayList<AllResultsItem>(); 
    mAllResultsAdapter = new AllResultsAdapter(this, mAllResultsItem); 
    mListView.setAdapter(mAllResultsAdapter); 
    mAllResultsAdapter.notifyDataSetChanged(); 
} 

@Override 
public void bindResources() { 
    mLoadItemsIndicator = (ProgressBar)findViewById(R.id.all_results_view_more_items_indicator); 
    mListView = (ListView)findViewById(R.id.all_results_listview); 
    mViewFlipper = (ViewFlipper)findViewById(R.id.all_results_view_viewflipper); 
    mTitleText = (TextView) findViewById(R.id.all_results_view_title_text); 
    mSettings = getSharedPreferences(WBAConstants.TRACEBUZZ, MODE_PRIVATE); 
    mEdit  = mSettings.edit(); 

} 

@Override 
public void bindListeners() { 
    mListView.setOnItemClickListener(new OnItemClickListener() { 

     @Override 
     public void onItemClick(AdapterView<?> arg0, View view, int id, long arg3) { 

     String url = (String) view.getTag(R.string.item_url); 
     Intent intnt = new Intent(AllResultsActivity.this, WebviewWithControllsActivity.class); 
      if(url.contains("twitter")) { 
       int  UQID = (Integer)view.getTag(R.id.twitter_result_identifier); 
       String table = (String)view.getTag(R.string.twitter_table); 

       intnt.putExtra("UQID", UQID); 
       intnt.putExtra("apiKey", apiKey); 
       intnt.putExtra("table", table); 
      } 
      View bar = (View)findViewById(R.id.all_results_title_bar); 
      int barHeight = bar.getHeight(); 
      intnt.putExtra("barHeight", barHeight); 
      intnt.putExtra("URL", url); 
      AllResultsActivity.this.startActivity(intnt);   
     } 
    }); 

    mListView.setOnScrollListener(new OnScrollListener() { 

     @Override 
     public void onScrollStateChanged(AbsListView view, int scrollState) { 
     } 

     @Override 
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 
      Log.d("","totalItemCount = " + totalItemCount); 
      if (loading) { 
       if (totalItemCount > previousTotal) { 
        loading = false; 
        previousTotal = totalItemCount; 
        itemHolder = previousTotal; 
       } 
      } 
      if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { 
        mLoadItemsIndicator.setVisibility(View.VISIBLE); 
        mListView.invalidate(); 

        mPage++; 
        loadItems(apiKey); 
        loading = true; 
      } else { 

      } 
     } 
    });  
} 

private void loadItems(String passedApiKey) { 

    procesReuest = new ProcesReuest(); 
    procesReuest.execute(identifier, feedIdentifier, passedApiKey); 
} 

public void getExtras() { 
    Bundle extras = getIntent().getExtras(); 

    feedIdentifier = null; 
    tagID = null; 
    apiKey = null; 
    if(extras != null) { 
     identifier  = extras.getString("identifier"); 
     feedIdentifier = extras.getString("feedidentifier"); 
     apiKey   = extras.getString("apiKey"); 
     titleName  = extras.getString("tag_name"); 
     tagID   = extras.getString("tag_id"); 
     if((titleName != null) && (!titleName.equals("null"))) { 
      mTitleText.setText(titleName); 
     } 
    } 
} 

public void displayDialog() { 
    AlertDialog.Builder dialog = new AlertDialog.Builder(this); 
    dialog.setTitle("Error"); 
    dialog.setMessage("Failed to contact server, check your Internet connection or try again later"); 
    dialog.setNegativeButton("back", new OnClickListener() { 

     @Override 
     public void onClick(DialogInterface dialog, int which) { 
      AllResultsActivity.this.finish(); 
     } 
    }); 
    dialog.show(); 
} 


private synchronized void addSyncedItems() throws InterruptedException { 

     if(firstRun){ 
      mAllResultsAdapter.setItems(mAllResultsItem); 
      firstRun = false; 
     } 
       mAllResultsAdapter.notifyDataSetChanged(); 

       mListView.invalidate(); 
       mLoadItemsIndicator.setVisibility(View.GONE); 

} 

/** Subclass for processing the ResultReqesut for the specified type **/ 

private class ProcesReuest extends AsyncTask<String, Void, Exception>{ 
    Downloader downloader = new Downloader(); 
    JSONObject result = null; 
    List<NameValuePair> postParams; 
    boolean timeOut; 
    @Override 
    protected Exception doInBackground(String... params) { 
     Log.d("","doInBackground " + apiKey); 

     try { 
      postParams = new ArrayList<NameValuePair>(2);  
      postParams.add(new BasicNameValuePair("api_key",apiKey)); 
      postParams.add(new BasicNameValuePair("num","100")); 
      postParams.add(new BasicNameValuePair("feed_id", feedIdentifier)); 
      postParams.add(new BasicNameValuePair("page", Integer.toString(mPage))); 
      postParams.add(new BasicNameValuePair("order", "time DESC")); 
      postParams.add(new BasicNameValuePair("tag_id", tagID)); 
      postParams.add(new BasicNameValuePair("format", "json")); 
      Log.d("","postParams = " + postParams); 
      downloadJSON(postParams); 
      proccesJSON(); 
     } catch (JSONException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return null; 
    } 

    @Override 
    protected void onPostExecute(Exception exception) { 
     Log.d("","onPostExecute"); 
      try { 
       addSyncedItems(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     try { 
       if(!result.getJSONObject("results").getString("result_count").equals("0")){ 
        mViewFlipper.setDisplayedChild(2); 
       } else { 
        Log.d("","View 3"); 
        mViewFlipper.setDisplayedChild(2); 
       } 
      } catch (Exception e) { 
       // TODO: handle exception 
      } 
    } 

    private void proccesJSON() throws JSONException, IOException { 
     String UIDHolderString = mSettings.getString(WBAConstants.UIDHOLDER, "empty"); 
     JSONArray arrayHolder = null; 

     if(UIDHolderString.equals("empty")){ 
      arrayHolder = new JSONArray(); 
     } else { 
      arrayHolder = new JSONArray(UIDHolderString);  
     } 

    if(result != null){ 
     JSONObject feedResults = result.getJSONObject("results").getJSONObject("result"); 
     Log.d("","" + feedResults); 
     String uniqueItemID = null; 
     Iterator<String> feedResultIter = feedResults.keys(); 

     while (feedResultIter.hasNext()) { 
      uniqueItemID = (String) feedResultIter.next(); 
      Log.d("","" + uniqueItemID); 

      if(!uniqueItemID.equals("metaresult")) { 
      AllResultsItem item = new AllResultsItem(); 


      if(UIDHolderString.contains(uniqueItemID)) { 
       item.setNewFeed(0); 
      } else { 
       item.setNewFeed(1); 
       arrayHolder.put(uniqueItemID); 
      } 

      JSONObject resultItem = feedResults.getJSONObject(uniqueItemID);   
       String typeFeed = resultItem.getString("type"); 
       if(!typeFeed.contains("twitter") && typeFeed != null){  
        if(resultItem.has("tags") && resultItem.getString("tags")!= null) { 
         JSONObject tags = resultItem.getJSONObject("tags");  

         Iterator<String> tagIter = tags.keys(); 
         ArrayList<String> tagHolder = new ArrayList<String>(); 
         while (tagIter.hasNext()) { 
          String tagID = (String) tagIter.next(); 
          String tagName = tags.getString(tagID); 
          tagHolder.add(tagName);   
         }     
         item.setTagNames(tagHolder.toString()); 
        } 
        item.setType(typeFeed); 
        if((resultItem.has("title")) && (!resultItem.isNull("title")) && (!resultItem.getString("title").equals("null"))) { 
         item.setResultTitle(resultItem.getString("title")); 
        } 
        if(resultItem.has("unique_id")) { 
         item.setResultIdentifier(Integer.parseInt(resultItem.getString("unique_id"))); 
        } 
        if(resultItem.has("src_link") && (resultItem.getString("src_link") != null)) { 
         item.setMessageURL(resultItem.getString("src_link")); 
        } 
        if(resultItem.has("date_time")) { 
         item.setDate(resultItem.getString("date_time")); 
        } 
        if(resultItem.has("description")) { 
         item.setMessage(resultItem.getString("description")); 
        } 

       } else if(resultItem.getString("type").contains("twitter")){ 

        Icon icon = new Icon();          
        if((resultItem.has("title")) && (!resultItem.isNull("title")) && (!resultItem.getString("title").equals("null"))) { 
         item.setUserTwitter(resultItem.getString("title")); 
        } 
        if(resultItem.has("unique_id")) { 
         item.setIdentifier(Integer.parseInt(resultItem.getString("unique_id"))); 
        } 
        if(resultItem.has("src_link") && (resultItem.getString("src_link") != null)) { 
         item.setMessageURL(resultItem.getString("src_link")); 

        } 
        if(resultItem.has("date_time")) {       

         item.setDate(resultItem.getString("date_time")); 
        } 
        if(resultItem.has("description")) { 
         item.setMessageText(resultItem.getString("description")); 

        } 
        if(resultItem.has("image_link")) { 
         if(!resultItem.has("null")){ 
          icon.setImageURL(resultItem.getString("image_link")); 
        }     
       }  
        if(resultItem.has("table")) { 
        item.setTable(resultItem.getString("table")); 
        }  

         item.setType(typeFeed); 
         item.addIconsObject(icon); 
         if(resultItem.has("tags") && resultItem.getString("tags")!= null) { 
          JSONObject tags = resultItem.getJSONObject("tags"); 

          Iterator<String> tagIter = tags.keys(); 
          ArrayList<String> tagHolder = new ArrayList<String>(); 
          while (tagIter.hasNext()) { 
           String tagID = (String) tagIter.next(); 
           String tagName = tags.getString(tagID); 

           tagHolder.add(tagName); 

          } 
          item.setTagNames(tagHolder.toString()); 
         } 
       } 
       mAllResultsItem.add(item); 
      } 
     } 
     mEdit.putString(WBAConstants.UIDHOLDER, arrayHolder.toString()); 
     mEdit.commit(); 
     } 
    } 

    public boolean downloadJSON(List<NameValuePair>postParams) { 
     try { 
      result = downloader.getJSONFromURL("http://www.example.com/webservice/get_feed_results.php", true, postParams); 
     } catch (ClientProtocolException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (JSONException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     return true; 
    } 
} 
} 

Przyczyną metody Syncronized była próba pobrania adaptera i listview aktualizacji w tym samym czasie.

+0

gdzie ten kod został napisany w tle() lub w postExcution()? – Pratik

+0

invalidate(); i requestLayout(); są nadmiarowe, jeśli potrzebujesz tylko odświeżyć ListView. – yorkw

+0

Jaki jest powód wywołania zsynchronizowanej metody z 'onPostExecute'? –

Odpowiedz

27

Zgodnie z fragmentem kodu istnieje kilka metod (bindResources() i bindListeners() itp.) Oznaczonych jako @Override, które nie są dziedziczone z oficjalnego API ani wyraźnie nazwane w AllResultsActivity. Załóżmy, że są one poprawnie wdrożone i zaangażowane w super-klasę lub gdzieś indziej. Problem widzę w kodzie jest:

@Override 
public void onCreate(Bundle savedInstanceState) { 
    ... ... 

    loadItems(apiKey); // <-- method start AsyncTask, and finially involve mAllResultsAdapter.notifyDataSetChanged(); 
    initListview(); // <-- method that bind Adapter to ListView. i.e. mListView.setAdapter(mAllResultsAdapter); 
} 

Problem jest, gdy AysncTask wykonany i onPostExecute() nazywa się (gdzie mAllResultsAdapter.notifyDataSetChanged(); sprawdzony), adapter nie związany ListView jeszcze. Po prostu wywołanie initListview(); before loadItems (apiKey); powinien uczynić wyjątek java.lang.IllegalStateException: odchodzi.

Aktualizacja:
Wzięłam głęboki wygląd w kodzie, problem jest ArrayList, które wiąże się z adapterem jest zmieniana w wątku tła:

// proccesJSON() is called in AsyncTask.doInBackground() 
private void proccesJSON() throws JSONException, IOException { 
    ... ... 

    mAllResultsItem.add(item); // <-- mAllResultsItem is bound to mAllResultsAdapter 

    ... ... 
} 

Twój zasilacz jest rzeczywiście zmodyfikowana tle wątek, dokładnie tak, jak zasugerował wyjątek. Rozwiązaniem jest przeniesienie go do wątku UI lub po prostu owijając go runOnUiThread():

... ... 

runOnUiThread(new Runnable() { 
    public void run() { 
    mAllResultsItem.add(item); 
    mAllResultsAdapter.notifyDataSetChanged(); 
    } 
}); // end of runOnUiThread 

... ... 

nadzieję, że to pomaga.

+0

Dziękuję za odpowiedź, że metody odziedziczone po super-klasie, zmieniłem nazwę działania na tajemnicę dla naszej aplikacji klienckiej. Przetestuję to rozwiązanie i wrócę do Ciebie. –

+0

Wciąż nie ma szczęścia, ale to dziwne. przez większość czasu to działa, ale rzadko po prostu się zawiesza. –

+1

Co masz na myśli przez _realnie to po prostu zawiesza się? ten sam wyjątek? – yorkw

1

Wiem, że ten wątek ma 3 lata. Zostałem poproszony o naprawienie Zawartość adaptera uległa zmianie, ale ListView nie otrzymał powiadomienia o błędzie w istniejącym kodzie pod numerem. Zbadałem sposób użycia Timer i dodałem runOnUiThread(), ale problem nadal występował. Ale wszystko zostało zrobione w wątku UI!

W rzeczywistości, ListView pokazywał dane na podstawie niektórych katalogów systemu plików - to było równoważne wyświetlaniu wszystkich plików w katalogu w ListView. Funkcje odbierały dane bezpośrednio z katalogu, a kiedy Android mógł wykryć, że liczba plików się zmieniła, wyrzucił wyjątek.

Rozwiązaniem było zapisanie w pamięci podręcznej katalogu i zezwolenie na jego odświeżenie. Tak, zmiany na dysku nie mogły być natychmiast odzwierciedlone w widoku ... ale le mieux est l'ennemi du bien.

Powiązane problemy