Android 可以正常在XML中预览的TextClock(解决TextClock在Android studio3.5以上版本无法正常预览)

话不多说 先放图 (xml预览截图)不太会录制gif


时间则是在xm预览中的效果,每次打开xml的时候会自动刷新,但是预览界面中xml是不会动的,实际运行起来每秒跳动一次

Android自带的TextClock会导致xml无法正常预览和刷新
具体问题表现在AS 3.5以上的版本中都有卡顿
具体表现你在xml中放一个TextClock就知道了,这里不赘述

寻找原因

查看TextClock以后发现
核心问题是TextClock中存在一个FormatChangeObserver , 继承于ContentObserver
然后在TextClock的onAttachedToWindow方法中调用了以下代码

    private void registerObserver() {
        if (mRegistered) {
            if (mFormatChangeObserver == null) {
                mFormatChangeObserver = new FormatChangeObserver(getHandler());
            }
            final ContentResolver resolver = getContext().getContentResolver();
            Uri uri = Settings.System.getUriFor(Settings.System.TIME_12_24);
            if (mShowCurrentUserTime) {
                resolver.registerContentObserver(uri, true,
                        mFormatChangeObserver, UserHandle.USER_ALL);
            } else {
                // UserHandle.myUserId() is needed. This class is supported by the
                // remote views mechanism and as a part of that the remote views
                // can be inflated by a context for another user without the app
                // having interact users permission - just for loading resources.
                // For example, when adding widgets from a managed profile to the
                // home screen. Therefore, we register the ContentObserver with the user
                // the app is running (e.g. the launcher) and not the user of the
                // context (e.g. the widget's profile).
                resolver.registerContentObserver(uri, true,
                        mFormatChangeObserver, UserHandle.myUserId());
            }
        }
    }

这个代码中的FormatChangeObserver主要作用是观察手机的时区变化和12/24小时设置的变化
调用位置是


    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        if (!mRegistered) {
            mRegistered = true;

            registerReceiver();
            registerObserver();

            createTime(mTimeZone);
        }
    }

具体分析原因就是在onAttachedToWindow中调用了 registerObserver();
导致XML实时更新的时候处理不了(具体原因不明)
Google搜索以后发现AS3.5以后的版本都有这样的问题

解决

其实在项目场景中,时钟样式都是固定的.除非是做组件视图
在自己重写了一个TextClock后
1.忽略了对设备设置中的12/24小时制处理
2.忽略了对时区的处理
3.固定了显示时间的格式
代码如下

package com.linkturing.base.widget;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.SystemClock;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.widget.TextClock;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;

import java.util.Calendar;

/**
 * ================================================
 * Description:
 * <p>
 * Created by Alex on 2020/9/1 0001
 * <p>
 * 页面内容介绍:
 * <p>
 * ================================================
 */
public class AlexTextClock extends TextClock {
    private String timeFormat = "yyyy年MM月dd日 hh:mm:ss EEEE";

    private Calendar mTime;

    public AlexTextClock Context context) {
        super(context);
    }

    public AlexTextClock Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AlexTextClock Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
       
        public void onReceive(Context context, Intent intent) {
            onTimeChanged();
        }
    };

    private void onTimeChanged() {
        mTime.setTimeInMillis(System.currentTimeMillis());
        setText(DateFormat.format(timeFormat, mTime));
    }

    private final Runnable mTicker = new Runnable() {
        public void run() {

            onTimeChanged();

            long now = SystemClock.uptimeMillis();
            long next = now + (1000 - now % 1000);

            getHandler().postAtTime(mTicker, next);
        }
    };

   
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mTime = Calendar.getInstance();
        mTime.setTimeInMillis(System.currentTimeMillis());
        setText(DateFormat.format(timeFormat, mTime));
        mTicker.run();

        final IntentFilter filter = new IntentFilter();

        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
        getContext().registerReceiver(mIntentReceiver, filter);
    }

   
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        getContext().unregisterReceiver(mIntentReceiver);
    }
}

代码很简单,但是可以在xml中正常预览,以及每次打开xml的时候会更新预览时间
没有设置自定义属性,普通属性和TextView写法相同
写死了时间格式,有需要自己改
需要实现更复杂的功能等以后更新吧

© 著作权归作者所有
这个作品真棒,我要支持一下!
大话安卓群友文章分享,包含一些技术讨论、新框架介绍
0条评论
top Created with Sketch.