Android Handler的使用

发布于 2024-10-20 22:31:18 字数 209 浏览 1 评论 0 原文

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

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

使用内联代码版本

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

Which is the better way to use a handler. Any advantages. All examples I have come across seem to give the inline version.

Using implements Handler.Callback in the class and implementing interface method.

or

Using inline code version

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

神妖 2024-10-27 22:31:18

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

您可以在Java/Android:匿名本地类与命名类中阅读有关这些内容的更多讨论

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

从资源的角度来看,匿名类创建可能会导致垃圾收集器产生开销,如 避免创建不必要的对象。我不确定匿名类创建的确切细节,但是,在类上实现接口更有效是合乎逻辑的。

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

The common term or these inline class definitions is Anonymous Classes.

You can read more about the discussion on these in Java/Android: anonymous local classes vs named classes

Essentially the main differences are readbility, speed of coding, re-use and scope.

From a resource point of view the anonymous class creation may cause an overhead in the garbage collector as discussed in Avoid Creating Unnecessary Objects. I am not certain on the exact details of anonymous class creation, however, it is logical that implementing the interface on the class is more efficient.

@WilliamTMallard has provided an example of what NOT to do. In his example, a long and syntacticly complex handler should be implementented on the class rather than anonymous handler because it is harder to read and edit when defined inline.

一刻暧昧 2024-10-27 22:31:18

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

package : android.os
public class
Handler
extends Object

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

处理程序有两个主要用途:

  1. 安排消息和可运行对象在某个点执行
    将来;并将
  2. 要在不同线程上执行的操作排入队列
    你自己的。

示例 1

在应用启动页面中使用处理程序。

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

使用Handler和Timer来更新进度条。

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);
    }
}; 

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

package : android.os
public class
Handler
extends Object

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

There are two main uses for a Handler:

  1. to schedule messages and runnables to be executed as some point
    in the future; and
  2. to enqueue an action to be performed on a different thread than
    your own.

Exmaple 1

use handler in app splash page.

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();
} 

Example 2

use Handler request network in child thread if the request work may time consuming.

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);
        }
    }
    
}; 

Example 3

use Handler and Timer to update progress bar.

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);
    }
}; 
云柯 2024-10-27 22:31:18

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

我正在编写一个用作遥控器的应用程序。有多种活动将与受控设备交互,并且根据命令的结果及其来自的活动需要发生不同的事情。我不喜欢处理程序的两件事是: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;  
                }
            }
        }
    });

永远记住,这可能完全值得您为此付出的代价。;))

This really isn't an answer to the above question because I don't know what "the best way" is, and it likely depends on what you're doing. However, I'll explain what I'm doing and why.

I'm writing an app that serves as a remote controller. There are several activities that will interact with the controlled device, and different things need to happen based on the result of the command and the activity it came from. Two things I didn't like about handlers are A) that they end up being a sort of "kitchen sink" construct, implementing functionality from different sources, and B) that they separated an action (the send of the command in my case) from the processing of the result of that action. However, using an anonymous (right term? I'm such a noob.) handler as a parameter allows me to keep the logic together. Here's the pseudocode for my approach:

    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;  
                }
            }
        }
    });

(Always remember, this is probably worth exactly what you've paid for it. ;) )

意中人 2024-10-27 22:31:18

在 Android 中使用匿名类存在危险。如 这篇博文中所述< /a> -

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

泄密的机会来了。

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

例如,泄漏安全处理程序可能如下所示:

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
            }
        }
    }
}

我制作了一个 关于处理程序的使用的博客文章,所以可能也值得检查:)

There is a danger in using anonymous classes in Android. As described in this blog post -

In Java, non-static inner and anonymous classes hold an implicit
reference to their outer class.

And here comes an opportunity for a leak.

So, the short answer would be: implement the interface methods or use static inner classes (which don't hold an outer class reference).

For instance, a leak-safe Handler could look like this:

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
            }
        }
    }
}

I made a blog post around usage of Handlers, so might be worth checking as well :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文