2010-08-18 89 views
5

我剛剛遇到以下情況。我有一個Android應用程序,我想這可能會發生在多個應用程序中。這是關於標記/標記/分類,按你的意願調用它。我基本上有以下關係在SQLite數據庫ListView與來自多個「表」的數據的優化建議

--------     --------------    --------- 
| Tags |    | DeviceTags |   | Devices | 
|--------|    |--------------|   |---------| 
| ID  | 1 ------ * | ID   | * ------ 1 | ID  | 
| NAME |    | TAGS_ID  |   | NAME | 
--------    | DEVICE_ID |   | ...  | 
          --------------    --------- 

一切都暴露在我寫的ContentProvider。到目前爲止,一切都很好。

在UI部分,我有一個ListActivity顯示所有存儲的設備(從設備表),並進一步自定義用戶界面,我創建自定義行項目顯示前面的小圖像根據設備類型等等

我現在想實現的目標是也顯示每個設備的列表上的關聯標籤。現在這裏來了我的問題。對於簡單的設備列表中,我創建,我設置的bindView方法

@Override 
public void bindView(final View view, final Context context, final Cursor cursor) { 
    final int objectId = cursor.getInt(cursor.getColumnIndex(Devices._ID)); 

    TextView deviceName = (TextView) view.findViewById(R.id.deviceName); 
    deviceName.setText(...); //set it from the cursor 
    ... 
    TextView associatedTagsView = (TextView)...; 
    associatedTagsView.setText(...); //<<<???? This would need a call to a different table 
    ... 
} 

正如你所看到的,爲了能夠知道什麼樣的標籤我的設備已經相關的信息,根據自定義ResourceCursorAdapter,我需要查詢DeviceTags。所以我做了:

@Override 
public void bindView(final View view, final Context context, final Cursor cursor) { 
    ... 
    TextView associatedTagsView = (TextView)view.findViewById(R.id.deviceTags); 
    String tagsString = retrieveTagsString(view.getContext().getContentResolver(), objectId); 
    ... 
} 

private String retrieveTagsString(ContentResolver contentResolver, int objectId) { 
    Cursor tagForDeviceCursor = contentResolver.query(DroidSenseProviderMetaData.TABLE_JOINS.TAG_DEVICETAG,...); 
    if(tagForDeviceCursor != null && tagForDeviceCursor.moveToFirst()){ 
     StringBuffer result = new StringBuffer(); 

     boolean isFirst = true; 
     do{ 
      if(!isFirst) 
       result.append(", "); 
      else 
       isFirst = false; 

      result.append(retrieve name from cursor column...); 
     }while(tagForDeviceCursor.moveToNext()); 

     return result.toString(); 
    }  
    return null; 
} 

我測試了這個,它實際上工作得很好,但說實話我不覺得這樣做很好。不知何故似乎對我來說很奇怪...

有沒有更好的解決方案,如何解決這個問題?

//編輯:

CommonsWare的反饋這裏有點澄清之後。我很奇怪對CursorAdapter中的數據庫執行第二次查詢,基本上這會導致每行有一個查詢,我擔心這會嚴重影響我的性能(我仍然需要在具有相當數量的實際設備上測試它的數據來看看這會產生多大的影響)。

所以我的問題上是否有關於如何避免這個問題給我的數據模型,還是我的一些策略必須基本上是「活」與:)

回答

0

我用大約100個條目測試了我的解決方案(在我的問題中提出)。它仍然可用,但滾動並不像預期的那樣順利。正如CommonsWare已經指出的那樣,最好的做法是調整數據模型或至少適當地將其聚合。最後,光標包含在UI上顯示所需的所有數據。

我不想完全改變底層數據模型。我所做的是以某種方式彙總數據,即s.t.由ContentProvider的返回遊標包含包括代表相關的標籤的名字已經準備串了器件的數據:

| ID | NAME    | ... | LABELSSTRING | 
------------------------------------------------ 
| 1 | "My Device name" | ... | "Work, Friend" | 
| 1 | "Some other"  | ... |    | 
| 1 | "Yet another" | ... | "Work"   | 

這幾乎解決了這個問題,是因爲沒有必要在CursorAdapter的的bindView重新查詢( ..)爲每個設備,這btw。非常糟糕。這個解決方案可以通過使用SQLite的group_concat(X, Y) function

3

你在Twitter上,你間沒有」抱怨沒有得到任何反饋。我並不十分驚訝,因爲當你的問題有詳細的示範性水平,它有兩個主要的缺陷所害:

  1. 你的問題,到了最後,是模糊的
  2. 你的問題依賴於你自己的解釋「這」是什麼,我們不知道它

因此,我沒有清楚的圖片你認爲是什麼「怪異」。 do...while()循環? :-)

我打算出去走一走,猜測你的擔心是關於在你的ListView中爲每一行做第二個查詢和一串字符串連接。這完全取決於您是否認爲「以逗號分隔的標籤列表」是數據模型的一部分還是演示文稿的一部分。如果它是演示文稿的一部分,我不知道你如何避免你在這裏做什麼。

如果您確實認爲它是您的數據模型的一部分,請調整ContentProvider以提供以逗號分隔的標記列表作爲您首先查詢的任何內容(未顯示)的一部分。

在這兩種情況下,性能都是一個可能的問題。每行執行一個查詢,特別是在滾動時,可能會很糟糕。畢竟,Romain Guy反覆強調,你需要在你的適配器中重複使用行,並且我不得不想象數據庫查詢比膨脹佈局要貴一點。不幸的是,你使用了一段時間內強調空間的數據模型,所以你將不得不沿着線路支付風向標。

+0

對不起,我不知何故模糊的問題。沒有注意到,現在就修好了。但你完全符合我的問題(+1):)性能就是這樣。但考慮到1個設備可能有多個標籤的需求,我將不得不採用上面顯示的數據庫設計......當然,我可以做的是以某種方式「合併」設備標籤和標籤,但我想這會變得非常難看...也許我會更好地加入ContentProvider級別的所有內容我已經準備好了數據...如果我看到當前的解決方案嚴重影響性能,我會嘗試。 – Juri 2010-08-19 06:34:10

+0

我也會嘗試避免適配器中的第二個查詢。只需構建您的內容提供者,就可以在列表中顯示給用戶的時候列出所有需要的數據。 – Janusz 2010-08-19 07:53:18

+0

@Juri:「但是考慮到需要1個設備可能有多個標籤,我必須使用上面顯示的DB設計。」 - 不,你不知道。你只需要,如果你也從數據標籤的一面,並經常足以使其值得。您的替代方案是對數據進行非規範化處理,將逗號分隔的標記列表作爲設備表中的單個列。 – CommonsWare 2010-08-19 10:13:26