根据网络响应更新活动的正确方法是什么?

时间:2011-09-02 05:14:21

标签: android android-networking android-gui

我正在实现一种VOIP应用程序。所以我的应用程序是一种网络应用程序。现在我想在我的应用程序中实现两个部分,一个是GUI部分,一个是网络部分。我的GUI部分将包含用户交互的活动和处理。我的网络部分应该处理所有与网络相关的活动,例如处理传入的网络数据和基于GUI交互将数据发送到网络。现在,只要有任何传入数据,我想更新一些在网络模块中没有引用的活动。那么什么可能是从其他类更新活动的最佳方式?在我的情况下,其他一些类是我的网络类。总之,我想问一下这种场景中的架构应该是什么?即网络部分应该在单独的线程中运行,从那里它应该更新GUI?

4 个答案:

答案 0 :(得分:2)

根据您需要发送到活动的数据的类型/大小,您可以使用多种选项之一。

  1. 使用其中一种方法here
  2. 使用BroadcastReceiver:在Activity中注册,然后触发处理网络代码的Intent中匹配的Service
  3. Activity绑定到Service,然后传递Handler发送给您的Message

答案 1 :(得分:1)

我写过这样的应用程序,我更喜欢Handler方法。事实上,我已经编写了一个Abstract Activity类来完成所有的艰苦工作,只需将其扩展到任何想要通知变更的活动中。

要使用以下代码,只需让您的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 */
}


}

答案 2 :(得分:0)

是的,我个人认为网络和UI应该在不同的线程中。我倾向于在两者之间进行通信的方式,这可能不是推荐的正确方法,但它对我有用,就是在应用程序类中创建一个全局变量。希望这有点帮助

答案 3 :(得分:0)

我会直接发布到主UI线程,

Handler mHandler = new Handler(Looper.getMainLooper());

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