【问题标题】:Listeners observer design pattern with Handler带有处理程序的侦听器观察者设计模式
【发布时间】:2016-10-21 21:12:46
【问题描述】:

我最近正在处理一个我不知道如何回答的问题。 我为我想要执行的一些 AsyncTask 编写了一个代码示例。我在网上某处读到有人将 AsyncTask 和 Handler 实现为内部类,我想稍微扩展一下并减少耦合,所以我为它们创建了单独的类,这样我就可以在多个 Activity 中重用它们。 因为我必须在每个 Activity 上做一些不同的 UI 操作,所以我决定让这些 Activity 实现一个接口,这样我就可以用相同的方法对每个事件做出反应。

我不明白为什么我需要处理程序对象来处理事件发生的消息传递?我不能只使用听众观察者模式吗?然后我问自己并且无法理解网络上的答案的问题是我的 listener 观察者实现和我们从 Android 获得的处理程序对象之间有什么区别。

这是我的代码示例:

活动 1:

public class SomeActivity extends Activity implements MyListener{

    MyAsyncTask myTask;
    MyHandler handler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        handler = new MyHandler();
        myTask = new MyAsyncTask(handler);
        // initilize the activity views etc...
    }

    @Override
    public void do1(){
        // DO UI THINGS FOR ACTIVITY 1 IN A CALLBACK TO DO1 EVENT
    }

    @Override
    public void do2(){
        // DO UI THINGS FOR ACTIVITY 1 IN A CALLBACK TO DO2 EVENT
    }
}

活动 2:

public class OtherActivity extends Activity implements MyListener{

    MyAsyncTask myTask;
    MyHandler handler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        handler = new MyHandler();
        myTask = new MyAsyncTask(handler);
        // initilize the activity views etc...
    }

    @Override
    public void do1(){
        // DO UI THINGS FOR ACTIVITY 2 IN A CALLBACK TO DO1 EVENT
    }

    @Override
    public void do2(){
        // DO UI THINGS FOR ACTIVITY 2 IN A CALLBACK TO DO2 EVENT
    }
}

监听器接口:

public interface MyListener{
    void do1();
    void do2();
}

AsyncTask 实现:

public class MyAsyncTask extends AsyncTask<Void,Void,String>{
    private MyModel m;

    public MyAsyncTask(Handler h){
        m = new MyModel();
        m.setHandler(h);
    }

    protected String doInBackground(Void... params) {
        // do something in background with MyModel m
        return null;            
    }
}

处理程序实现:

public class MyHandler extends Handler {

    Vector<MyListener> listeners = new Vector<>();

    @Override
    public void handleMessage(Message msg) {
        switch(msg.what){
            case 1:
                // do something for case 1
                fireMethod1();
                break;
            case 2:
                // do something for case 2
                fireMethod2();
                break;
        } 
    }

    public void registerListener(MyListener l){
        listeners.add(l);
    }

    public void unregisterListener(MyListener l){
        listeners.remove(l);
    }

    private void fireMethod1(){
        for(MyListener l : listeners){
            l.do1();
        }
    }

    private void fireMethod2(){
        for(MyListener l : listeners){
            l.do2();
        }
    }

}

我创建的一些演示模型:

public class MyModel{

    private Handel h;

    public MyModel(){
        // at some point send message 1 or message 2 ...
    }

    public void setHandler(Handler h){
        this.h = h;
    }

    private void sendMessage1(){
        h.obtainMessage(1, null);
    }

    private void sendMessage2(){
        h.obtainMessage(2, null);
    }
}

如果看代码太难请告诉我,如果不想看代码请帮我解答Handler和观察者模式监听事件有什么区别?他们对于同一个问题的解决方案有很大不同吗?谢谢!

【问题讨论】:

    标签: java android android-asynctask observer-pattern android-handler


    【解决方案1】:

    Handler 和使用观察者模式监听事件有什么区别?

    不同之处在于,当您使用侦听器时,您会在同一线程上同步调用方法。当您使用Handler 时,您会同步向MessageQueue 添加一条消息,但它仅在那些已经在队列中的消息之后处理。

    例如,如果您正在使用 UI 处理程序,并且您已经在 Activity 上调用了 finish(),然后添加了您的消息,它将被插入到 onStop()onDestroy() 之后。您无法通过侦听器实现此目的。

    处理程序的优点是您只需将消息添加到队列中,而无需关心线程。您可以轻松地从后台线程向 UI 处理程序添加消息。如果你使用后台线程的监听器,它将在后台线程上同步调用。

    对于同一个问题,它们的解决方案是否大相径庭?

    不,他们不是。我认为,处理程序可以帮助您解耦对 Android 至关重要的 android 组件。如果您使用侦听器,您将仅依赖强引用,这在某些情况下是不可能的,因为您可能会泄漏内存。

    【讨论】:

    • 如何使用相同的处理程序扩展类对不同的活动进行任何类型的操作?我使用可观察模式的方式是正确的方式吗?我只是想防止自己创建一个'getHandler'重复方法来实例化一个新的处理程序,在我想要处理来自处理程序的消息的每个活动中?再次感谢
    • 您真的需要跨活动的相同Handler 对象吗?通常在每个活动中创建一个 UI 处理程序是可以的,它并不繁重。如果您想要相同的对象,那么您可以在 Application 类或基础活动中使用静态变量。这是安全的,因为处理程序将与 UI 线程相关联。关于您的下一个问题,我不知道您是否正确执行此操作,因为它始终取决于用例。后台运行多长时间?是否需要更新 UI?如果系统决定终止您的应用,预期的行为是什么?
    • 太好了,我想我明白了。后台操作由用户处理,它是一个音乐播放器(代码示例中的MyModel),用户选择是播放还是停止,播放时我需要接收某些消息。它会随着 onStop 而死亡并被摧毁。每当我收到一条消息时,我都需要使用一些画布绘图来更新 UI。也许在每个活动中创建处理程序并没有那么繁重,我会考虑这种方法。
    • 好的。对于音乐播放器等应用程序,通常使用Service 组件。它允许您独立于 UI 运行操作,并且还增加了应用程序进程的优先级,以便在设备在低内存上运行时有更多的生存机会。考虑这个解决方案,也许它更适合您的用例。谢谢。
    • 哦,好的,我会尝试将它作为服务运行,实际上它是一个节拍器播放器(所以我使用 AudioTrack),所以当我将它作为服务运行时,我仍然可以使用处理程序作为服务和 UI 之间的消息传递平台并利用消息队列?因为它是一个节拍器,所以我真的需要注意同步性,而且我从处理程序中得到的队列是一件很棒的事情。
    【解决方案2】:

    Handler 是 UI 线程组件。如果你想触摸一些 UI,使用简单的监听器可能会导致CalledFromWrongThreadException

    AsyncTask 虽然有onPreExecuteonPostExecuteonProgressUpdate,它们只是方法,它们在UI 线程上运行。 doInBackground 在单独的线程上运行

    【讨论】:

    猜你喜欢
    • 2011-03-22
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 2011-09-25
    • 2013-12-02
    • 2011-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多