Как правильно обновлять активность, основываясь на ответах Сети? - PullRequest
1 голос
/ 02 сентября 2011

Я реализую приложение, которое является своего рода приложением VOIP.Таким образом, мое приложение является своего рода сетевым приложением.Теперь я хочу реализовать две части в моем приложении, одна часть с графическим интерфейсом, а другая часть с сетью.Моя часть с графическим интерфейсом будет просто содержать действия и обработку взаимодействия с пользователем.Моя сетевая часть должна обрабатывать все связанные с сетью действия, такие как обработка входящих сетевых данных и отправка данных в сеть на основе взаимодействия с графическим интерфейсом.Теперь, когда есть входящие данные, я хочу обновить некоторые действия, чья ссылка отсутствует в сетевом модуле.Итак, что может быть лучшим способом обновить активность из другого класса?В моем случае другой класс - это мой класс Network.Короче говоря, я хотел бы спросить, какой должна быть архитектура в таком сценарии?т.е. сетевая часть должна запускаться в отдельном потоке и оттуда она должна обновлять GUI?

Ответы [ 4 ]

2 голосов
/ 02 сентября 2011

В зависимости от типа / размера данных, которые необходимо отправить в мероприятие, вы можете использовать один из нескольких вариантов.

  1. Используйте один из методов, описанных здесь .
  2. Используйте BroadcastReceiver: зарегистрируйте его в Activity и затем запустите соответствующие Intent s в Service, который обрабатывает сетевой код.
  3. Создайте Activity привязывается к вашему Service, а затем передает Handler, который вы отправляете Message s.
1 голос
/ 02 сентября 2011

Я написал подобные приложения, и я предпочитаю метод Handler. На самом деле я написал класс Abstract Activity, чтобы выполнить всю тяжелую работу и просто расширить его в любой деятельности, которая хочет получать уведомления об изменениях.

Чтобы использовать следующий код, просто получите действие, чтобы расширить UpdatableActivity и переопределить метод dataUpdated (). Этот метод вызывается, когда ваша служба уведомляет обработчик об обновлении данных. В коде службы введите свой код для обновления в методе update () (или измените его для вызова существующего кода). Это позволяет деятельности вызывать this.updateService () для принудительного обновления. Служба может вызвать метод sendMessageToUI (), чтобы уведомить все заинтересованные действия об обновлении данных.

Вот как выглядит абстрактная деятельность:

public abstract class UpdatableActivity extends Activity {

public static final String TAG = "UpdatableActivity (Abstract)";
private final Messenger mMessenger = new Messenger(new IncomingHandler());
private Messenger mService = null;
private boolean mIsBound;


protected class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        if (Constants.LOG_DEBUG) Log.d(TAG, "Service has notified us of an update: ");
        switch (msg.arg1) {
        case UpdateService.MSG_DATA_UPDATED:
            dataUpdated();
            break;
        default: super.handleMessage(msg);
        }
    }
}

private ServiceConnection mConnection = new ServiceConnection() {
    public void onServiceConnected(ComponentName className, IBinder service) {
        mService = new Messenger(service);
        try {
            Message msg = Message.obtain(null, UpdateService.MSG_REGISTER_CLIENT);
            msg.replyTo = mMessenger;
            mService.send(msg);
        } catch (RemoteException e) {
            // In this case the service has crashed before we could even do anything with it
        }
    }

    public void onServiceDisconnected(ComponentName className) {
        // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
        mService = null;
    }
};


    /**Override this method in you acctivity to handle the update */
public abstract void dataUpdated();

void doBindService() {
    if (Constants.LOG_DEBUG) Log.d(TAG, "Binding to service...");
    bindService(new Intent(this, UpdateService.class), mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
}

void doUnbindService() {
    if (mIsBound) {
        // If we have received the service, and hence registered with it, then now is the time to unregister.
        if (mService != null) {
            try {
                Message msg = Message.obtain(null, UpdateService.MSG_UNREGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                // There is nothing special we need to do if the service has crashed.
            }
        }
        // Detach our existing connection.
        unbindService(mConnection);
        mIsBound = false;
    }
}

public void updateService() {
    if (Constants.LOG_DEBUG) Log.d(TAG,"Updating Service...");
    if (mIsBound) {
        if (mService != null) {
            try {
                Message msg = Message.obtain(null, UpdateService.MSG_SET_INT_VALUE, UpdateService.MSG_DO_UPDATE, 0);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                if (Constants.LOG_ERROR) Log.e(TAG,Log.getStackTraceString(e));
            }
        }
    } else {
        if (Constants.LOG_DEBUG) Log.d(TAG, "Fail - service not bound!");
    }
}

pu
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.doBindService();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    try {
        doUnbindService();
    } catch (Throwable t) {
        if (Constants.LOG_ERROR) Log.e(TAG, "Failed to unbind from the service", t);
    }
}
}

А вот как выглядит сервис:

public class UpdateService extends Service {

public static final String TAG = "UpdateService";

public static final int MSG_DATA_UPDATED = 0;
public static final int MSG_REGISTER_CLIENT = 1;
public static final int MSG_UNREGISTER_CLIENT = 2;
public static final int MSG_DO_UPDATE = 3;
public static final int MSG_SET_INT_VALUE = 4;

private static boolean isRunning = false;

private Handler handler = new IncomingHandler();
private final Messenger mMessenger = new Messenger(handler);

private ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.


@Override
public IBinder onBind(Intent intent) {
    return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MSG_REGISTER_CLIENT:
            mClients.add(msg.replyTo);
            break;
        case MSG_UNREGISTER_CLIENT:
            mClients.remove(msg.replyTo);
            break;
        case MSG_SET_INT_VALUE:
            switch (msg.arg1) {
                case MSG_DO_UPDATE:
                    if (Constants.LOG_DEBUG) Log.d(TAG,"UI has asked to update");
                    update();
                    break;
            }
            break;
        default:
            super.handleMessage(msg);
        }
    }
}

 private void sendMessageToUI() {
     if (Constants.LOG_DEBUG) Log.d(TAG, "Notifying "+mClients.size()+" UI clients that an update was completed");
        for (int i=mClients.size()-1; i>=0; i--) {
            try {
                // Send data as an Integer
                mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, MSG_DATA_UPDATED, 0));


            } catch (RemoteException e) {
                // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
                mClients.remove(i);
            }
        }
    }

 public static boolean isRunning()
    {
        return isRunning;
    }


@Override
public void onCreate() {
    super.onCreate();
    isRunning = true;
    if (Constants.LOG_DEBUG) Log.d(TAG, "Service Started");
    update();
}


@Override
public void onDestroy() {
    if (Constants.LOG_DEBUG) Log.d(TAG, "Service Destroyed");
    isRunning = false;
}

private void update() {
/**Your code to do an update goes here */
}


}
0 голосов
/ 02 сентября 2011

Я бы напрямую опубликовал в основной ветке пользовательского интерфейса,

Обработчик mHandler = новый обработчик (Looper.getMainLooper ());

mHandler.post (new Runnable () {...});

0 голосов
/ 02 сентября 2011

Да, лично я считаю, что сеть и пользовательский интерфейс должны быть в отдельных потоках.Способ, которым я склонен общаться между ними, что, вероятно, не является рекомендуемым правильным способом, но он работает для меня, это создать глобальную переменную в вашем классе приложения.надеюсь, это поможет немного

...