代码

    // 构建JobInfo对象,传递给JobSchedulerService
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID,new ComponentName(mContext, AliveJobService.class));
builder.setPeriodic(5000);
builder.setPersisted(true);
builder.setRequiresCharging(true);
JobInfo info = builder.build();
mJobScheduler.schedule(info);

这段定时任务在每隔5秒执行一次任务,Android 5.0和6.0系统能够正常运行.但是在Android7.0不能正常工作了。

https://stackoverflow.com/questions/39641278/job-scheduler-in-android-n-with-less-then-15-minutes-interval?rq=1

https://stackoverflow.com/questions/38344220/job-scheduler-not-running-on-android-n/38774104

看万两片关于JobService 7.0(Nougat) 看完有几个疑问

1.如果想到在小于15分钟间隔执行为什么要设置setMinimumLatency()?

2.setBackoffCriteria(youtime, JobInfo.BACKOFF_POLICY_LINEAR)这个是有什么作用,如果不设置会怎么样?

3.如果设置obFinished(parameters, true)和obFinished(parameters, false)有什么区别

4.如果想重复执行怎么操作?

想知道这些问题的答案肯定要看源码

andorid 7.5JobInfo源码

package android.app.job;

public class JobInfo implements Parcelable {
//... /**
* Amount of backoff a job has initially by default, in milliseconds.
*/
public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 30 seconds. /**
* Maximum backoff we allow for a job, in milliseconds.
*/
public static final long MAX_BACKOFF_DELAY_MILLIS = 5 * 60 * 60 * 1000; // 5 hours. public static final int BACKOFF_POLICY_LINEAR = 0; public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
//默认指数
public static final int DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL; /* Minimum interval for a periodic job, in milliseconds. */
private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L; // 15 minutes /* Minimum flex for a periodic job, in milliseconds. */
private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes /**
* Specify that this job should be delayed by the provided amount of time.
* Because it doesn't make sense setting this property on a periodic job, doing so will
* throw an {@link java.lang.IllegalArgumentException} when
* {@link android.app.job.JobInfo.Builder#build()} is called.
* @param minLatencyMillis Milliseconds before which this job will not be considered for
* execution.
*/ public Builder setMinimumLatency(long minLatencyMillis) {
mMinLatencyMillis = minLatencyMillis;
mHasEarlyConstraint = true;
return this;
} /**
* 最小15分钟
*/
public static final long getMinPeriodMillis() {
return MIN_PERIOD_MILLIS;
} public Builder setPeriodic(long intervalMillis, long flexMillis) {
mIsPeriodic = true;
mIntervalMillis = intervalMillis;
mFlexMillis = flexMillis;
mHasEarlyConstraint = mHasLateConstraint = true;
return this;
} /**
* 最小15分钟 如果值比15分钟大取大的值
*/
public long getIntervalMillis() {
return intervalMillis >= getMinPeriodMillis() ? intervalMillis : getMinPeriodMillis();
} /**
* 最小5分钟
*/
public static final long getMinFlexMillis() {
return MIN_FLEX_MILLIS;
} /**
* Math.max(percentClamp, getMinFlexMillis())最小15分钟
* flexMillis 是setPeriodic(long intervalMillis, long flexMillis)第二参数,默认这个和intervalMillis
* clampedFlex的值最小值15分钟
*/
public long getFlexMillis() {
long interval = getIntervalMillis();//最小15分钟
long percentClamp = 5 * interval / 100; //取时间间隔的5%
//先取getMinFlexMillis()五分钟 和getIntervalMillis()的5%的取最大值
//然后和设置的setPeriodic(long intervalMillis, long flexMillis)中的flexMillis取最大值
//所有这里最小的值15分钟
long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, getMinFlexMillis()));
//如果这个值比间隔小,去这个值,如果比间隔大去间隔值
return clampedFlex <= interval ? clampedFlex : interval;
} /**
* The amount of time the JobScheduler will wait before rescheduling a failed job. This value
* will be increased depending on the backoff policy specified at job creation time. Defaults
* to 5 seconds.
*/
public long getInitialBackoffMillis() {
return initialBackoffMillis;
} public Builder setBackoffCriteria(long initialBackoffMillis, int backoffPolicy) {
mBackoffPolicySet = true;
mInitialBackoffMillis = initialBackoffMillis;
mBackoffPolicy = backoffPolicy;
return this;
} //... }

