我正在实现一种VOIP应用程序。所以我的应用程序是一种网络应用程序。现在我想在我的应用程序中实现两个部分,一个是GUI部分,一个是网络部分。我的GUI部分将包含用户交互的活动和处理。我的网络部分应该处理所有与网络相关的活动,例如处理传入的网络数据和基于GUI交互将数据发送到网络。现在,只要有任何传入数据,我想更新一些在网络模块中没有引用的活动。那么什么可能是从其他类更新活动的最佳方式?在我的情况下,其他一些类是我的网络类。总之,我想问一下这种场景中的架构应该是什么?即网络部分应该在单独的线程中运行,从那里它应该更新GUI?
答案 0 :(得分:2)
根据您需要发送到活动的数据的类型/大小,您可以使用多种选项之一。
BroadcastReceiver
:在Activity
中注册,然后触发处理网络代码的Intent
中匹配的Service
。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(){...});