处理活动

时间:2015-11-10 21:31:16

标签: android android-activity callback singleton retrofit

我正在通过改造在android中实现一个客户端。 当我使用异步请求时,客户端在一个单独的线程中处理每个请求,然后,我在回调中得到答案。

它看起来像这样:

public void request(){


    ThisService client = ServiceGenerator.createService(ThisService.class,baseUrl);

    client.request(new Callback<Answer>() {
        @Override
        public void success(LoginAnswer answer, Response response) {

        }

        @Override
        public void failure(RetrofitError error) {

        }
    });

}

我需要做的是,在回调之后,更改一些UI设置,所以我做的是在我的活动中实现静态方法:

public static void changeUI(){}

所以在回调中我可以做类似的事情:

public void request(){


    ThisService client = ServiceGenerator.createService(ThisService.class,baseUrl);

    client.request(new Callback<Answer>() {
        @Override
        public void success(LoginAnswer answer, Response response) {
            Activity.changeUI();
        }

        @Override
        public void failure(RetrofitError error) {

        }
    });

}

问题在于,这样做的方法是让我为Activity定义很多静态变量和方法(从静态方法我只能调用其他静态方法或访问静态变量)。 因此,例如,如果从changeUI(),我想调用另一个Activity方法,它必须是静态的,依此类推。

如果我想完成活动,我不能调用finish()因为这不是静态的。

我想我想问的是:最好的方法是避免这种情况吗?

我在网上看到的每个例子,都是在sucess方法中实现了所有内容,但对我来说似乎并不“干净”。

我在想类似单例模​​式的东西,我可以调用getInstance(),这是一个返回活动副本的静态方法,然后为UI更改定义非静态方法。

2 个答案:

答案 0 :(得分:4)

我喜欢通过在我的网络类中定义自定义回调接口来处理这些情况,然后将消息直接发送给需要它的人。例如,假设您有一个名为YourCallbackClass的类来执行某些网络操作。我们将这样定义:

public class YourCallbackClass {

    YourNetworkCallbacks callback;

    public YourCallbackClass(YourNetworkCallbacks callback) {
        this.callback = callback;
    }

    public void networkMethod() {
        String message = "This came from YourCallbackClass";
        callback.networkCallback(message);
    }

    public interface YourNetworkCallbacks {
        public void networkCallback(String message);
    }
}

在这个类中,我们定义了一个名为YourNetworkCallbacks的公共接口,它有一个方法。此方法将用于将网络操作的结果发送回调用类。我们的网络方法只是一个定义为networkMethod()的虚拟方法。它只是生成一个我们发送给我们的调用类的String。

因此,要将此String转换为另一个类,我们必须让我们的调用类实现公共接口YourNetworkCallbacks。因此,我们想要网络操作结果的Activity的顶部看起来像这样:

