文章出處
文章列表
標記字段
代碼中有時候有這種需求:需要一個公共訪問的標記字段,以下稱為標記字段。
下面是案例:
一個訂單詳情頁面,如果頁面在顯示中,程序中其它地方需要訪問這個“正在查看中”的訂單信息,訂單詳情頁面打開和關閉時負責設置和清除公共字段所標記的訂單對象。在像Android這樣的設備上,假設頁面可以打開多個,但是用戶只會看到最上面的一個,那么此時只有處在任務棧最上面的OrderDetailActivity對象在其onStart和onStop中負責標記的訂單的設置。假設有1和2兩個詳情頁面依次被打開,然后依次關閉2、1,其onStart、onStop的執行順序可能是像下面的:
09-26 11:55:10.808 5493-5493/? D/hxwcc: onStart + @1
09-26 11:55:14.840 5493-5493/? D/hxwcc: onStart + @2
09-26 11:55:15.228 5493-5493/? D/hxwcc: onStop + @1
09-26 11:55:16.672 5493-5493/? D/hxwcc: onStart + @1
09-26 11:55:17.076 5493-5493/? D/hxwcc: onStop + @2
09-26 11:55:19.548 5493-5493/? D/hxwcc: onStop + @1
可見onStart和onStop的執行是有交叉的。在對標記字段進行賦值時,需要考慮這種“相互干擾”,這里的執行都是在UI線程中執行,多線程環境下當然更容易產生這樣的交叉賦值。從需求上看,不是當前對象設置的標記它就不應該去清除,因為另一個對象在重新設置標記字段的值得時候自動清除了上一標記值。
可以使用一個額外的字段記錄對標記進行賦值的對象,然后通過比較當前對象標記試圖操作的對象和之前設置已有標記值的對象就可以得到需要的標記作用。
下面設計一個類型FlagField來組合標記值和標記人,使得標記字段的含義更加內聚。
FlagField類型
代碼如下:
/**
* 標記字段,用來存儲被公共訪問的帶有賦值者信息的數據。賦值者在合適的時間賦值,
* 之后可以清除標記值,如果中間有其它
* 賦值者重新標記則清除操作不做任何動作——訪問者繼續 訪問新的標記。
*/
public class FlagField<T> {
private T field;
private Object provider;
public void mark(T field, Object provider) {
synchronized (this) {
this.field = field;
this.provider = provider;
}
}
public T getField() {
synchronized (this) {
return this.field;
}
}
public Object getProvider() {
synchronized (this) {
return this.provider;
}
}
public boolean isMarked() {
synchronized (this) {
return field != null;
}
}
public void clear(Object provider) {
synchronized (this) {
if (provider == this.provider) {
field = null;
provider = null;
}
}
}
}
上面提供了線程安全的版本,如果不需要多線程控制去掉synchronized (this)即可。
使用案例如下:
public class OrderDetailActivity extends Activity {
/** 當前正在被查看的訂單id */
public static FlagField<Integer> viewingOrderId = new FlagField<Integer>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewingOrderId.mark(10086, this);
}
@Override
protected void onDestroy() {
super.onDestroy();
viewingOrderId.clear(this);
}
}
(本文是由Atom編寫)
文章列表
全站熱搜