欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Handler實現(xiàn)倒計時功能

 更新時間:2021年04月22日 16:46:17   作者:木子@喵  
這篇文章主要為大家詳細介紹了Handler實現(xiàn)倒計時功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了Handler實現(xiàn)倒計時功能的具體代碼,供大家參考,具體內(nèi)容如下

1、需求

1.1 實現(xiàn)目標

當后臺傳遞一個時間戳時,與當前系統(tǒng)時間做時間差,并轉(zhuǎn)換為時分秒,作為商品活動的倒計時;

如下圖所示:

1.2 實現(xiàn)步驟

自定義View

1、實現(xiàn)倒計時功能,封裝成方法;
2、初始化倒計時功能,及布局文件;
3、通過Handler中的post()或sendMessage()方法向主線程傳遞消息,不對刷新UI;
4、對外暴露一個方法,接收后臺傳入的時間戳;

在Activity中實現(xiàn)
通過自定義View中的方法,接收時間戳;

2、封裝成自定義view

2.1 倒計時功能

方法名 processCountMsg()

private boolean processCountMsg() {
        if (hou == 0 && min == 0 && sec == 0) {
            Toast.makeText(getContext(), "時間到", Toast.LENGTH_SHORT).show();
            return false;
        }
        if (sec > 0) {
            sec--;
        } else {
            sec = 59;
            if (min == 0) {
                min = 59;
                hou--;
            } else {
                min--;
            }
        }
        String hour, minute, second;
        hour = (hou < 10) ? "0" + hou : "" + hou;
        minute = (min < 10) ? "0" + min : "" + min;
        second = (sec < 10) ? "0" + sec : "" + sec;

        tv_hour.setText(hour);
        tv_min.setText(minute);
        tv_sec.setText(second);
        return true;
    }

2.2 初始化倒計時功能及布局文件

初始化代碼 init()

private void init() {
        //TODO  LayoutInflater中inflate三個參數(shù)代表含義
     LayoutInflater.from(getContext()).inflate(R.layout.layout_countdown_time, this, true);
        tv_hour = findViewById(R.id.btn_countdown_hour);
        tv_min = findViewById(R.id.countdown_min);
        tv_sec = findViewById(R.id.countdown_sec);
        runnable = new Runnable() {
            @Override
            public void run() {
                boolean needProcess = processCountMsg();
                if(!needProcess)return;
                //沒隔一秒再次執(zhí)行一次run方法,實現(xiàn)倒計時功能
                mHandler.postDelayed(this, 1000);
            }
        };
    }

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="horizontal"
    android:layout_margin="10dp">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="距結(jié)束:"
        android:textColor="#DAA520"
        android:textSize="20dp"/>
    <TextView
        android:id="@+id/btn_countdown_hour"
        android:layout_width="31dp"
        android:layout_height="30dp"
        android:layout_marginRight="2dp"
        android:background="@drawable/countdown_shape"
        android:gravity="center"
        android:textColor="@color/white" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=":"/>
    <TextView
        android:id="@+id/countdown_min"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginRight="2dp"
        android:background="@drawable/countdown_shape"
        android:textColor="@color/white"
        android:gravity="center"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=":"/>
    <TextView
        android:id="@+id/countdown_sec"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="@drawable/countdown_shape"
        android:textColor="@color/white"
        android:gravity="center"/>
</LinearLayout>

2.3 提供對外方法,處理時間戳

使用post() 發(fā)送消息

public void setData(long curDate) {
        //TODO
        String time;
        //計算時間戳與系統(tǒng)時間的時間差,單位為秒
        int timeDifference = (int) (curDate - System.currentTimeMillis());
        //將總秒數(shù)轉(zhuǎn)化為時分秒
        if (timeDifference < 60) {
            time = String.format("00:00:%02d", timeDifference % 60);
        } else if (timeDifference < 3600) {
            time = String.format("00:%02d:%02d", timeDifference / 60, timeDifference % 60);
        } else {
            time = String.format("%02d:%02d:%02d", timeDifference / 3600, timeDifference % 3600 / 60, timeDifference % 60);
        }
        //通過“:”分離時、分、秒
        String[] sArray = time.split(":");
        hou = Integer.parseInt(sArray[0]);
        min = Integer.parseInt(sArray[1]);
        sec = Integer.parseInt(sArray[2]);
        //通過Handler中的post()方法傳遞message
        mHandler.post(runnable);
    }

使用sendMessage發(fā)送消息

private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case COUNT_MSG:
                    boolean needProcess = processCountMsg();
                    if(!needProcess)return;
                    Message message = Message.obtain();
                    message.what = COUNT_MSG;
                    mHandler.sendMessageDelayed(message, 1000);
                    break;
            }
        }
    };
   public void setData(long curDate) {
      ...............
        Message msg = Message.obtain();
        msg.what = COUNT_MSG;
        mHandler.sendMessage(msg);
    }

3、在Activity中實現(xiàn)

public class MainHandlerActivity extends AppCompatActivity {
    private CountDown mTime;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_handler);
        mTime = findViewById(R.id.view_countdown);
        mTime.setData(System.currentTimeMillis() + 10);
    }
}

4、遇到的問題總結(jié)

4.1 LayoutInflate

inflate(int resource,ViewGroup root,boolean attachToRoot)

