[英]Dispatch user action to activities in backstack
我正在開發社交應用。 讓我們假設我有一堆活動A -> B -> C -> D
D在前台,用戶按下“喜歡”按鈕到那里(帖子,評論,用戶等)。為了刷新他們的數據,通知所有其他有關此操作的活動的最佳方法是什么? 我在這里看到3個選項:
BasicUserInfo
, UserInfo
, DetailedUserInfo
),則需要大量代碼。 真實的例子:
在Instagram:我打開一些特定用戶的個人資料(A),在那里我打開一些特定的帖子(B),再打開個人資料(A)等等 - > B - > A - > B - > A ....所以它每次從Web加載數據。 在步驟“n + 1”上出現對該帖子的新評論。 如果我開始通過我的backstack回來,我將看到Instagram已經向所有B活動發送了這個“新”評論,而沒有從web重新加載任何數據。 所以我很有意思他們是怎么做到的。
通知系統(事件,觀察者, BroadcastReceiver
,...)的主要用例是當您希望收件人在發生某些事情時或多或少立即采取行動時。
我認為這不是這種情況:后台活動不需要立即采取行動,因為它們不可見。 此外,他們甚至可能不再存在(殺死/凍結)。 他們實際需要的是在他們回到前台時(可能在重新創建之后)獲取最新數據。
為什么不簡單地在onStart()
或onResume()
觸發刷新(使用Loader
或你已經使用的任何東西)?
如果需要保持'喜歡'狀態,你可以在D
的onPause()
。 如果沒有,喜歡的對象可以存儲在一個全局變量中(這實際上是一個粘性事件)
您可以使用LocalBroadcastManager
通知您的堆疊活動您的Liked事件已發生
假設你的活動D:
private void liked() {
Log.d("liked", "Broadcasting message");
Intent intent = new Intent("like-event");
// You can also include some extra data.
intent.putExtra("message", "my like event occurs!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
現在它將通知所有在此廣播接收者注冊的活動
例如,在您的活動A,B,C中:
@Override
public void onCreate(Bundle savedInstanceState) {
...
// Register to receive messages.
// We are registering an observer (mMessageReceiver) to receive Intents
// with actions named "custom-event-name".
LocalBroadcastManager.getInstance(this).registerReceiver(mLikeEventReceiver ,
new IntentFilter("like-event"));
}
// Our handler for received Intents. This will be called whenever an Intent
// with an action named "like-event" is broadcasted.
private BroadcastReceiver mLikeEventReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
@Override
protected void onDestroy() {
// Unregister since the activity is about to be closed.
LocalBroadcastManager.getInstance(this).unregisterReceiver(mLikeEventReceiver );
super.onDestroy();
}
參考: [ http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html] [1 ] [ 如何使用LocalBroadcastManager? [ https://androidcookbook.com/Recipe.seam?recipeId=4547] [3 ]
處理此類事情的經典方法是使用BroadcastReceivers 。
這是一個示例接收器:
public class StuffHappenedBroadcastReciever extends BroadcastReceiver {
private static final String ACTION_STUFF_HAPPENED = "stuff happened";
private final StuffHappenedListener stuffHappenedListener;
public StuffHappenedBroadcastReciever(@NonNull Context context, @NonNull StuffHappenedListener stuffHappenedListener) {
this.stuffHappenedListener = stuffHappenedListener;
context.registerReceiver(this, new IntentFilter(ACTION_STUFF_HAPPENED));
}
public static void notifyStuffHappened(Context context, Bundle data) {
Intent intent = new Intent(ACTION_STUFF_HAPPENED);
intent.putExtras(data);
context.sendBroadcast(intent);
}
@Override
public void onReceive(Context context, Intent intent) {
stuffHappenedListener.onStuffHappened(intent.getExtras());
}
public interface StuffHappenedListener {
void onStuffHappened(Bundle extras);
}
}
以及如何將其附加到活動:
public class MainActivity extends AppCompatActivity implements StuffHappenedBroadcastReciever.StuffHappenedListener {
private StuffHappenedBroadcastReciever mStuffHappenedReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mStuffHappenedReceiver = new StuffHappenedBroadcastReciever(this, this);
}
@Override
protected void onDestroy() {
unregisterReceiver(mStuffHappenedReceiver);
super.onDestroy();
}
@Override
public void onStuffHappened(Bundle extras) {
// do stuff here
}
}
只要活動處於活動狀態,就會調用“onStuffHappened”。
我同意@bwt的方法。 當您想立即通知某些內容時,這些通知系統應該很重要。
我的方法是緩存系統。 您不需要處理“如果活動是后台堆疊或新創建的”,您始終需要在活動的onResume
中查詢所需內容。 因此,您將始終獲得最新的數據。
從服務器獲取數據時,還需要在本地數據庫中復制數據模型。 在您ping服務器之前,例如用戶帖子中有類似內容時,您需要將其設置為本地數據庫中的Flag
,並將您的Http請求發送到您的服務器,說“嘿,這個帖子很受歡迎”。 稍后當您收到此請求的響應時,如果成功與否,請嘗試再次修改此標志。
因此,在您的活動中,如果您從onResume
本地數據庫查詢,您將獲得最新的數據。 對於其他用戶帖子的更改,您可以使用BroadcastReceiver
來反映Visible活動中的更改。
PS:您可以檢查Realm.io以獲得相對較快的查詢,因為您需要更快地進行本地數據庫調用。
正如許多其他答案所未解釋的那樣,這是一個典型的例子,其中BroadcastReceiver可以輕松完成工作。
我還建議將LocalBroadcastManager類與BroadcastReceiver結合使用。 從BroadcastReceiver的文檔:
如果您不需要跨應用程序發送廣播,請考慮將此類與LocalBroadcastManager一起使用,而不是使用下面描述的更一般的工具。 這將為您提供更高效的實現(無需跨進程通信),並允許您避免考慮與其他應用程序能夠接收或發送您的廣播相關的任何安全問題。
為了刷新他們的數據?
這就是答案。 活動不應該擁有數據。 活動提供數據並允許用戶對其采取行動。 數據本身應該位於一個單獨的實體中,可以通過活動實例(模型)與其進行交互。
此外, 不應該假設在后棧中始終存在活動實例。 當用戶導航回來時,系統可以銷毀這些活動,然后通過系統將其重新創建為不同的對象。 創建整個活動時,數據始終會刷新。
將數據處理分離到專門的類,可以通過活動輕松訪問,並可以按需提供數據/事件綁定到活動。 綁定Service
是一個很好的候選人。
就不從Web加載數據而言,您可以設置最近訪問的數據的本地緩存(緩存,因為移動設備有嚴格的存儲限制,服務器和數據庫不是這樣)。 因此,用戶端的任何更改也會在傳播到服務器的同時提交到此緩存。 所有這些都更好地由專門的數據類封裝,而不是依賴於活動類中的反向堆棧或特殊代碼。
作為模式,您可以為所涉及的數據實體構建Model
類。 編寫Web API接口實現以與服務器通信。 然后,在API接口之前放置一個緩存層。 緩存將保留對API層的傳出更改和傳入更新,並在不需要服務器調用時簡單地反映數據請求。
Cache必須主要做3件事:
現在大多數緩存實現處理原始字節。 我建議使用Realm這樣的東西,一個對象數據庫並將其包裝在緩存中。 因此,請求用戶推文的典型流程是:
Tweets
表中查找最后獲取的推文列表,並立即返回該消息。 通過維護與服務器的套接字連接並實時接收有趣的更改,您的數據實現可以更進一步。 只要有新數據傳入,服務器就會調用上面的第5步。
TLDR; 將數據管理與“活動”分開,然后您可以獨立於UI關注點進行演變。
如果您必須對某些數據進行所有活動的更改,您可以遵循界面模式。例如,您有一個自定義類類ActivityData,其中包含您需要在所有活動中更新的內容
步驟1:
創建如下界面
public interface ActivityEventListener
{
ActivityData getData( Context context,
Activity activity );
}
第2步:
創建一個BaseActivity,用於引用您在應用程序中具有的所有活動,並按如下方式實現接口
public class BaseActivity extends Activity
{
protected AcitivityData mData= null;
@Override
protected void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
}
protected ActivityEventListener mListener = new ActivityEventListener()
{
@Override
public ActivityData getData( Context context,
Activity activity )
{
// TODO Auto-generated method stub
return mData;
}
};
}
第3步:使用BaseActivity擴展您自己的活動,例如A或B或C .......
公共類A擴展BaseActivity {
ActivityData mData;
@Override
protected void onCreate( Bundle savedInstanceState )
{
mData = mListener.getData(this,this);
updateWidgets(mData);
}
}
其中updateWidgets是一個函數,您可以在其中定義UI元素並使用與接口相關的數據
由於您的所有活動B / C /等都可以獲得ActivityData的參考。 活動表單backstack將通過onStart()開始執行,用戶可以處理ActivityData中存在的詳細信息
在您喜歡上次活動的情況下,您可以更新ActivtyData的對象,當后台堆棧活動恢復或啟動時,您可以獲得更新的數據,因為您的Backstack活動擴展了BaseActiivty具有接口。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.