Best way to update Activity from a Queue

2020-07-18 11:41发布

问题:

I have a LinkedBlockingQueue in a Mediator in my "Producer-Mediator-Consumer" model. Producer first updates the Mediator adding to the activityQueue. Next the Consumer/Activity waits/listens on the queue and grabs the next item.

I want an Activity to see the queue size has changed and grab the next item. The Mediator has no visibility into the activity only the activity can see the Mediator. So how do I create this listener mechanism i want?

Here is my mediator class that holds the Queue and the Activity will somehow look at the queue and get informed if it needs to update. Data coming into the queue can be spotty and random at times so a polling mechanism will not work.

public class MediatorData {

    /** Queue for the Activity */
    LinkedBlockingQueue <byte[]> queueConsumer = new LinkedBlockingQueue <byte[]>();

    /**
     * Add data to a queue(s) for consumption
     */
    public void put(byte[] data) throws InterruptedException {
        queueConsumer.add(data);
    }

    /**
     * Return data from the queue for the Feature calculations
     */
    public byte[] getFeatureData() throws InterruptedException {
        return queueConsumer.poll(100, TimeUnit.MILLISECONDS);
    }

}

Example of my activity class, its a graphing class so the queue listener has to be efficient and fast.

public class DisplayGraph extends Activity {

    // populated from Application Class where its created
    pirvate MediatorData md;

    public void onCreate(Bundle savedInstanceState) {
        md = getMediator();  // This comes from the custom Application class

        ... some type of listener to queue 
    }

    private void getQueueData() {
        byte[] tv = md.queueConsumer.poll();
        // can't update textview  get exception CalledFromWrongThreadException
        ((TextView) DisplayGraph.this.findViewById(R.id.tv)).setText("TV " + tv[0]);
    }
}

回答1:

How about using Observer and Observable?

Could be something like this:

public class MediatorData extends Observable {

    /** Queue for the Activity */
    LinkedBlockingQueue <byte[]> queueConsumer = new LinkedBlockingQueue <byte[]>();

    /**
     * Add data to a queue(s) for consumption
     */
    public void put(byte[] data) throws InterruptedException {
        queueConsumer.add(data);
        setChanged();
        notifyObservers();
    }

    /**
     * Return data from the queue for the Feature calculations
     */
    public byte[] getFeatureData() throws InterruptedException {
        return queueConsumer.poll(100, TimeUnit.MILLISECONDS);
    }
}

And this:

public class DisplayGraph extends Activity implements Observer {

    // populated from Application Class where its created
    private MediatorData md;

    public void onCreate(Bundle savedInstanceState) {
        md = getMediator();  // This comes from the custom Application class
        md.addObserver(this);
    }

    private void getQueueData() {
        byte[] tv = md.queueConsumer.poll();
        // can't update textview  get exception CalledFromWrongThreadException
        ((TextView) DisplayGraph.this.findViewById(R.id.tv)).setText("TV " + tv[0]);
    }

    public void update(Observable arg0, Object arg1) {
        getQueueData();
    }
}


回答2:

Best way to handle this situation is to do this: Previous answer has errors in it.

public class MediatorData extends Observable {

    /** Queue for the Activity */
    LinkedBlockingQueue <byte[]> queueConsumer = new LinkedBlockingQueue <byte[]>();

    /**
     * Add data to a queue(s) for consumption
     */
    public void put(byte[] data) throws InterruptedException {
        queueConsumer.add(data);
        notifyObservers();
    }

    /**
     * Return data from the queue for the Feature calculations
     */
    public byte[] getFeatureData() throws InterruptedException {
        return queueConsumer.poll(100, TimeUnit.MILLISECONDS);
    }
}

Display activity needs to run the update on the UI Thread so use the runOnUiThread method.

public class DisplayGraph extends Activity implements Observer {

    // populated from Application Class where its created
    private MediatorData md;

    byte[] tv;

    public void onCreate(Bundle savedInstanceState) {
        md = getMediator();  // This comes from the custom Application class
        md.addObserver(this);
    }

    private void getQueueData() {
        tv = md.queueConsumer.poll();
        runOnUiThread(setRunnable);
    }

    public void update(Observable arg0, Object arg1) {
        getQueueData();
    }

    // Need to do this to update the data to the UI.
    final Runnable setImageRunnable = new Runnable() {
        public void run() {
            ((TextView) DisplayGraph.this.findViewById(R.id.tv)).setText("TV " + tv[0]);
        }
    };
}