使用Handler Android

时间:2011-03-08 07:08:51

标签: android handler

使用处理程序的更好方法是什么。任何优点。我遇到的所有示例似乎都给出了内联版本。

在类中使用implements Handler.Callback并实现接口方法。

使用内联代码版本

private Handler mHandler = new Handler(){ ....};

4 个答案:

答案 0 :(得分:5)

常用术语或这些内联类定义是匿名类。

您可以在Java/Android: anonymous local classes vs named classes

中详细了解有关这些问题的讨论

本质上,主要区别在于可读性,编码速度,重复使用和范围。

从资源的角度来看,匿名类创建可能会导致垃圾收集器的开销,如Avoid Creating Unnecessary Objects中所述。我不确定匿名类创建的确切细节,但是,在类上实现接口更有效是合乎逻辑的。

@WilliamTMallard提供了一个 NOT 的例子。在他的例子中,应该在类而不是匿名处理程序上实现一个冗长且语法复杂的处理程序,因为在内联定义时更难阅读和编辑。

答案 1 :(得分:2)

http://developer.android.com/reference/android/os/Handler.html

package : android.os
public class
Handler
extends Object

Handler允许您发送和处理与线程的MessageQueue关联的Message和Runnable对象。每个Handler实例都与一个线程和该线程的消息队列相关联。当您创建一个新的Handler时,它被绑定到正在创建它的线程的线程/消息队列 - 从那时起,它将消息和runnables传递给该消息队列并在消息出来时执行它们队列中。

Handler有两个主要用途:

  1. 安排消息和runnables作为某个点执行 在将来;和
  2. 将要在不同的线程上执行的操作排入队列 你自己的。
  3. Exmaple 1

    在app splash页面中使用handler。

    if (!isFirstIn) {
        mHandler.sendEmptyMessageDelayed(GO_HOME, SPLASH_DELAY_MILLIS);
    } else {
        mHandler.sendEmptyMessageDelayed(GO_GUIDE, SPLASH_DELAY_MILLIS);
    } 
    
    
    /**************************************************************************************
    *1. Handler
    */
    private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            if(isAuto){
                switch (msg.what) {
                case GO_HOME:
                    goHome();
                    break;
                case GO_GUIDE:
                    goGuide();
                    break;
                }
            }
            super.handleMessage(msg);
        }
    }; 
    private void goHome() {
        Intent intent = new Intent(SplashActivity.this, MainAct.class);
        SplashActivity.this.startActivity(intent);
        SplashActivity.this.finish();
    } 
    
    private void goGuide() {
        Intent intent = new Intent(SplashActivity.this, GuideActivity.class);
        SplashActivity.this.startActivity(intent);
        SplashActivity.this.finish();
    } 
    

    示例2

    如果请求工作可能需要时间,则在子线程中使用Handler请求网络。

    new Thread(new Runnable(){
        @Override
        public void run() {
            String versionPath = Parameters.getCheckVersionPath();
            String result = RequestHelper.doGet(versionPath, null);
            Message msg = new Message();
            Bundle data = new Bundle();
            data.putString("result",result);
            msg.setData(data);
            handler1.sendMessage(msg);
        }
    }).start();
    
    handler1 = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            String result = msg.getData().getString("result");
            JSONObject obj;
            try {
                obj = new JSONObject(result);
                Map<String, String> versionInfo = Helper.getSoftwareVersion(obj);
                if (versionInfo != null) {
                    newVersion = versionInfo.get("version");
                    updateUrl = versionInfo.get("url");
                }
            } catch (JSONException e) {
                Log.w("net work error!", e);
            }
        }
    
    }; 
    

    示例3

    使用处理程序和计时器更新进度条。

    logobar = (ImageView) findViewById(R.id.splash_bar);//progress bar.
    logobarClipe = (ClipDrawable) logobar.getBackground();
    
    timer = new Timer();
    timer.schedule(new TimerTask() {
        public void run() {
            updateLogoBarHandler.sendEmptyMessage(0);
    }}, 0, rate);
    
    
    /**************************************************************************************
    *2. Handler
    */
    //update progress bar.
    private Handler updateLogoBarHandler = new Handler() {
        public void handleMessage(Message msg) {
            if(logobarClipe.getLevel() < 10000){
                //1.update image.
                logobarClipe.setLevel(logobarClipe.getLevel() + rate*2);  
    
                //2.update text.
                float percent = logobarClipe.getLevel() /100;
                String percentTxtVerbose = String.valueOf(percent);
                String percentTxt = percentTxtVerbose.substring(0, percentTxtVerbose.indexOf('.')) + "%";
                bartxt.setText(percentTxt);
    
            }else{
                timer.cancel();
            }  
            super.handleMessage(msg);
        }
    }; 
    

答案 2 :(得分:0)

这真的不是上述问题的答案,因为我不知道“最好的方式”是什么,而且可能取决于你在做什么。但是,我会解释我在做什么以及为什么。

我正在编写一个充当遥控器的应用程序。有几个活动将与受控设备进行交互,并且需要根据命令的结果及其来自的活动来执行不同的操作。我不喜欢处理程序的两件事是A)它们最终成为一种“厨房接收器”构造,实现来自不同来源的功能,以及B)它们分离了一个动作(在我的情况下发送命令)从处理该行动的结果。但是,使用匿名(正确的术语?我就是这样的菜鸟。)处理程序作为参数允许我将逻辑保持在一起。这是我的方法的伪代码:

    command = "Wake up!";

    mDeviceInterface.write(command, new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
            case DeviceInterface.MESSAGE_TIMEOUT: // Process the timeout.
                announce("Device not responding.");
                break;
            case DeviceInterface.MESSAGE_READ: // Process the response.
                byte[] readBuf = (byte[]) msg.obj;
                if (readBuf[0] == 0x05) {
                    // Success, update device status.
                } else {  
                    announce("Error!");
                    break;  
                }
            }
        }
    });

(永远记住,这可能与你为此付出的确实相同。;))

答案 3 :(得分:0)

在Android中使用匿名类是有危险的。如this blog post -

中所述
  

在Java中,非静态内部和匿名类具有隐式   引用他们的外类。

这是一个泄密的机会。

因此,简短的回答是:实现接口方法或使用静态内部类(不包含外部类引用)。

例如,防漏的Handler可能如下所示:

private static class ChangeTextHandler extends Handler {
    private final WeakReference activity;

    public ChangeTextHandler(MainActivity activity) {
        this.activity = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        MainActivity activity = this.activity.get();
        if (activity == null) {
            Log.e(TAG, "Activity is null ChangeTextHandler.handleMessage()!");
            return;
        }

        final String text = (String) msg.getData().get(BUNDLE_KEY);
        if (!TextUtils.isEmpty(text)) {
            switch (msg.what) {
                // do something
            }
        }
    }
}

我制作了blog post around usage of Handlers,所以也值得一试:)