JobInfo这里

看完这个类可以回答这个问题

1.如果想到在小于15分钟间隔执行为什么要设置.setMinimumLatency()

在7.0调用setPeriodic()之后在获取间隔时间getIntervalMillis() 强制使用了最小时间15分钟。所以想通过setPeriodic()来设置小于15分钟间隔是不行的。所以如果小于15分钟需要通过设置setMinimumLatency ()

     public Builder setMinimumLatency(long minLatencyMillis) {
mMinLatencyMillis = minLatencyMillis;
mHasEarlyConstraint = true;
return this;
} /**
* 最小15分钟
*/
public static final long getMinPeriodMillis() {
return MIN_PERIOD_MILLIS;
} public Builder setPeriodic(long intervalMillis, long flexMillis) {
mIsPeriodic = true;
mIntervalMillis = intervalMillis;
mFlexMillis = flexMillis;
mHasEarlyConstraint = mHasLateConstraint = true;
return this;
} /**
* 最小15分钟 如果值比15分钟大取大的值
*/
public long getIntervalMillis() {
return intervalMillis >= getMinPeriodMillis() ? intervalMillis : getMinPeriodMillis();
}

1.getIntervalMillis()最小值15分钟

2.getFlexMillis()最小值15分钟

3.getMinFlexMillis最小值5分钟

andorid 7.1NJobSchedulerService源码

  public final class JobSchedulerService extends com.android.server.SystemService
