2012-06-04 8 views

Antwort

12

Bin ich denke richtig, dass ich nicht ‚klebrig schicken 'Broadcasts mit LocalBroadcastManager?

Ja, Sie haben Recht.

Wenn so scheint dies sehr kurzsichtig vor allem, wenn eine App nutzt Fragmente, die in und aus während des App-Lebenszyklus und setzt auf Broadcast-Daten ausgetauscht werden können ..

Sie sind willkommen, die nehmen Quellcode zu LocalBroadcastManager und erstellen Sie Ihre eigenen klebrigen Erweiterungen, wenn Sie dies wünschen. Persönlich würde ich andere Mittel zur Speicherung solcher Daten verwenden (Modellfragmente, Singletons oder persistente Datenspeicher, je nach Szenario).

+0

Ich habe einige Fragmente auf dem Bildschirm, und ich möchte, dass je nachdem, was "Haupt" -Fragment geladen ist, ein kleines Fragment auf der Unterseite ändert seine Nummer. Ich wollte dies tun, indem ich eine Sendung über das OnResume des Hauptfragments sendete. Aber das Fragment, das die Nummer hätte anzeigen sollen, ist zu diesem Zeitpunkt nicht geladen. Wie kann ich das machen? .... –

+1

@QuadroQ: Lassen Sie das Fragment die Daten von irgendwo ziehen. Oder wechseln Sie zu einem Event-Bus, der diese Art von Pattern anbietet (der EventBus von greenrobot bietet klebrige Events an; Squares Otto bietet '@ Producer' an). – CommonsWare

+0

Danke! Ich dachte an Otto! –

7

Wie @CommonsWare sagte, habe ich versucht, Sticky mit LocalBroadcastManager Quellcodes zu implementieren. Überprüfen Sie dies: https://gist.github.com/lidemin/5cd4080ebbc74154a0e7

Nicht sicher, ob es der beste Weg ist, das zu tun. Es funktioniert bis jetzt gut. Persönlich bevorzuge ich Otto.

public class StickyLocalBroadcastManager { 

private static class ReceiverRecord { 
    final IntentFilter filter; 
    final BroadcastReceiver receiver; 
    boolean broadcasting; 

    ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) { 
     filter = _filter; 
     receiver = _receiver; 
    } 

    @Override 
    public String toString() { 
     StringBuilder builder = new StringBuilder(128); 
     builder.append("Receiver{"); 
     builder.append(receiver); 
     builder.append(" filter="); 
     builder.append(filter); 
     builder.append("}"); 
     return builder.toString(); 
    } 
} 

private static class BroadcastRecord { 
    final Intent intent; 
    final ArrayList<ReceiverRecord> receivers; 

    BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers) { 
     intent = _intent; 
     receivers = _receivers; 
    } 
} 

private static final String TAG = "LocalBroadcastManager"; 
private static final boolean DEBUG = false; 

private final Context mAppContext; 

private final HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers 
     = new HashMap<BroadcastReceiver, ArrayList<IntentFilter>>(); 
private final HashMap<String, ArrayList<ReceiverRecord>> mActions 
     = new HashMap<String, ArrayList<ReceiverRecord>>(); 

private final ArrayList<BroadcastRecord> mPendingBroadcasts 
     = new ArrayList<BroadcastRecord>(); 

private final ArrayList<Intent> mStickyBroadcasts 
     = new ArrayList<Intent>(); 

static final int MSG_EXEC_PENDING_BROADCASTS = 1; 

private final Handler mHandler; 

private static final Object mLock = new Object(); 
private static StickyLocalBroadcastManager mInstance; 

public static StickyLocalBroadcastManager getInstance(Context context) { 
    synchronized (mLock) { 
     if (mInstance == null) { 
      mInstance = new StickyLocalBroadcastManager(context.getApplicationContext()); 
     } 
     return mInstance; 
    } 
} 

private StickyLocalBroadcastManager(Context context) { 
    mAppContext = context; 
    mHandler = new Handler(context.getMainLooper()) { 

     @Override 
     public void handleMessage(Message msg) { 
      switch (msg.what) { 
       case MSG_EXEC_PENDING_BROADCASTS: 
        executePendingBroadcasts(); 
        break; 
       default: 
        super.handleMessage(msg); 
      } 
     } 
    }; 
} 