resource:加載的布局id; root:在該布局的外部再嵌套一層父布局,但不是把當前布局放入到界面已有的布局中,比如xml界面,這個方法只是單穿的返回一個view對象。默認attachToRoot是true。
1、如果root為null,attachToRoot將失去作用,設(shè)置任何職都沒有意義;
2、如果root不為null,attachToRoot設(shè)為true,則會給加載布局文件指定一個父布局,即root;
3、如果root不為null,attachToRoot設(shè)為false,則會將布局文件最外層的所有l(wèi)ayout屬性進行設(shè)置,當該view被添加到父view當中時,這些layout屬性則自動生效。
4、在不設(shè)置attachToRoot參數(shù)的情況下,如果root不為null,attachToRoot參數(shù)默認為true。

4.2 Handler中post()與sendMessage()區(qū)別

post(Runnable r)

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
   private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

sendMessage(msg)

public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

總結(jié):從源碼分析,post(runnable)與sendMessage(msg)本質(zhì)是一樣的,最后返回的都是sendMessageDelayed(msg,0);post()通過調(diào)用getPostMessage()方法將Runnable賦值到Message的callback變量中;

消息處理:Looper從MessageQueue中取出Message之后,會調(diào)用dispatchMessage方法進行處理;

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

dispatchMessage兩種情況

1、如果Message的callback不為null,一般為通過post(Runnable)方式,會直接執(zhí)行Runnable的run()。因此這里的Runnable實際上就是一個回調(diào)接口,跟線程Thread沒有任何關(guān)系;

2、如果Message的callback為null,這種一般為sendMessage的方式,則會調(diào)用handlerMessage()方法進行處理;

4.3 Handler如何實現(xiàn)線程隔離的

final MessageQueue mQueue;
public static @Nullable Looper myLooper(){
  return sThreadLocal.get();
}

ThreadLocal是一個能創(chuàng)建線程局部變量的類。通過ThreadLocal提供的get和set方法,可以為每一個使用該變量的線程保存一份數(shù)據(jù)副本,且線程之間是不能相互訪問,從而達到變量在線程間隔離、封閉的效果。

4.4 sendMessageDelayed()是如何實現(xiàn)的

向Message隊列中插入Message時,會根據(jù)Message的執(zhí)行時間排序,而消息的延時處理的核心實現(xiàn)是在獲取Message的階段,MessageQueue的next方法如下:

Message next(){
if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }
}

從MessageQueue中取出一個Message,但是當前的系統(tǒng)時間小于Message.when,因此會計算一個timeout,目的是實現(xiàn)在timeout時間段后再將UI線程喚醒,因此后續(xù)處理Message的代碼只會在timeout時間之后才會被CPU執(zhí)行;
如果當前系統(tǒng)時間大于或等于Message.when,那么會返回Message給Looper.loop().但是這個邏輯只能保證在when之前的消息不被處理,不能保證一定在when時被處理。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android UI實現(xiàn)SlidingMenu側(cè)滑菜單效果

    Android UI實現(xiàn)SlidingMenu側(cè)滑菜單效果

    這篇文章主要為大家詳細介紹了Android UI實現(xiàn)SlidingMenu側(cè)滑菜單效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 詳解Android冷啟動實現(xiàn)APP秒開的方法

    詳解Android冷啟動實現(xiàn)APP秒開的方法

    這篇文章給大家介紹的是Android冷啟動實現(xiàn)APP秒開的方法,對大家日常開發(fā)APP還是很實用的,有需要的可以參考借鑒。
    2016-08-08
  • Android中init.rc文件的解析 分享

    Android中init.rc文件的解析 分享

    本文分析Android中如何解析init.rc文件,重點描述了on action內(nèi)的解析,并從解析的過程中總結(jié)出init.rc的語法規(guī)范。
    2013-06-06
  • Android 手機防止休眠的兩種實現(xiàn)方法

    Android 手機防止休眠的兩種實現(xiàn)方法

    這篇文章主要介紹了Android 手機防止休眠方法的相關(guān)資料,一種是在Manifest.xml文件里面聲明,另外一種方法是在代碼里面修改LayoutParams的標志位,需要的朋友可以參考下
    2017-08-08
  • Android實現(xiàn)院系專業(yè)三級聯(lián)動

    Android實現(xiàn)院系專業(yè)三級聯(lián)動

    這篇文章主要為大家詳細介紹了Android實現(xiàn)院系專業(yè)三級聯(lián)動,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • Android中的build.gradle文件深入講解

    Android中的build.gradle文件深入講解

    這篇文章主要給大家介紹了關(guān)于Android中build.gradle文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-10-10
  • android使用videoview播放視頻

    android使用videoview播放視頻

    這篇文章主要介紹了Android利用自帶VideoView控件播放視頻的示例,需要的朋友可以參考下
    2014-02-02
  • android studio按鈕監(jiān)聽的5種方法實例詳解

    android studio按鈕監(jiān)聽的5種方法實例詳解

    這篇文章主要介紹了android studio按鈕監(jiān)聽的5種方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • 在Android中創(chuàng)建菜單項Menu以及獲取手機分辨率的解決方法

    在Android中創(chuàng)建菜單項Menu以及獲取手機分辨率的解決方法

    本篇文章小編為大家介紹,在Android中創(chuàng)建菜單項Menu以及獲取手機分辨率的解決方法。需要的朋友參考下
    2013-04-04
  • Android RelativeLayout相對布局屬性簡析

    Android RelativeLayout相對布局屬性簡析

    在Android應(yīng)用開發(fā)過程中,為了界面的美觀考慮,經(jīng)常會使用到布局方面的屬性,本文就以此問題深入解析,詳解一下Android RelativeLayout相對布局屬性在實際開發(fā)中的應(yīng)用,需要的朋友可以參考下
    2012-11-11

最新評論