implements StateChangedListener, JobCompletedListener {
//... 862 /**
863 * Called when we have a job status object that we need to insert in our
864 * {@link com.android.server.job.JobStore}, and make sure all the relevant controllers know
865 * about.
866 */
867 private void startTrackingJob(JobStatus jobStatus, JobStatus lastJob) {
868 synchronized (mLock) {
869 final boolean update = mJobs.add(jobStatus);
870 if (mReadyToRock) {
871 for (int i = 0; i < mControllers.size(); i++) {
872 StateController controller = mControllers.get(i);
873 if (update) {
874 controller.maybeStopTrackingJobLocked(jobStatus, null, true);
875 }
876 controller.maybeStartTrackingJobLocked(jobStatus, lastJob);
877 }
878 }
879 }
880 } 882 /**
883 * Called when we want to remove a JobStatus object that we've finished executing. Returns the
884 * object removed.
先从 JobStore 中移除这个 job,因为 writeBack 为 true,则需要更新 jobxs.xml 文件,通知控制器,取消 track!
885 */ 886 private boolean stopTrackingJob(JobStatus jobStatus, JobStatus incomingJob,
887 boolean writeBack) {
888 synchronized (mLock) {
889 // Remove from store as well as controllers. 先从 JobStore 中移除这个 job,因为 writeBack 为 true,则需要更新 jobxs.xml 文件!
890 final boolean removed = mJobs.remove(jobStatus, writeBack);
891 if (removed && mReadyToRock) {
892 for (int i=0; i<mControllers.size(); i++) {
893 StateController controller = mControllers.get(i);//通知控制器,取消 track!
894 controller.maybeStopTrackingJobLocked(jobStatus, incomingJob, false);
895 }
896 }
897 return removed;
898 }
899 } 1026 /**
1027 * A job just finished executing. We fetch the
1028 * {@link com.android.server.job.controllers.JobStatus} from the store and depending on
1029 * whether we want to reschedule we readd it to the controllers.
1030 * @param jobStatus Completed job.
1031 * @param needsReschedule Whether the implementing class should reschedule this job.
1032 */
1033 @Override
1034 public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
1035 if (DEBUG) {
1036 Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
1037 }
1038 // Do not write back immediately if this is a periodic job. The job may get lost if system
1039 // shuts down before it is added back.
1040 if (!stopTrackingJob(jobStatus, null, !jobStatus.getJob().isPeriodic())) {//调用了 stopTrackingJob 将这个 job 从 JobStore 和 controller 中移除:
1041 if (DEBUG) {
1042 Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
1043 }
1044 // We still want to check for jobs to execute, because this job may have
1045 // scheduled a new job under the same job id, and now we can run it.
1046 mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
1047 return;
1048 }
1049 // Note: there is a small window of time in here where, when rescheduling a job,
1050 // we will stop monitoring its content providers. This should be fixed by stopping
1051 // the old job after scheduling the new one, but since we have no lock held here
1052 // that may cause ordering problems if the app removes jobStatus while in here.
1053 if (needsReschedule) {
1054 JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
1055 startTrackingJob(rescheduled, jobStatus);
1056 } else if (jobStatus.getJob().isPeriodic()) {//如果JobInfo调用setPeriodic会设置true
1057 JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
1058 startTrackingJob(rescheduledPeriodic, jobStatus);
1059 }
1060 reportActive();
1061 mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();//发送 MSG_CHECK_JOB_GREEDY 给 JobSchedulerService.JobHandler
1062 } 947 /**
948 * Reschedules the given job based on the job's backoff policy. It doesn't make sense to
949 * specify an override deadline on a failed job (the failed job will run even though it's not
950 * ready), so we reschedule it with {@link JobStatus#NO_LATEST_RUNTIME}, but specify that any
951 * ready job with {@link JobStatus#numFailures} > 0 will be executed.
952 *
953 * @param failureToReschedule Provided job status that we will reschedule.
954 * @return A newly instantiated JobStatus with the same constraints as the last job except
955 * with adjusted timing constraints.
956 *
957 * @see JobHandler#maybeQueueReadyJobsForExecutionLockedH
958 */
959 private JobStatus getRescheduleJobForFailure(JobStatus failureToReschedule) {
960 final long elapsedNowMillis = SystemClock.elapsedRealtime();
961 final JobInfo job = failureToReschedule.getJob();
962
963 final long initialBackoffMillis = job.getInitialBackoffMillis();
964 final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
965 long delayMillis;
966
967 switch (job.getBackoffPolicy()) {
968 case JobInfo.BACKOFF_POLICY_LINEAR:
969 delayMillis = initialBackoffMillis * backoffAttempts;
970 break;
971 default:
972 if (DEBUG) {
973 Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
974 }
975 case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
976 delayMillis =
977 (long) Math.scalb(initialBackoffMillis, backoffAttempts - 1);
978 break;
979 }
980 delayMillis =
981 Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);//和5小时比较
982 JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
983 JobStatus.NO_LATEST_RUNTIME, backoffAttempts);//构建新的JobStatu 设置下次时间 设置backoff次数
984 for (int ic=0; ic<mControllers.size(); ic++) {
985 StateController controller = mControllers.get(ic);
986 controller.rescheduleForFailure(newJob, failureToReschedule);
987 }
988 return newJob;
989 } 991 /**
992 * Called after a periodic has executed so we can reschedule it. We take the last execution
993 * time of the job to be the time of completion (i.e. the time at which this function is
994 * called).
995 * This could be inaccurate b/c the job can run for as long as
996 * {@link com.android.server.job.JobServiceContext#EXECUTING_TIMESLICE_MILLIS}, but will lead
997 * to underscheduling at least, rather than if we had taken the last execution time to be the
998 * start of the execution.
999 * @return A new job representing the execution criteria for this instantiation of the
1000 * recurring job.
1001 */
1002 private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
1003 final long elapsedNow = SystemClock.elapsedRealtime();
1004 // Compute how much of the period is remaining.
1005 long runEarly = 0L;
1006
1007 // If this periodic was rescheduled it won't have a deadline.
1008 if (periodicToReschedule.hasDeadlineConstraint()) {
1009 runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L);
1010 }
1011 long flex = periodicToReschedule.getJob().getFlexMillis();
1012 long period = periodicToReschedule.getJob().getIntervalMillis();//间隔时间
1013 long newLatestRuntimeElapsed = elapsedNow + runEarly + period;
1014 long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex;
1015
1016 if (DEBUG) {
1017 Slog.v(TAG, "Rescheduling executed periodic. New execution window [" +
1018 newEarliestRunTimeElapsed/1000 + ", " + newLatestRuntimeElapsed/1000 + "]s");
1019 }
1020 return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
1021 newLatestRuntimeElapsed, 0 /* backoffAttempt */);
1022 }
//...
}

