Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/230.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android:根据服务中后台线程的对象值更新UI_Java_Android_Multithreading - Fatal编程技术网

Java Android:根据服务中后台线程的对象值更新UI

Java Android:根据服务中后台线程的对象值更新UI,java,android,multithreading,Java,Android,Multithreading,我目前正在开发一款Android应用程序,其中包含以下活动: 主要活动 更新活动 此外,它还包含一个完全独立的包,其中存在以下类: SyncService:正如名称所示,它是一种服务。更具体地说是绑定服务 SyncServiceManager:绑定到服务的单例对象 SyncTask:仅包含服务需要执行的逻辑。因此,服务是与之交互的唯一对象 两个接口使我的经理能够与服务交互。和2个界面,仅用于我的应用程序的观察者模式。服务是应该通知经理、syncTask和updateActivity执行某些

我目前正在开发一款Android应用程序,其中包含以下活动:

  • 主要活动
  • 更新活动
此外,它还包含一个完全独立的包,其中存在以下类:

  • SyncService:正如名称所示,它是一种服务。更具体地说是绑定服务
  • SyncServiceManager:绑定到服务的单例对象
  • SyncTask:仅包含服务需要执行的逻辑。因此,服务是与之交互的唯一对象
  • 两个接口使我的经理能够与服务交互。和2个界面,仅用于我的应用程序的观察者模式。服务是应该通知经理、syncTask和updateActivity执行某些操作的主体
我面临的问题是,我想根据服务需要执行其工作时更改的枚举来修改updateActivity的UI。通知syncTask执行请求的作业(配置、重置或将应用程序数据库与Web服务的数据同步)

然而,因为我想让服务在后台完成他的工作,所以我使用了一个新的线程对象,它可以在其中完成我希望它完成的事情。 这是所有类型的工作方式,除了我可以在更新活动中修改UI,因为UI只能从UI线程进行编辑。 我已经在论坛上找到了一个非常有前途的链接,但我只是不知道它是否真的是我需要的东西和/或如何实现它。

这是我的密码。 服务:

public enum ServiceState {
    RESETTING,
    CONFIGURING,
    SYNCHRONIZING,
    IDLE
}

private Vector<IObserver> observers = new Vector<IObserver>();
private IBinder syncBinder = new SyncServiceBinder();
private ServiceState serviceState;

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return syncServiceBinder;
}

private final IBinder syncServiceBinder = new SyncServiceBinder();

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Thread th = new Thread(new Runnable() {
        @Override
        public void run() {
            //Modifying the service state and starting the sync depending on the state.
            startSync();
        }
    });

    th.start();

    return START_REDELIVER_INTENT;
}

private void startSync() {
    notifyObservers(serviceState);
}

@Override
public void registerObserver(IObserver iObserver) {
    observers.add(iObserver);
}

@Override
public void unregisterObserver(IObserver iObserver) {
    observers.remove(iObserver);
}

@Override
public void notifyObservers(SyncService.ServiceState serviceState) {
    for (IObserver observer : observers) {
        observer.update();
    }
}
}

我还考虑过使用activity类附带的runOnUiThread函数,但它启动得太晚了。在updateactivity中创建一个新的处理程序,并创建一个runnable,这应该允许我向处理程序发送消息

你们有什么想法/建议吗

提前感谢,


迈克尔

在这种情况下,广播听众将是最好的,也被推荐。只需在activity中创建广播侦听器,它将更新UI,在onStart中注册,并在onStop中注销。

我认为您的逻辑太复杂了。没有必要把这一切搞得一团糟。 你只需要主要的活动类和服务,你就可以得到更多。您甚至不需要绑定服务

由于活动和服务在同一个进程中运行,因此在它们之间共享状态的一个好方法是静态变量。因此,将服务状态设为静态,并设置一个getter,以便活动可以访问服务的状态

当需要更新UI时,您可以向活动发送广播,在onStart中注册,在onStop中注册(根据需要,onPause和onResume也可以工作)

尽管我认为比广播更简单的方法是使用事件总线,比如otto。 只需创建一个提供总线的单例类,进入服务并将事件发布到总线上(参见如何从后台发布到主线程的示例,这非常简单)。在活动中,按照我前面所说的方法注册和注销,并设置@susbuide事件

一些代码示例:

从服务发布更新:

EventBusProvider.getInstance().postToMainThread(new SomeEventOrAnyClassObject());
注册和注销活动以侦听总线:

  @Override
public void onStart(){
    super.onStart();
    EventBusProvider.getInstance().register(this);

 @Override
public void onStop(){
    super.onStop();
    EventBusProvider.getInstance().unregister(this);
}
订阅以接收更新

 @Subscribe
public void loginResponse(Data someinstance){
 //Here you could read the update directly from the someinstance
//or check the service static variable
 SyncService.getStatus()
}

这真的很容易。希望它有助于创建BroadCastReceiver,并通过服务Broadcast intent在您的活动中注册它。根据
onReceive
中的数据,将您的活动更新为旁注:如果您在
onStart
中注册,您希望在
onStop
中注销。如果您在
onResume
中注销,请在
onPause
中注册,否则您可能会遇到一些奇怪的生命周期问题(尤其是
片段
s)。@AlexTownsend您预计会发生什么样的奇怪生命周期问题?我只是没有看到任何与此相关的内容。@InvertedNetwork我们在生产中看到了一些问题,在这些问题中,围绕片段的配置更改会导致本应取消注册的接收器试图触发。不是很常见,但最好是安全的,只需在正确镜像的生命周期回调中注册/注销即可:)好吧,我想说这取决于您希望何时注销侦听器。但不依赖OnStop更安全,因为有时系统不会调用它。因此,最后一个操作是OnStart&OnPause或OnResume&OnPause。如果您正确理解了何时调用这些方法,那么这不应该是一个问题。它部分地解决了这个问题。我现在面临的唯一问题是,我需要确保BroadcastListener立即接收到广播的意图。因为现在有3秒左右的延迟。这会导致在侦听器响应广播时更新活动已经关闭的情况。
 @Subscribe
public void loginResponse(Data someinstance){
 //Here you could read the update directly from the someinstance
//or check the service static variable
 SyncService.getStatus()
}