2014-01-23 82 views
3

我有三個可滑動的選項卡。在第一個選項卡中,我有一個包含1000多個項目的列表視圖。listView.setAdapter是如此呆滯?

我試圖用Asynctask和Runnable填充列表,我沒有問題。

問題是當我試圖將適配器分配給列表視圖。我注意到無論有多少物品在適配器中,無論它是1還是1000,當它試圖做:listView.setAdapter(適配器)時,它跳過大約30幀...

由於listView.setAdapter(適配器)在第一個選項卡中使用,每當用戶嘗試輸入該選項卡時,UI會凍結幾毫秒。雖然這不是一個嚴重的問題,但我不喜歡它。

問題是:這是正常的,當我們調用listView.setAdapter(適配器)的UI凍結了幾毫秒,並跳過一些幀?有沒有辦法解決這個問題?

我清楚嗎?

Carpet_handler ch; // my db handler 
ListView listview; 

public ArrayList<CarpetGen> carpetGens; 
CarpetAdapter adapter; 
boolean loadingMore=false; 
int offset; 
Context ctx; 
@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 

    View rootView = inflater.inflate(R.layout.fragment_first_page_customers, container, false); 
    ch=new Carpet_handler(getActivity()); // db handler 
    listview = (ListView) rootView.findViewById(R.id.listView2); 
    ctx=this.getActivity(); 
    carpetGens = new ArrayList<CarpetGen>(); 
    offset=0; 
    adapter = new CarpetAdapter(getActivity(), R.layout.row, carpetGens); 



    listview.setAdapter(adapter); // adapter is empty first time, runnable fills it 
    listview.setOnItemClickListener(myClickListener); 



    //Here is where the magic happens 
    listview.setOnScrollListener(new OnScrollListener(){ 
     @Override 
     public void onScrollStateChanged(AbsListView view, int scrollState) {} 
     @Override 
     public void onScroll(AbsListView view, int firstVisibleItem, 
      int visibleItemCount, int totalItemCount) { 
      //what is the bottom iten that is visible 
      int lastInScreen = firstVisibleItem + visibleItemCount; 
      //is the bottom item visible & not loading more already ? Load more ! 
      if((lastInScreen == totalItemCount) && !(loadingMore)){ 
       Thread thread = new Thread(null, loadMoreListItems); 
       thread.start(); 
      } 
     } 
    }); 


    return rootView; 
} 



    //Runnable to load the items 
    private Runnable loadMoreListItems = new Runnable() { 
    @Override 
    public void run() { 
     //Set flag so we cant load new items 2 at the same time 
     loadingMore = true; 
     //Reset the array that holds the new items 
     carpetGens= new ArrayList<CarpetGen>(); 
     carpetGens.addAll(ch.getAllCustomerCarpets1(getActivity().getIntent().getIntExtra("recordid", -1), offset)); 
     offset+=15; 
     //Done! now continue on the UI thread 
     if(getActivity()==ctx) 
      getActivity().runOnUiThread(returnRes); 

    } 
}; 

//Since we cant update our UI from a thread this Runnable takes care of that! 
private Runnable returnRes = new Runnable() { 
    @Override 
    public void run() { 
     //Loop thru the new items and add them to the adapter 
     if(carpetGens != null && carpetGens.size() > 0){ 
        for(int i=0;i < carpetGens.size();i++) 
        adapter.add(carpetGens.get(i)); 
       } 
       adapter.notifyDataSetChanged(); 
       loadingMore = false; 
     } 
    }; 

這裏是我的適配器:

public class CarpetAdapter extends ArrayAdapter<CarpetGen> { 

private final Context context; 
private final int rowResourceId; 
//private final String[] Ids; 
private final ArrayList<CarpetGen> Objects; 

public CarpetAdapter(Context context, int textViewResourceId, ArrayList<CarpetGen> objects){//Arr[] objects) { 
    super(context, textViewResourceId, objects); 
    // TODO Auto-generated constructor stub 
    this.context = context; 
    this.rowResourceId = textViewResourceId; 
    this.Objects = objects; 

} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    ViewHolder holder; 
    View rowView = convertView; 
    CarpetGen i = Objects.get(position); 
    if (rowView == null) { 
     LayoutInflater inflater = (LayoutInflater) context 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

     rowView = inflater.inflate(R.layout.row, parent, false); 
     //TextView textView = (TextView) rowView.findViewById(R.id.textView); 

     //textView.setText(i.Result_String); 

     holder = new ViewHolder(); 
     holder.title = (TextView) rowView 
       .findViewById(R.id.textView); 

     rowView.setTag(holder);    
    } else {   
     holder = (ViewHolder) rowView.getTag(); 
    } 

    holder.title.setText(i.Result_String); 



    return rowView; 

} 
static class ViewHolder { 
TextView title; 

} }

+0

更新了第一篇文章,包括我的自定義arrayadapter。 – SMahdiS

+1

我找到了解決方案。這是因爲我使用了自定義文本視圖。 – SMahdiS

回答

1

我認爲這是完全正常的。請記住,當您調用setAdapter()方法時,它必須刷新佈局,即使它沒有元素,您正在執行取決於您的實現的一些操作,但基本上它不是0秒的奇蹟。正如@laalto所建議的那樣,自定義適配器實現也可能存在瓶頸,因此您可能需要考慮在Thread(或基本上爲AsyncThread)中執行一些工作。但正如我所說,我不擔心它(總體而言,如果此幀跳過發生在虛擬設備中)。

+0

我希望是正常的。測試是在真實的設備上(而不是仿真器)。正如我所說,我以前試過Asynstask,它仍然是一樣的。 – SMahdiS

+0

如果你已經試過移動到'Thread's(或者你的例子中的'AsyncTask')你最困難的工作並且仍然存在,我真的不用擔心。正如我所說,這取決於幾個因素,一個是你的實施。如果你試圖優化它,它仍然存在,這是由於佈局處理,所以沒有別的可做。 – nKn

+0

我也懷疑這是由於佈局處理。只是想從其他人那裏聽到這個消息:D – SMahdiS

0

,我認爲你應該儘量做到以下幾點:

月1日 - 使用的AsyncTask加載的項目doInBakground方法。

2nd - listView.setAdapter在doPostExecute方法中的AsyncTask中。

希望有幫助

+1

謝謝,但由於PostExecute在UI線程上運行,問題仍然存在。我試過這個解決方案,它仍然跳過一些框架。 – SMahdiS

+0

您可以嘗試在自定義適配器中創建一個加載數據的線程,然後在UI線程中運行它,也許這會給你一些時間。 –