3.如果设置obFinished(parameters, true)和obFinished(parameters, false)有什么区别

这里关键在onJobCompleted

首先调用了 stopTrackingJob 将这个 job 从 JobStore 和 controller 中移除,因为之前已经移除过了,所以这个 stopTrackingJob 的返回值为 false

   @Override
public void onJobCompleted(JobStatus jobStatus, boolean needsReschedule) {
if (DEBUG) {
Slog.d(TAG, "Completed " + jobStatus + ", reschedule=" + needsReschedule);
}
// Do not write back immediately if this is a periodic job. The job may get lost if system
// shuts down before it is added back.
// 再次停止 track 这个 job,这里 stopTrackingJob 的返回值为 false!
if (!stopTrackingJob(jobStatus, null, !jobStatus.getJob().isPeriodic())) {
if (DEBUG) {
Slog.d(TAG, "Could not find job to remove. Was job removed while executing?");
}
// We still want to check for jobs to execute, because this job may have
// scheduled a new job under the same job id, and now we can run it.
// 发送 MSG_CHECK_JOB_GREEDY,继续执行其他的 job,然后直接 return
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
return;
}
// Note: there is a small window of time in here where, when rescheduling a job,
// we will stop monitoring its content providers. This should be fixed by stopping
// the old job after scheduling the new one, but since we have no lock held here
// that may cause ordering problems if the app removes jobStatus while in here.
if (needsReschedule) {
JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
startTrackingJob(rescheduled, jobStatus);
} else if (jobStatus.getJob().isPeriodic()) {
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
startTrackingJob(rescheduledPeriodic, jobStatus);
}
reportActive();
mHandler.obtainMessage(MSG_CHECK_JOB_GREEDY).sendToTarget();
}
如果是true那么needsReschedule的也是true执行就是这段代码
      if (needsReschedule) {
JobStatus rescheduled = getRescheduleJobForFailure(jobStatus);
startTrackingJob(rescheduled, jobStatus);
}

这段点主要调用getRescheduleJobForFailure

    private JobStatus getRescheduleJobForFailure(JobStatus failureToReschedule) {
final long elapsedNowMillis = SystemClock.elapsedRealtime();
final JobInfo job = failureToReschedule.getJob(); final long initialBackoffMillis = job.getInitialBackoffMillis();//获取setBackoffCriteria设置的值,如果没有设置默认是30秒
final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
long delayMillis; switch (job.getBackoffPolicy()) {//是线性还是指数级别策略
case JobInfo.BACKOFF_POLICY_LINEAR:
delayMillis = initialBackoffMillis * backoffAttempts;//随着失败的次数越多这个值也越大
break;
default:
if (DEBUG) {
Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
}
case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
delayMillis =
(long) Math.scalb(initialBackoffMillis, backoffAttempts - 1);
break;
}
//getNumFailures值越大这个值也越大间隔时间会越来越长
delayMillis =
Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);//和5小时比较
JobStatus newJob = new JobStatus(failureToReschedule, elapsedNowMillis + delayMillis,
JobStatus.NO_LATEST_RUNTIME, backoffAttempts);//构建新的JobStatu 设置下次时间 设置backoff次数
for (int ic=0; ic<mControllers.size(); ic++) {
StateController controller = mControllers.get(ic);
controller.rescheduleForFailure(newJob, failureToReschedule);
}
return newJob;
}
看完这段代码可以回答
2.setBackoffCriteria(youtime, JobInfo.BACKOFF_POLICY_LINEAR)这个是有什么作用,如果不设置会怎么样?
这个代码可以看出如果不想默认的时间是30秒,默认指数DEFAULT_BACKOFF_POLICY = BACKOFF_POLICY_EXPONENTIAL
就必须通过setBackoffCriteria()来设置时间 和线性或者指数增长策略

