我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android时间设置问题怎么解决

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android时间设置问题怎么解决

这篇文章主要讲解了“Android时间设置问题怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android时间设置问题怎么解决”吧!

问题现象

最近处理了一个非常有意思的系统bug,修改系统时间,重启后居然没有生效

Android时间设置问题怎么解决

注意要关闭使用网络提供的时间和使用网络提供的时区这两个开关。

重启后显示的时间日期为

Android时间设置问题怎么解决

显示的时间既不是我设置的时间,也不是当前时间(当前时间为2023-03-20 15:49),那么显示的这个时间到底是什么时间呢?

为了弄清楚这个问题,我研究了一下Android设置时间的逻辑,研究过程中还发现了一些彩蛋。

源码分析

首先是设置时间的逻辑,源码位于packages/apps/Settings/class="lazy" data-src/com/android/settings/datetime/DatePreferenceController.java

public class DatePreferenceController extends AbstractPreferenceController        implements PreferenceControllerMixin, DatePickerDialog.OnDateSetListener {    //省略部分代码    private final DatePreferenceHost mHost;    @Override    public boolean handlePreferenceTreeClick(Preference preference) {        //点击日期后处理        if (!TextUtils.equals(preference.getKey(), KEY_DATE)) {            return false;        }        //显示日期选择框        mHost.showDatePicker();        return true;    }    //省略部分代码}

mHostDatePreferenceHost接口,接口实现在packages/apps/Settings/class="lazy" data-src/com/android/settings/DateTimeSettings.java中,因此,showDatePicker()的逻辑位于该实现类中

@SearchIndexablepublic class DateTimeSettings extends DashboardFragment implements        TimePreferenceController.TimePreferenceHost, DatePreferenceController.DatePreferenceHost {    //省略部分代码@Override    public void showDatePicker() {        //显示日期选择对话框        showDialog(DatePreferenceController.DIALOG_DATEPICKER);    }    //省略部分代码}

showDialog()定义在父类packages/apps/Settings/class="lazy" data-src/com/android/settings/SettingsPreferenceFragment.java

public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceFragment        implements DialogCreatable, HelpResourceProvider, Indexable {    protected void showDialog(int dialogId) {        if (mDialogFragment != null) {            Log.e(TAG, "Old dialog fragment not null!");        }        //创建SettingsDialogFragment并进行show        mDialogFragment = SettingsDialogFragment.newInstance(this, dialogId);        mDialogFragment.show(getChildFragmentManager(), Integer.toString(dialogId));    }}

showDialog()中就是创建了SettingsDialogFragment然后显示,SettingsDialogFragmentSettingsPreferenceFragment的一个内部类,看一下SettingsDialogFragment的定义

    public static class SettingsDialogFragment extends InstrumentedDialogFragment {        private static final String KEY_DIALOG_ID = "key_dialog_id";        private static final String KEY_PARENT_FRAGMENT_ID = "key_parent_fragment_id";        private Fragment mParentFragment;        private DialogInterface.OnCancelListener mOnCancelListener;        private DialogInterface.OnDismissListener mOnDismissListener;        public static SettingsDialogFragment newInstance(DialogCreatable fragment, int dialogId) {            if (!(fragment instanceof Fragment)) {                throw new IllegalArgumentException("fragment argument must be an instance of "                        + Fragment.class.getName());            }            final SettingsDialogFragment settingsDialogFragment = new SettingsDialogFragment();            settingsDialogFragment.setParentFragment(fragment);            settingsDialogFragment.setDialogId(dialogId);            return settingsDialogFragment;        }        @Override        public int getMetricsCategory() {            if (mParentFragment == null) {                return Instrumentable.METRICS_CATEGORY_UNKNOWN;            }            final int metricsCategory =                    ((DialogCreatable) mParentFragment).getDialogMetricsCategory(mDialogId);            if (metricsCategory <= 0) {                throw new IllegalStateException("Dialog must provide a metrics category");            }            return metricsCategory;        }        @Override        public void onSaveInstanceState(Bundle outState) {            super.onSaveInstanceState(outState);            if (mParentFragment != null) {                outState.putInt(KEY_DIALOG_ID, mDialogId);                outState.putInt(KEY_PARENT_FRAGMENT_ID, mParentFragment.getId());            }        }        @Override        public void onStart() {            super.onStart();            if (mParentFragment != null && mParentFragment instanceof SettingsPreferenceFragment) {                ((SettingsPreferenceFragment) mParentFragment).onDialogShowing();            }        }        @Override        public Dialog onCreateDialog(Bundle savedInstanceState) {            if (savedInstanceState != null) {                mDialogId = savedInstanceState.getInt(KEY_DIALOG_ID, 0);                mParentFragment = getParentFragment();                int mParentFragmentId = savedInstanceState.getInt(KEY_PARENT_FRAGMENT_ID, -1);                if (mParentFragment == null) {                    mParentFragment = getFragmentManager().findFragmentById(mParentFragmentId);                }                if (!(mParentFragment instanceof DialogCreatable)) {                    throw new IllegalArgumentException(                            (mParentFragment != null                                    ? mParentFragment.getClass().getName()                                    : mParentFragmentId)                                    + " must implement "                                    + DialogCreatable.class.getName());                }                // This dialog fragment could be created from non-SettingsPreferenceFragment                if (mParentFragment instanceof SettingsPreferenceFragment) {                    // restore mDialogFragment in mParentFragment                    ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = this;                }            }            //通过DialogCreatable接口剥离了dialog的创建            return ((DialogCreatable) mParentFragment).onCreateDialog(mDialogId);        }        @Override        public void onCancel(DialogInterface dialog) {            super.onCancel(dialog);            if (mOnCancelListener != null) {                mOnCancelListener.onCancel(dialog);            }        }        @Override        public void onDismiss(DialogInterface dialog) {            super.onDismiss(dialog);            if (mOnDismissListener != null) {                mOnDismissListener.onDismiss(dialog);            }        }        public int getDialogId() {            return mDialogId;        }        @Override        public void onDetach() {            super.onDetach();            // This dialog fragment could be created from non-SettingsPreferenceFragment            if (mParentFragment instanceof SettingsPreferenceFragment) {                // in case the dialog is not explicitly removed by removeDialog()                if (((SettingsPreferenceFragment) mParentFragment).mDialogFragment == this) {                    ((SettingsPreferenceFragment) mParentFragment).mDialogFragment = null;                }            }        }        private void setParentFragment(DialogCreatable fragment) {            mParentFragment = (Fragment) fragment;        }        private void setDialogId(int dialogId) {            mDialogId = dialogId;        }    }

很标准的自定义DialogFragment的模板代码,核心代码在onCreateDialog()方法当中,但此方法通过DialogCreatable接口剥离了dialog的创建,这里也很好理解,因为不仅有设置日期的Dialog,还有设置时间的Dialog,如果写死的话,那么就需要定义两个DialogFragment,所以这里它给抽象出来了,DialogCreatable接口的实现仍然在DateTimeSettings当中,它的父类SettingsPreferenceFragment实现了DialogCreatable

@SearchIndexablepublic class DateTimeSettings extends DashboardFragment implements        TimePreferenceController.TimePreferenceHost, DatePreferenceController.DatePreferenceHost {    //省略部分代码@Override    public Dialog onCreateDialog(int id) {        //根据选项创建对应的dialog        switch (id) {            case DatePreferenceController.DIALOG_DATEPICKER:                return use(DatePreferenceController.class)                        .buildDatePicker(getActivity());            case TimePreferenceController.DIALOG_TIMEPICKER:                return use(TimePreferenceController.class)                        .buildTimePicker(getActivity());            default:                throw new IllegalArgumentException();        }    }    //省略部分代码}

根据用户选择的操作(设置日期or设置时间),创建对应的dialog,最终的创建过程由DatePreferenceController来完成

public class DatePreferenceController extends AbstractPreferenceController        implements PreferenceControllerMixin, DatePickerDialog.OnDateSetListener {    //省略部分代码public DatePickerDialog buildDatePicker(Activity activity) {        final Calendar calendar = Calendar.getInstance();        //创建DatePickerDialog        final DatePickerDialog d = new DatePickerDialog(                activity,                this,                calendar.get(Calendar.YEAR),                calendar.get(Calendar.MONTH),                calendar.get(Calendar.DAY_OF_MONTH));        // The system clock can't represent dates outside this range.        calendar.clear();        calendar.set(2007, Calendar.JANUARY, 1);        //设置最小时间为2007-01-01        d.getDatePicker().setMinDate(calendar.getTimeInMillis());        calendar.clear();        calendar.set(2037, Calendar.DECEMBER, 31);        //设置最大时间为2037-12-31        d.getDatePicker().setMaxDate(calendar.getTimeInMillis());        return d;    }    //省略部分代码}

这里可以看到,系统限制了可选的日期范围为2007-01-01至2037-12-31,实际操作也确实是这样子的(开发板和小米手机都是),此为彩蛋1。

Android时间设置问题怎么解决

看一下DatePickerDialog的定义

public class DatePickerDialog extends AlertDialog implements OnClickListener,        OnDateChangedListener {    private static final String YEAR = "year";    private static final String MONTH = "month";    private static final String DAY = "day";    @UnsupportedAppUsage    private final DatePicker mDatePicker;    private OnDateSetListener mDateSetListener;    //省略部分代码    private DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,            @Nullable OnDateSetListener listener, @Nullable Calendar calendar, int year,            int monthOfYear, int dayOfMonth) {        super(context, resolveDialogTheme(context, themeResId));        final Context themeContext = getContext();        final LayoutInflater inflater = LayoutInflater.from(themeContext);        //初始化Dialog的View        final View view = inflater.inflate(R.layout.date_picker_dialog, null);        setView(view);        setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);        setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);        setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);        if (calendar != null) {            year = calendar.get(Calendar.YEAR);            monthOfYear = calendar.get(Calendar.MONTH);            dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);        }        mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);        mDatePicker.init(year, monthOfYear, dayOfMonth, this);        mDatePicker.setValidationCallback(mValidationCallback);        mDateSetListener = listener;    }    //省略部分代码        public void setOnDateSetListener(@Nullable OnDateSetListener listener) {        mDateSetListener = listener;    }    @Override    public void onClick(@NonNull DialogInterface dialog, int which) {        switch (which) {            case BUTTON_POSITIVE:                if (mDateSetListener != null) {                    // Clearing focus forces the dialog to commit any pending                    // changes, e.g. typed text in a NumberPicker.                    mDatePicker.clearFocus();                    //设置完成回调                    mDateSetListener.onDateSet(mDatePicker, mDatePicker.getYear(),                            mDatePicker.getMonth(), mDatePicker.getDayOfMonth());                }                break;            case BUTTON_NEGATIVE:                cancel();                break;        }    }    //省略部分代码        public interface OnDateSetListener {                void onDateSet(DatePicker view, int year, int month, int dayOfMonth);    }}

可以看到也是标准的自定义Dialog,不过它是继承的AlertDialog,设置完成后通过OnDateSetListener进行回调,而DatePreferenceController实现了该接口

public class DatePreferenceController extends AbstractPreferenceController        implements PreferenceControllerMixin, DatePickerDialog.OnDateSetListener {//省略部分代码    @Override    public void onDateSet(DatePicker view, int year, int month, int day) {        //设置日期        setDate(year, month, day);        //更新UI        mHost.updateTimeAndDateDisplay(mContext);    }    //省略部分代码        @VisibleForTesting    void setDate(int year, int month, int day) {        Calendar c = Calendar.getInstance();        c.set(Calendar.YEAR, year);        c.set(Calendar.MONTH, month);        c.set(Calendar.DAY_OF_MONTH, day);        //设置日期与定义的最小日期取最大值,也就意味着设置的日期不能小于定义的最小日期        long when = Math.max(c.getTimeInMillis(), DatePreferenceHost.MIN_DATE);        if (when / 1000 < Integer.MAX_VALUE) {            //设置系统时间            ((AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE)).setTime(when);        }    }}

可以看到系统定义了一个最小日期DatePreferenceHost.MIN_DATE,其值为2007-11-05 0:00

public interface UpdateTimeAndDateCallback {    // Minimum time is Nov 5, 2007, 0:00.    long MIN_DATE = 1194220800000L;    void updateTimeAndDateDisplay(Context context);}

最终显示日期会在目标日期和最小日期中取最大值,也就是说设定的日期不能小于最小日期,而上文说到,选择的日期范围为2007-01-01至2037-12-31,因此,如果你设置的日期在2007-01-01至2007-11-05之间,最终都会显示2007-11-05,实际测试也是如此(开发板和小米手机都是),此为彩蛋2。

Android时间设置问题怎么解决

选择完时间后,最后通过AlarmManagerService来设置系统内核的时间,此处涉及到跨进程通信,使用的通信方式是AIDL,直接到AlarmManagerService看看如何设置内核时间的

class AlarmManagerService extends SystemService {    //省略部分代码    private final IBinder mService = new IAlarmManager.Stub() {        //省略部分代码@Override        public boolean setTime(long millis) {            //先授权            getContext().enforceCallingOrSelfPermission(                    "android.permission.SET_TIME",                    "setTime");//然后设置系统内核时间            return setTimeImpl(millis);        }        //省略部分代码    }        //省略部分代码        boolean setTimeImpl(long millis) {        if (!mInjector.isAlarmDriverPresent()) {            Slog.w(TAG, "Not setting time since no alarm driver is available.");            return false;        }        synchronized (mLock) {            final long currentTimeMillis = mInjector.getCurrentTimeMillis();            //设置系统内核时间            mInjector.setKernelTime(millis);            final TimeZone timeZone = TimeZone.getDefault();            final int currentTzOffset = timeZone.getOffset(currentTimeMillis);            final int newTzOffset = timeZone.getOffset(millis);            if (currentTzOffset != newTzOffset) {                Slog.i(TAG, "Timezone offset has changed, updating kernel timezone");                //设置系统内核时区                mInjector.setKernelTimezone(-(newTzOffset / 60000));            }            // The native implementation of setKernelTime can return -1 even when the kernel            // time was set correctly, so assume setting kernel time was successful and always            // return true.            return true;        }    }        //省略部分代码        @VisibleForTesting    static class Injector {    //省略部分代码        void setKernelTime(long millis) {            Log.d("jasonwan", "setKernelTime: "+millis);            if (mNativeData != 0) {                //在native层完成内核时间的设置                AlarmManagerService.setKernelTime(mNativeData, millis);            }        }        //省略部分代码    }        //native层完成    private static native int setKernelTime(long nativeData, long millis);    private static native int setKernelTimezone(long nativeData, int minuteswest);    //省略部分代码}

可以看到最终是在native层完成内核时间的设置,这也理所当然,毕竟java是应用层,触及不到kernel层。

回到最开始的问题,为啥开机之后却不是我们设置的时间呢,这就要看看开机之后系统是怎么设置时间的。同样在AlarmManagerService里面,因为它是SystemService的子类,所以会随着开机启动而启动,而Service启动后必定会执行它的生命周期方法,设置时间的逻辑就是在onStart()生命周期方法里面

class AlarmManagerService extends SystemService {    //省略部分代码    @Override    public void onStart() {        mInjector.init();        synchronized (mLock) {            //省略部分代码            // We have to set current TimeZone info to kernel            // because kernel doesn't keep this after reboot            //设置时区,从SystemProperty中读取            setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));            // Ensure that we're booting with a halfway sensible current time.  Use the            // most recent of Build.TIME, the root file system's timestamp, and the            // value of the ro.build.date.utc system property (which is in seconds).            //设置时区            //先读取系统编译时间            long utc = 1000L * SystemProperties.getLong("ro.build.date.utc", -1L);            //再读取根目录最近的修改的时间            long lastModified = Environment.getRootDirectory().lastModified();            //然后读取系统构建时间,三个时间取最大值            final long systemBuildTime =  Long.max(                    utc,                    Long.max(lastModified, Build.TIME));            //代码1            Log.d("jasonwan", "onStart: utc="+utc+", lastModified="+lastModified+", BuildTime="+Build.TIME+", currentTimeMillis="+mInjector.getCurrentTimeMillis());            //设置的时间小于最大值,则将最大值设置为系统内核的时间,注意,因为我们刚刚已经设置了内核时间,所以重启后通过System.currentTimeMillis()得到的时间戳为我们设置的时间,此判断意味着,系统编译时间、根目录最近修改时间、系统构建时间、设置的时间,这四者当中取最大值作为重启后的内核时间            if (mInjector.getCurrentTimeMillis() < systemBuildTime) {                //这里mInjector.getCurrentTimeMillis()其实就是System.currentTimeMillis()                Slog.i(TAG, "Current time only " + mInjector.getCurrentTimeMillis()                        + ", advancing to build time " + systemBuildTime);                mInjector.setKernelTime(systemBuildTime);            }            //省略部分代码    }    //省略部分代码            @VisibleForTesting    static class Injector {        //省略部分代码        void setKernelTimezone(int minutesWest) {            AlarmManagerService.setKernelTimezone(mNativeData, minutesWest);        }        void setKernelTime(long millis) {            //代码2            Log.d("jasonwan", "setKernelTime: "+millis);            if (mNativeData != 0) {                AlarmManagerService.setKernelTime(mNativeData, millis);            }        }        //省略部分代码        long getElapsedRealtime() {            return SystemClock.elapsedRealtime();        }        long getCurrentTimeMillis() {            return System.currentTimeMillis();        }        //省略部分代码    }}

实践验证

根据源码分析得知,系统最终会在系统编译时间、根目录最近修改时间、系统构建时间、设置的时间,这四者当中取最大值作为重启后的内核时间,这里我在代码1和代码2处埋下了log,看看四个时间的值分别是多少,以及最终设置的内核时间是多少,我在设置中手动设置的日期为2022-10-01,重启后的日志如下

Android时间设置问题怎么解决

四个值分别为:

  • 系统编译时间:1669271830000,格式化后为2022-11-24 14:37:10

  • 根目录最近修改时间:1678865533000,格式化后为2023-03-15 15:32:13

  • 构建时间:1669271830000,同系统编译时间

  • 设置的时间:1664609754998,格式化后为2022-10-01 15:35:54

注意,我们只需要注意日期,不需要关注时分秒,可以看到四个时间当中,最大的为根目录最近修改时间,所以最终显示的日期为2023-03-15,此为彩蛋3。

Android时间设置问题怎么解决

我在开发板和小米手机上测试的结果相同,说明MIUI保留了这一块的逻辑,但是MIUI也有一个bug,就是明明我关闭了使用网络提供的时间和使用网络提供的时区,它还是给我自动更新了日期和时间,除非开启飞行模式之后才不自动更新。

同时我们还注意到,系统编译时间ro.build.date.utc跟系统构建时间Build.TIME是相同的,这很好理解,编译跟构建是一个意思,而且Build.TIME的取值其实也来自于ro.build.date.utc

public class Build {    //省略部分代码    public static final long TIME = getLong("ro.build.date.utc") * 1000;    //省略部分代码}

感谢各位的阅读,以上就是“Android时间设置问题怎么解决”的内容了,经过本文的学习后,相信大家对Android时间设置问题怎么解决这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android时间设置问题怎么解决

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android时间设置问题怎么解决

这篇文章主要讲解了“Android时间设置问题怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Android时间设置问题怎么解决”吧!问题现象最近处理了一个非常有意思的系统bug,修改
2023-07-05

nginx设置超时时间的问题及解决方案

nginx超时设置常见问题包括启动超时、读写超时、keepalive超时和发送超时。优化超时设置的最佳实践包括识别关键请求、使用合理默认值、根据负载调整超时、使用keepalive连接和监视超时错误。具体示例包括增加启动超时、调整读写超时、优化keepalive超时和减少发送超时。
nginx设置超时时间的问题及解决方案
2024-04-02

怎么解决php.ini设置时区不生效问题

这篇文章主要介绍“怎么解决php.ini设置时区不生效问题”,在日常操作中,相信很多人在怎么解决php.ini设置时区不生效问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么解决php.ini设置时区不生
2023-06-25

postgresql timestamp时间戳问题怎么解决

这篇文章主要介绍“postgresql timestamp时间戳问题怎么解决”,在日常操作中,相信很多人在postgresql timestamp时间戳问题怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答
2023-07-05

redis过期时间的问题怎么解决

这篇文章主要介绍“redis过期时间的问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“redis过期时间的问题怎么解决”文章能帮助大家解决问题。1.多次修改一个redis的String过期
2023-07-06

怎么解决 Windows-Linux 双启动设置中显示时间错误的问题

这篇文章主要讲解了“怎么解决 Windows-Linux 双启动设置中显示时间错误的问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么解决 Windows-Linux 双启动设置中显示时
2023-06-15

php时间格式转换时间戳的问题怎么解决

本文小编为大家详细介绍“php时间格式转换时间戳的问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“php时间格式转换时间戳的问题怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。时间戳是一个整数值
2023-07-05

Android的Toast问题怎么解决

这篇“Android的Toast问题怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android的Toast问题怎么
2023-06-04

android中FLAG_ACTIVITY_NEW_TASK问题怎么解决

在Android中,FLAG_ACTIVITY_NEW_TASK标志用于启动一个新的任务栈。如果出现FLAG_ACTIVITY_NEW_TASK问题,可能是因为在启动一个Activity时没有正确设置该标志或者该标志被错误地设置了。以下是解
2023-08-19

解决Android webview设置cookie和cookie丢失的问题

Android页面嵌套了一个h5,H5页面内部有用户登陆页面,发现h5页面的登陆功能无法使用,一直登陆失败。和web那边商量一会,发现js写入的cookie丢失了。所有需要Android这边在重写写入一次。mWebView = view.f
2022-06-06

Ubuntu的tzselect设置时间失效怎么解决

今天小编给大家分享一下Ubuntu的tzselect设置时间失效怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。tzs
2023-07-04

php跳转时间戳相关问题怎么解决

这篇文章主要介绍了php跳转时间戳相关问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇php跳转时间戳相关问题怎么解决文章都会有所收获,下面我们一起来看看吧。PHP跳转时间戳:在网站开发中,常常需要用
2023-07-05

android handler移除问题怎么解决

要解决Android Handler移除问题,可以参考以下几个步骤:1. 在使用Handler的Activity或Fragment的生命周期方法中,确保在适当的时机移除Handler的消息和回调。例如,在onPause()方法中移除消息和回
2023-10-18

sql模式设置引起的问题怎么解决

今天小编给大家分享一下sql模式设置引起的问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1 报错类似如下数据库错
2023-06-30

Android中EditText 设置 imeOptions 无效问题的解决方法

有时候我们需要在EditText 输出完之后 需要在键盘出现 右下角变成“Go”或“前往 搜索时;通常我们需要设置Android:imeOptions属性。Android:imeOptions的值有actionGo、 actionSend
2022-06-06

设置session过期时间不生效怎么解决

如果设置session过期时间不生效,可能是由于以下原因:1. 服务器配置问题:检查服务器的session配置是否正确。确保session的过期时间设置正确,并且服务器支持session过期时间的功能。2. 代码逻辑问题:检查代码中是否有其
2023-08-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录