/** 
* Register a receive for any local broadcasts that match the given IntentFilter. 
* 
* @param receiver The BroadcastReceiver to handle the broadcast. 
* @param filter Selects the Intent broadcasts to be received. 
* @see #unregisterReceiver 
*/ 
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { 
    synchronized (mReceivers) { 
     ReceiverRecord entry = new ReceiverRecord(filter, receiver); 
     ArrayList<IntentFilter> filters = mReceivers.get(receiver); 
     if (filters == null) { 
      filters = new ArrayList<IntentFilter>(1); 
      mReceivers.put(receiver, filters); 
     } 
     filters.add(filter); 
     for (int i = 0; i < filter.countActions(); i++) { 
      String action = filter.getAction(i); 
      ArrayList<ReceiverRecord> entries = mActions.get(action); 
      if (entries == null) { 
       entries = new ArrayList<ReceiverRecord>(1); 
       mActions.put(action, entries); 
      } 
      entries.add(entry); 
     } 
     //check sticky broadcasts 
     for (Intent intent : mStickyBroadcasts) { 
      if (mActions.containsKey(intent.getAction())) { 
       sendBroadcast(intent, false); 
      } 
     } 
    } 
} 

/** 
* Unregister a previously registered BroadcastReceiver. <em>All</em> 
* filters that have been registered for this BroadcastReceiver will be 
* removed. 
* 
* @param receiver The BroadcastReceiver to unregister. 
* @see #registerReceiver 
*/ 
public void unregisterReceiver(BroadcastReceiver receiver) { 
    synchronized (mReceivers) { 
     ArrayList<IntentFilter> filters = mReceivers.remove(receiver); 
     if (filters == null) { 
      return; 
     } 
     for (int i = 0; i < filters.size(); i++) { 
      IntentFilter filter = filters.get(i); 
      for (int j = 0; j < filter.countActions(); j++) { 
       String action = filter.getAction(j); 
       ArrayList<ReceiverRecord> receivers = mActions.get(action); 
       if (receivers != null) { 
        for (int k = 0; k < receivers.size(); k++) { 
         if (receivers.get(k).receiver == receiver) { 
          receivers.remove(k); 
          k--; 
         } 
        } 
        if (receivers.size() <= 0) { 
         mActions.remove(action); 
        } 
       } 
      } 
     } 
    } 
} 

/** 
* remove the sticky broadcasts . 
* @param action is the action need to be removed. 
*/ 
public void removeStickyBroadcast(String action) { 
    if (action == null || action.length() <= 0) { 
     return; 
    } 
    synchronized (mStickyBroadcasts) { 
     Iterator<Intent> intentIterator = mStickyBroadcasts.iterator(); 
     while (intentIterator.hasNext()) { 
      Intent intent = intentIterator.next(); 
      if (action.equalsIgnoreCase(intent.getAction())) { 
       intentIterator.remove(); 
      } 
     } 
    } 
} 

/** 
* remove all the sticky broadcasts. 
*/ 
public void removeAllStickyBroadcasts(){ 
    synchronized (mStickyBroadcasts){ 
     mStickyBroadcasts.clear(); 
    } 
} 

/** 
* send broadcast with specified action. 
* @param action is the action . 
* @return 
*/ 
public boolean sendBroadcast(String action){ 
    Intent intent = new Intent(action); 
    return sendBroadcast(intent); 
} 

/** 
* send broadcast with specified action. 
* @param action is the action . 
* @return 
*/ 
public boolean sendBroadcast(String action, boolean isSticky){ 
    Intent intent = new Intent(action); 
    return sendBroadcast(intent, isSticky); 
} 

/** 
* Broadcast the given intent to all interested BroadcastReceivers. This 
* call is asynchronous; it returns immediately, and you will continue 
* executing while the receivers are run. 
* 
* @param intent The Intent to broadcast; all receivers matching this 
*    Intent will receive the broadcast. 
* @see #registerReceiver 
*/ 
public boolean sendBroadcast(Intent intent) { 
    return sendBroadcast(intent, false); 
} 