public class MainActivity extends AppCompatActivity implements YourCallbackClass.YourNetworkCallbacks {
    ...
    ...

现在我们所要做的就是实现我们在YourNetworkCallbacks中定义的回调方法。所以在MainActivity中,我们简单地说:

public void networkCallback(String message) {
    Log.d("NETWORK CALLBACK", "A message from YourCallbackClass: "+message);
}

现在我们的回调实现已准备好接收消息。现在,我们所要做的就是告诉YourCallbackClass谁正在收听我们的回调,因此它知道在哪里路由消息。我们通过传入一个侦听器实例来做到这一点,该侦听器只是实现回调的任何类。在这种情况下,我们的MainActivity按定义实现回调,因此我们可以在创建YourCallbackClass实例时发送this。所以我们会这样做:

YourCallbackClass callbackClass = new YourCallbackClass(this);

您将在YourCallbackClass中看到,我们接受传入的侦听器(它只是我们Activity的一个实例,它实现了回调)并且我们将引用分配给我们自己的本地回调变量。这样做是允许我们现在将消息发送到回调引用,这实际上是对MainActivity中回调的引用。这有效地让我们直接与MainActivity进行通信!

现在要将消息发送回MainActivity,我们只需:

public void networkMethod() {
    String message = "This came from YourCallbackClass";
    callback.networkCallback(message);
}

您为自己的项目实现此方法的方法是,您可以使用来自网络操作的回调来调用您自己的自定义回调,这些回调在您想要获取信息的任何活动/类中实现。

一开始这一切都非常令人困惑,但是一旦掌握了这一点,你就会很快意识到在处理异步操作时有什么强大的工具回调!

希望这能回答你的问题!

编辑回应评论: 好的,让我们来谈谈如何在自己的项目中实现这个解决方案。你显然有一些正在进行网络操作的课程,你提到你正在回调网络结果,对吗?

因此,您的网络操作类是您的版本&#34; YourCallbackClass。&#34;因此,在您的网络操作类中,定义公共接口并添加一个名为&#34; sendNetworkResults()&#34;的方法。或者你想要的任何接口定义。同样在您的网络操作类中,您需要创建一个私有成员,该成员是您的接口实例。因此,在您的网络操作类中,您应该定义接口,并且私有成员是您的回调接口的实例(在上面的示例中,您将其视为&#34; YourNetworkCallbacks回调;&#34;)。

现在,在需要网络结果的Activity中,让Activity类实现您在网络操作类中定义的接口。所以你需要添加&#34; implements&#34;到类定义,您需要实际实现在接口中定义的sendNetworkResults()方法。

现在,您的Activity已全部设置为接收回调,并且您的网络操作类已全部设置为发送回调。剩下要做的唯一事情是将两者连接起来以完成桥梁。因此,我们通过将您的Activity实例分配给您在网络操作类中创建的回调成员来完成此操作。在上面的示例中,这是YourNetworkCallbacks callback;成员。您可以通过将Activity传递给网络操作构造函数(我在示例中的方式)来执行此操作。或者您可以在网络操作类中创建一个setter方法,如setNetworkClassListener(YourNetworkCallbacks callback);

完成此分配后,您只需将消息发送给此回调成员,它会自动将结果发送到您在Activity中实现的方法。那你怎么做的?

您提到您正在收到网络搜索结果的回调。因此,当回调进入时,您只需通过在我们分配的回调成员上调用您在界面中定义的方法,将相关信息传递给您的Activity。所以它会是这样的:

//This is the callback that gets called when your network results come in
public void yourNetworkOperationCallback(String someValue) {

    /** 
    * Now we take the String result that returned from the network callback
    *and we pass it on to the Activity by sending it into our interface method
    *using the callback reference we assigned. Here, "callback" is a member 
    * we defined for this class, and we assigned it the value of our Activity 
    * instance. 
    **/
    callback.sendNetworkResults(someValue);
}

请记住,我们已将成员callback分配给Activity的值,该值实现了我们的界面。所以我们基本上说Activity是我们回调的一个实例,我们只是将引用复制到我们的本地回调变量。所以现在当我们调用sendNetworkResults()方法时,它会转到我们引用的实现,这是我们的Activity。

所以你的网络回调应该是这样的:

public void request(){


    ThisService client = ServiceGenerator.createService(ThisService.class,baseUrl);

    client.request(new Callback<Answer>() {
        @Override
        public void success(LoginAnswer answer, Response response) {
            //We're passing these values directly to Activity
            callback.sendNetworkResult(answer, response);
        }

        @Override
        public void failure(RetrofitError error) {

        }
    });

}

然后在您的Activity中,您实现了sendNetworkResults()方法,所以它看起来像这样:

public void sendNetworkResults(LoginAnswer answer, Response response) {
    //This is implemented in your Activity. So now just update your Activity UI
    //with the answer and response values!
}

现在,您的活动中包含answerresponse值!只剩下要做的就是使用它们来更新你的用户界面。

希望这一切都有意义。我知道它非常令人困惑:)

答案 1 :(得分:0)

您可以使用LocalBroadcastManager

在你的ui元素中声明一个接收器

private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
            // do whatever you ui needs to update
        }
    }
};

通过

收听你的ui元素的任何广播
@Override
protected void onStart() {
    super.onStart();
    final IntentFilter filter = new IntentFilter("nameOfYourFilterAction");
    LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, filter);
}

@Override
protected void onStop() {
    LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
    super.onStop();
}

从你的任务中你只需发送一个新的Intent对象

final Intent broadcast = new Intent("nameOfYourFilterAction");
broadcast.put(<any extras>);
LocalBroadcastManager.getInstance(<some context>).sendBroadcast(broadcast);