如果是false 那么needsReschedule的也是false 执行就是这段代码
这段如果设置了setPeriodic()被调用那么isPeriodic()是true则下面代码被执行

     else if (jobStatus.getJob().isPeriodic()) {
JobStatus rescheduledPeriodic = getRescheduleJobForPeriodic(jobStatus);
startTrackingJob(rescheduledPeriodic, jobStatus);
}

这段代码主要调用getRescheduleJobForPeriodic方法

    private JobStatus getRescheduleJobForPeriodic(JobStatus periodicToReschedule) {
final long elapsedNow = SystemClock.elapsedRealtime();
// Compute how much of the period is remaining.
long runEarly = 0L; // If this periodic was rescheduled it won't have a deadline.
if (periodicToReschedule.hasDeadlineConstraint()) {
runEarly = Math.max(periodicToReschedule.getLatestRunTimeElapsed() - elapsedNow, 0L);
}
long flex = periodicToReschedule.getJob().getFlexMillis();//最小15分钟
long period = periodicToReschedule.getJob().getIntervalMillis();//最小15分钟
long newLatestRuntimeElapsed = elapsedNow + runEarly + period;
long newEarliestRunTimeElapsed = newLatestRuntimeElapsed - flex; return new JobStatus(periodicToReschedule, newEarliestRunTimeElapsed,
newLatestRuntimeElapsed, 0 /* backoffAttempt */);
}
//...
}

4.如果想重复执行怎么操作?

1.设置jobFinished((JobParameters) msg.obj, true);设置true

         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
jobFinished((JobParameters) msg.obj, true);
} else {
jobFinished((JobParameters) msg.obj, false);
}

2.在jobFinished在jobFinished之前重新调用startJobScheduler

以下是android7.0怎么设置startJobScheduler执行的

 public void startJobScheduler() {
if (DEBUG) {
Log.i(TAG, "startJobScheduler");
}
int id = JOB_ID;
if (DEBUG) {
Log.i(TAG, "开启AstJobService id=" + id);
}
mJobScheduler.cancel(id);
JobInfo.Builder builder = new JobInfo.Builder(id, new ComponentName(mContext, AstJobService.class));
if (Build.VERSION.SDK_INT >= 24) {
builder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS); //执行的最小延迟时间
builder.setOverrideDeadline(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS); //执行的最长延时时间
builder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS);
builder.setBackoffCriteria(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS, JobInfo.BACKOFF_POLICY_LINEAR);//线性重试方案
} else {
builder.setPeriodic(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS);
}
builder.setPersisted(true); // 设置设备重启时,执行该任务
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
builder.setRequiresCharging(true); // 当插入充电器,执行该任务
JobInfo info = builder.build();
mJobScheduler.schedule(info); //开始定时执行该系统任务
}

