在执行之前取消runnable / handler

时间:2017-11-07 00:47:16

标签: java android multithreading handler runnable

我有一个textView,我已经设置了onClickListener。当用户将手指按住7秒然后抬起时,会弹出一个Dialog,在单击正按钮时触发意图,如果单击否定按钮则取消操作。当用户按住textView足够长的时间我想要一个视觉提示,所以我创建了一个处理程序和一个在7000ms后触发的runnable并稍微改变了根视图的背景颜色。它起初效果很好。如果用户按住7秒钟,背景会发生变化,您可以抬起手指以显示对话框。如果取消,一切都会恢复正常,包括背景颜色。问题是,如果用户在7秒之前抬起手指,我就不知道如何在MotionEvent.ACTION_UP上取消处理程序。这是我的代码:

View.OnTouchListener listener = new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                final Handler handler = new Handler();
                final Runnable runnable = new Runnable(){
                    @Override
                    public void run(){
                        Toast.makeText(mContext, "This is working", Toast.LENGTH_SHORT).show();
                        mMainContainer.setBackgroundColor(getResources().getColor(R.color.alert_color));
                    }
                };

                View rootView = LayoutInflater.from(mContext).inflate(R.layout.admin_dialog, null);

                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    // get the first touch in the series
                        start = System.currentTimeMillis();


                    handler.postDelayed(runnable, 7000);

                }
                if (event.getAction() == MotionEvent.ACTION_UP) {

                    handler.removeCallbacks(runnable);

                    stop += System.currentTimeMillis();

                    if ((stop - start) > 7000){

                        // reset values
                        start = 0;
                        stop = 0;

                        final EditText password = (EditText)rootView.findViewById(R.id.admin_password_et);

                        AlertDialog.Builder dialog = new AlertDialog.Builder(mContext)
                                .setView(rootView)
                                .setTitle("Edit Configuration?")
                                .setPositiveButton(R.string.yes_button, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        int counter = 1;
                                        if(password.getText().toString().equalsIgnoreCase("mq")){
                                            Intent intent = new Intent(mContext, MainActivity.class);
                                            startActivity(intent);
                                        } else {
                                            mMainContainer.setBackgroundColor(getResources().getColor(android.R.color.background_light));
                                            Toast.makeText(mContext, "Wrong password, Access denied", Toast.LENGTH_SHORT)
                                            .show();
                                            dialog.dismiss();
                                        }
                                    }
                                })
                                .setNegativeButton(R.string.no_button, new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        mMainContainer.setBackgroundColor(getResources().getColor(android.R.color.background_light));
                                        dialog.dismiss();
                                    }
                                });
                        dialog.create();
                        dialog.show();
                    } else {

                        // reset values
                        start = 0;
                        stop = 0;
                    }
                }

                return true;
            }
        };
        mAppTitle.setOnTouchListener(listener);

我以为调用了handler.removeCallbacks(runnable);是答案,但它没有成功。就像现在一样,如果你按下textView并在7秒前拉开手指,对话框就不会弹出,但是7秒后背景颜色仍会改变。我该如何取消该操作?我需要以不同的方式实现这一点吗?

3 个答案:

答案 0 :(得分:0)

你可以尝试而不是使用7000作为你的重复,你可以做一个小得多的间隔,而是做一个时间差异,所以在你的处理程序中,你检查该差异是否超过7000毫秒。满足条件后,即可执行操作。希望我能理解你的问题。

   Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    if (diff >7000) {
                        handler.removeCallbacks(runnable);
                    } else {
                        handler.postDelayed(runnable, 500);
                    }
                }
            };

答案 1 :(得分:0)

我明白了!谢谢大家的帮助,但我想出了我认为最好的解决方案。我在OnTouchListener之外创建了一个CountDownTimer对象。在MotionEven.ACTION_UP上我取消了计时器。这是代码,如果它可以帮助其他人:

<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <threadsafe>true</threadsafe>
    <runtime>java8</runtime>

    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
        <property name="file.encoding" value="UTF-8" />
        <property name="DEFAULT_ENCODING" value="UTF-8" />
    </system-properties>
    <sessions-enabled>true</sessions-enabled>

</appengine-web-app>

答案 2 :(得分:0)

你的实际问题是你在每个onTouch上创建了一个Runnable的新实例,所以removeCallback与你之前发布的那个不匹配,解决方法是:

从方法范围声明Runnable并仅在down时启动它。

此外,我将ACTION_CANCEL添加为UP会导致此行为发生。

        View.OnTouchListener listener = new View.OnTouchListener() {
        Runnable runnable;
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            final Handler handler = new Handler();

            View rootView = LayoutInflater.from(mContext).inflate(R.layout.admin_dialog, null);

            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                // get the first touch in the series
                    start = System.currentTimeMillis();


             runnable = new Runnable(){
                @Override
                public void run(){
                    Toast.makeText(mContext, "This is working", Toast.LENGTH_SHORT).show();
                    mMainContainer.setBackgroundColor(getResources().getColor(R.color.alert_color));
                }
            };
                handler.postDelayed(runnable, 7000);

            }
            if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {

                handler.removeCallbacks(runnable);

                stop += System.currentTimeMillis();

                if ((stop - start) > 7000){

                    // reset values
                    start = 0;
                    stop = 0;

                    final EditText password = (EditText)rootView.findViewById(R.id.admin_password_et);

                    AlertDialog.Builder dialog = new AlertDialog.Builder(mContext)
                            .setView(rootView)
                            .setTitle("Edit Configuration?")
                            .setPositiveButton(R.string.yes_button, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    int counter = 1;
                                    if(password.getText().toString().equalsIgnoreCase("mq")){
                                        Intent intent = new Intent(mContext, MainActivity.class);
                                        startActivity(intent);
                                    } else {
                                        mMainContainer.setBackgroundColor(getResources().getColor(android.R.color.background_light));
                                        Toast.makeText(mContext, "Wrong password, Access denied", Toast.LENGTH_SHORT)
                                        .show();
                                        dialog.dismiss();
                                    }
                                }
                            })
                            .setNegativeButton(R.string.no_button, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    mMainContainer.setBackgroundColor(getResources().getColor(android.R.color.background_light));
                                    dialog.dismiss();
                                }
                            });
                    dialog.create();
                    dialog.show();
                } else {

                    // reset values
                    start = 0;
                    stop = 0;
                }
            }

            return true;
        }
    };
    mAppTitle.setOnTouchListener(listener);