/** 
* Broadcast the given intent to all interested BroadcastReceivers. This 
* call is asynchronous; it returns immediately, and you will continue 
* executing while the receivers are run. 
* 
* @param intent The Intent to broadcast; all receivers matching this 
*     Intent will receive the broadcast. 
* @param isSticky The flag of this intent is need to be sticky or not. 
* @see #registerReceiver 
*/ 
public boolean sendBroadcast(Intent intent, boolean isSticky) { 
    if (isSticky) { 
     mStickyBroadcasts.add(intent); 
    } 
    synchronized (mReceivers) { 
     final String action = intent.getAction(); 
     final String type = intent.resolveTypeIfNeeded(
       mAppContext.getContentResolver()); 
     final Uri data = intent.getData(); 
     final String scheme = intent.getScheme(); 
     final Set<String> categories = intent.getCategories(); 

     final boolean debug = DEBUG || 
       ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); 
     if (debug) Log.v(
       TAG, "Resolving type " + type + " scheme " + scheme 
         + " of intent " + intent); 

     ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction()); 
     if (entries != null) { 
      if (debug) Log.v(TAG, "Action list: " + entries); 

      ArrayList<ReceiverRecord> receivers = null; 
      for (int i = 0; i < entries.size(); i++) { 
       ReceiverRecord receiver = entries.get(i); 
       if (debug) Log.v(TAG, "Matching against filter " + receiver.filter); 

       if (receiver.broadcasting) { 
        if (debug) { 
         Log.v(TAG, " Filter's target already added"); 
        } 
        continue; 
       } 

       int match = receiver.filter.match(action, type, scheme, data, 
         categories, "LocalBroadcastManager"); 
       if (match >= 0) { 
        if (debug) Log.v(TAG, " Filter matched! match=0x" + 
          Integer.toHexString(match)); 
        if (receivers == null) { 
         receivers = new ArrayList<ReceiverRecord>(); 
        } 
        receivers.add(receiver); 
        receiver.broadcasting = true; 
       } else { 
        if (debug) { 
         String reason; 
         switch (match) { 
          case IntentFilter.NO_MATCH_ACTION: 
           reason = "action"; 
           break; 
          case IntentFilter.NO_MATCH_CATEGORY: 
           reason = "category"; 
           break; 
          case IntentFilter.NO_MATCH_DATA: 
           reason = "data"; 
           break; 
          case IntentFilter.NO_MATCH_TYPE: 
           reason = "type"; 
           break; 
          default: 
           reason = "unknown reason"; 
           break; 
         } 
         Log.v(TAG, " Filter did not match: " + reason); 
        } 
       } 
      } 

      if (receivers != null) { 
       for (int i = 0; i < receivers.size(); i++) { 
        receivers.get(i).broadcasting = false; 
       } 
       mPendingBroadcasts.add(new BroadcastRecord(intent, receivers)); 
       if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) { 
        mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS); 
       } 
       return true; 
      } 
     } 
    } 
    return false; 
} 

/** 
* Like {@link #sendBroadcast(Intent, boolean)}, but if there are any receivers for 
* the Intent this function will block and immediately dispatch them before 
* returning. 
*/ 
public void sendBroadcastSync(Intent intent) { 
    if (sendBroadcast(intent, false)) { 
     executePendingBroadcasts(); 
    } 
} 

private void executePendingBroadcasts() { 
    while (true) { 
     BroadcastRecord[] brs = null; 
     synchronized (mReceivers) { 
      final int N = mPendingBroadcasts.size(); 
      if (N <= 0) { 
       return; 
      } 
      brs = new BroadcastRecord[N]; 
      mPendingBroadcasts.toArray(brs); 
      mPendingBroadcasts.clear(); 
     } 
     for (int i = 0; i < brs.length; i++) { 
      BroadcastRecord br = brs[i]; 
      for (int j = 0; j < br.receivers.size(); j++) { 
       br.receivers.get(j).receiver.onReceive(mAppContext, br.intent); 
      } 
     } 
    } 
} 
} 
+1

Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz zur Verfügung zu stellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. –

+0

@Markus Vielen Dank für Ihre Beratung. Erstmalige Antwort auf Stackoverflow. – Damon

Verwandte Themen