JobService 7.0 定时任务不生效的更多相关文章

  1. Linux 定时任务不生效的问题

    Linux 中定时任务不生效的问题屡见不鲜, 本质原因是: 登录式 shell & 非登录式 shell. 登录式 shell & 非登录式 shell 登录式 shell 有: su ...

  2. ECSTORE2.0 定时任务配置

    今天在配置ecstore2.0的定时任务时候,发现ECOS后台每30秒通过JS调用 http://localhost/ecstore-bugfix/index.php/shopadmin/index. ...

  3. jenkins定时任务未生效解决

    近期在配置jenkins定时任务时,发现未生效,并没有按时触发任务 解决思路: 1.先查看下我们的定时任务有没有选择正确,如下说明: Poll SCM:定时检查源码变更,如果有更新就checkout最 ...

  4. 转:Selenium2.0 click()不生效的解决办法

    除了http://573301735.com/?p=5126讲的,昨天又发现一个让我1个小时生不如死的问题,就是使用两个不同的配置文件来初始化driver,findelement方法获取到的坐标居然不 ...

  5. SpringBoot2.0+ DataSourceInitializer不生效的问题

    1.在url后声明时区 2.更换mysql6.0+的驱动 3.配置属性initialization-mode 为 always 我就是这样解决问题的,如果没解决的话,请在留言处指出错误.谢谢

  6. Servlet4.0 注解不生效解决

    当我们创建好一个4.0的servlet 生成的注解大概是这样  name=xxxxx 默认的是不具有效果的 你可以有两种方式 1.去掉属性name,3.0就是这样子的 2.非要有name属性 请加上u ...

  7. Kerberos kinit crontab定时任务不生效的问题解决

    问题 有这样一个定时任务 1 */12 * * * kinit -kt xxxxxx.keytab principle 这样写每天 12点,执行一次. 但是服务器的应用程序报错: GSS initia ...

  8. Quartz3.0定时任务学习之异步调度器

    前言 Quartz3与Quartz2的主要区别有两点: 1,Quartz3将它的资源类库拆的更细了,比如,想使用Quartz3开发,最少要引用Quartz,Quartz.Jobs,Quartz.Plu ...

  9. CSS中margin: 0 auto;样式没有生效

    问题:有两个元素: A, B.两则是嵌套关系,A是B的父节点.A和B都是块元素.当在A上设置:margin: 0 auto的时候,B并没有在页面中居中. margin: 0 auto 为什么没有生效? ...

随机推荐

  1. python-ASCII与Unicode

    # Auther: Aaron Fan'''ASCII:不支持中文,1个英文占1个字节Unicode(万国码,支持所有国家的文字显示):支持中文,但是每个英文和中文都占2个字节UTF-8(是一种针对U ...

  2. java全栈day11----构造方法 综合案例

    构造方法 在开发中经常需要在创建对象的同时明确对象的属性值,比如员工入职公司就要明确他的姓名.年龄等属性信息. 那么,创建对象就要明确属性值,那怎么解决呢?也就是在创建对象的时候就要做的事情,当使用n ...

  3. C# 写 LeetCode easy #14 Longest Common Prefix

    14.Longest Common Prefix Write a function to find the longest common prefix string amongst an array ...

  4. RedHat6安装git

    通过yum安装git : 一. 先配置yum: 把redhat系统镜像加载到电脑光驱中(无光驱可用u盘),然后把该镜像配置到环境变量中 文件名不限 在此新建的RHEL_6文件中添加如下内容 其中bas ...

  5. P2387 [NOI2014]魔法森林 LCT维护最小生成树

    \(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...

  6. 当我们谈论CloudTable时究竟在谈论什么?

    表格存储服务(CloudTable Service,简称CloudTable)是基于Apache HBase提供的分布式.可伸缩.全托管的毫秒级NoSQL数据存储服务.它提供了毫秒级的随机读写能力,适 ...

  7. opencv第三课,图像滤波

    1.介绍 OpenCV图像处理技术中比较热门的图像滤波操作主要被分为了两大类:线性邻域滤波和非线性滤波.线性邻域滤波常见的有“方框滤波“,”均值滤波“和”高斯滤波“三种,二常见的非线性滤波主要是中值滤 ...

  8. VS2010 简单ATL COM开发

    http://blog.csdn.net/wangwenjing90/article/details/8771934#reply http://blog.csdn.net/wangwenjing90/ ...

  9. vue项目中使用了vw适配方案,引入第三方ui框架mint-ui时,适配问题解决

    问题分析: 一般第三方ui框架用的都是不同的适配方式,如果我们使用了vw适配,那么在使用mint-ui框架时,就会发现px单位会被转换成vw,从而导致样式变小的问题,如图 解决方案 网上看到了很多种解 ...

  10. Gson的fromJson()方法

    Gson提供了fromJson()方法来实现从Json相关对象到Java实体的方法. 在日常应用中,我们一般都会碰到两种情况,转成单一实体对象和转换成对象列表或者其他结构. 先来看第一种: 比如jso ...