Browse Source

feat: 🆔 id fix

master
niushuai233 1 year ago
parent
commit
953fba7c94
  1. 16
      app/src/main/java/cc/niushuai/dididone/ui/calendar/CalendarFragment.java
  2. 216
      app/src/main/java/cc/niushuai/dididone/util/IntSnowflake.java

16
app/src/main/java/cc/niushuai/dididone/ui/calendar/CalendarFragment.java

@ -19,7 +19,6 @@ import com.mikepenz.fontawesome_typeface_library.FontAwesome; @@ -19,7 +19,6 @@ import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.iconics.view.IconicsImageView;
import com.necer.calendar.BaseCalendar;
import com.necer.entity.CalendarDate;
import com.necer.entity.Lunar;
import com.necer.enumeration.DateChangeBehavior;
import com.necer.listener.OnCalendarChangedListener;
@ -31,7 +30,9 @@ import org.joda.time.LocalDate; @@ -31,7 +30,9 @@ import org.joda.time.LocalDate;
import java.util.List;
import cc.niushuai.dididone.R;
import cc.niushuai.dididone.biz.entity.Record;
import cc.niushuai.dididone.databinding.FragmentCalendarBinding;
import cc.niushuai.dididone.util.IntSnowflake;
import cn.hutool.core.date.DateUtil;
public class CalendarFragment extends Fragment {
@ -87,7 +88,7 @@ public class CalendarFragment extends Fragment { @@ -87,7 +88,7 @@ public class CalendarFragment extends Fragment {
String lunarDate = lunar.chineseEra + "年" + lunar.lunarMonthStr + lunar.lunarDayStr;
// 当前选中的日期放到最上面
add2Top(localDate.toString(), lunarDate);
add2Top(new Record(), localDate.toString(), lunarDate);
// 重置上次选中日期
lastDate = localDate.toString();
@ -96,24 +97,23 @@ public class CalendarFragment extends Fragment { @@ -96,24 +97,23 @@ public class CalendarFragment extends Fragment {
}
private void add2Top(String localDate, String lunarDate) {
private void add2Top(Record record, String localDate, String lunarDate) {
// 外层layout 白色背景 存在边距
RelativeLayout itemLayout = new RelativeLayout(getContext());
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 175);
layoutParams.setMargins(25, 20, 25, 15);
itemLayout.setId(13);
itemLayout.setId(IntSnowflake.next_id());
itemLayout.setLayoutParams(layoutParams);
itemLayout.setPadding(15, 15, 15, 5);
itemLayout.setBackgroundResource(R.drawable.bg_miui10);
// itemLayout.setOrientation(LinearLayout.VERTICAL);
// projectIcon layout
RelativeLayout.LayoutParams iconLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
iconLayout.setMargins(10, 5, 0, 0);
IconicsImageView iconView = new IconicsImageView(getContext());
iconView.setId(111);
iconView.setId(IntSnowflake.next_id());
iconView.setLayoutParams(iconLayout);
IconicsDrawable icon = new IconicsDrawable(getContext());
icon.icon(FontAwesome.Icon.faw_swimmer).color(Color.BLUE).sizeDp(50);
@ -124,14 +124,14 @@ public class CalendarFragment extends Fragment { @@ -124,14 +124,14 @@ public class CalendarFragment extends Fragment {
RelativeLayout.LayoutParams projectLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
projectLayout.setMargins(20, 5, 0, 0);
projectLayout.addRule(RelativeLayout.RIGHT_OF, 111);
TextView projectTextView = this.getTextView(222, localDate, projectLayout, R.color._333333, 16, Gravity.CENTER_VERTICAL);
TextView projectTextView = this.getTextView(IntSnowflake.next_id(), localDate, projectLayout, R.color._333333, 16, Gravity.CENTER_VERTICAL);
itemLayout.addView(projectTextView);
RelativeLayout.LayoutParams dateLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
dateLayout.setMargins(20, 25, 0, 0);
dateLayout.addRule(RelativeLayout.RIGHT_OF, 111);
dateLayout.addRule(RelativeLayout.BELOW, 222);
TextView dateTextView = this.getTextView(333, DateUtil.now(), dateLayout, R.color._666666, 12, Gravity.TOP);
TextView dateTextView = this.getTextView(IntSnowflake.next_id(), DateUtil.now(), dateLayout, R.color._666666, 12, Gravity.TOP);
itemLayout.addView(dateTextView);
binding.cCalendarCheckInList.removeAllViews();

216
app/src/main/java/cc/niushuai/dididone/util/IntSnowflake.java

@ -0,0 +1,216 @@ @@ -0,0 +1,216 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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.
*/
package cc.niushuai.dididone.util;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
* @author funkye
* @author selfishlover
*/
public class IntSnowflake {
private static final IntSnowflake snowflake = new IntSnowflake(0L);
public static int next_id() {
return (int) snowflake.nextId();
}
public static String next_id_str() {
return snowflake.nextId() + "";
}
/**
* Start time cut (2020-05-03)
*/
private final long twepoch = 1588435200000L;
/**
* The number of bits occupied by workerId
*/
private final int workerIdBits = 8;
/**
* The number of bits occupied by timestamp
*/
private final int timestampBits = 12;
/**
* The number of bits occupied by sequence
*/
private final int sequenceBits = 12;
/**
* Maximum supported machine id, the result is 1023
*/
private final int maxWorkerId = ~(-1 << workerIdBits);
/**
* mask that help to extract timestamp and sequence from a long
*/
private final long timestampAndSequenceMask = ~(-1L << (timestampBits + sequenceBits));
/**
* business meaning: machine ID (0 ~ 1023)
* actual layout in memory:
* highest 1 bit: 0
* middle 10 bit: workerId
* lowest 53 bit: all 0
*/
private long workerId;
/**
* timestamp and sequence mix in one Long
* highest 11 bit: not used
* middle 41 bit: timestamp
* lowest 12 bit: sequence
*/
private AtomicLong timestampAndSequence;
/**
* instantiate an IdWorker using given workerId
*
* @param workerId if null, then will auto assign one
*/
public IntSnowflake(Long workerId) {
initTimestampAndSequence();
initWorkerId(workerId);
}
/**
* init first timestamp and sequence immediately
*/
protected void initTimestampAndSequence() {
long timestamp = getNewestTimestamp();
long timestampWithSequence = timestamp << sequenceBits;
this.timestampAndSequence = new AtomicLong(timestampWithSequence);
}
/**
* init workerId
*
* @param workerId if null, then auto generate one
*/
protected void initWorkerId(Long workerId) {
if (workerId == null) {
workerId = generateWorkerId();
}
if (workerId > maxWorkerId || workerId < 0) {
String message = String.format("worker Id can't be greater than %d or less than 0", maxWorkerId);
throw new IllegalArgumentException(message);
}
this.workerId = workerId << (timestampBits + sequenceBits);
}
/**
* get next UUID(base on snowflake algorithm), which look like:
* highest 1 bit: always 0
* next 10 bit: workerId
* next 41 bit: timestamp
* lowest 12 bit: sequence
*
* @return UUID
*/
public long nextId() {
waitIfNecessary();
long next = timestampAndSequence.incrementAndGet();
long timestampWithSequence = next & timestampAndSequenceMask;
return workerId | timestampWithSequence;
}
/**
* block current thread if the QPS of acquiring UUID is too high
* that current sequence space is exhausted
*/
private void waitIfNecessary() {
long currentWithSequence = timestampAndSequence.get();
long current = currentWithSequence >>> sequenceBits;
long newest = getNewestTimestamp();
if (current >= newest) {
try {
Thread.sleep(5);
} catch (InterruptedException ignore) {
// don't care
}
}
}
/**
* get newest timestamp relative to twepoch
*/
private long getNewestTimestamp() {
return System.currentTimeMillis() - twepoch;
}
/**
* auto generate workerId, try using mac first, if failed, then randomly generate one
*
* @return workerId
*/
private long generateWorkerId() {
try {
return generateWorkerIdBaseOnMac();
} catch (Exception e) {
return generateRandomWorkerId();
}
}
/**
* use lowest 10 bit of available MAC as workerId
*
* @return workerId
* @throws Exception when there is no available mac found
*/
private long generateWorkerIdBaseOnMac() throws Exception {
Enumeration<NetworkInterface> all = NetworkInterface.getNetworkInterfaces();
while (all.hasMoreElements()) {
NetworkInterface networkInterface = all.nextElement();
boolean isLoopback = networkInterface.isLoopback();
boolean isVirtual = networkInterface.isVirtual();
if (isLoopback || isVirtual) {
continue;
}
byte[] mac = networkInterface.getHardwareAddress();
return ((mac[4] & 0B11) << 8) | (mac[5] & 0xFF);
}
throw new RuntimeException("no available mac found");
}
/**
* randomly generate one as workerId
*
* @return workerId
*/
private long generateRandomWorkerId() {
return new Random().nextInt(maxWorkerId + 1);
}
public static void main(String[] args) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < 100000000; i++) {
long id = next_id();
map.put((int) id, (map.getOrDefault(id, 0) + 1));
}
List<Integer> collect = map.values().stream().filter(item -> item > 0).collect(Collectors.toList());
System.out.println(map.size());
System.out.println(collect);
}
}
Loading…
Cancel
Save