7 changed files with 433 additions and 86 deletions
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
package cc.niushuai.dididone.ui.base; |
||||
|
||||
public interface InitAndSetListener { |
||||
|
||||
/** |
||||
* 初始化数据 |
||||
*/ |
||||
void init(); |
||||
|
||||
/** |
||||
* 控件添加监听器 |
||||
*/ |
||||
void setListeners(); |
||||
} |
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
package cc.niushuai.dididone.ui.setting.icon.recycle; |
||||
|
||||
import android.content.Context; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.ImageView; |
||||
import android.widget.TextView; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
import androidx.recyclerview.widget.RecyclerView; |
||||
|
||||
import com.mikepenz.iconics.IconicsDrawable; |
||||
import com.mikepenz.iconics.typeface.IIcon; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import cc.niushuai.dididone.MainActivity; |
||||
import cc.niushuai.dididone.R; |
||||
import cc.niushuai.dididone.biz.entity.SavedIcon; |
||||
|
||||
public class IconRecycleAdapter extends RecyclerView.Adapter<IconRecycleAdapter.IconRecycleViewHolder> { |
||||
|
||||
public static final Map<String, List<SavedIcon>> ICON_MAP = new HashMap<>(); |
||||
private List<SavedIcon> savedIconList; |
||||
|
||||
private Context context; |
||||
|
||||
public IconRecycleAdapter(Context context, Class<? extends IIcon> iconClass) { |
||||
this.context = context; |
||||
this.savedIconList = ICON_MAP.get(getIconClassName(iconClass)); |
||||
} |
||||
|
||||
/** |
||||
* @param parent The ViewGroup into which the new View will be added after it is bound to |
||||
* an adapter position. |
||||
* @param viewType The view type of the new View. |
||||
* @return |
||||
*/ |
||||
@NonNull |
||||
@Override |
||||
public IconRecycleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
||||
View view = View.inflate(context, R.layout.icon_grid_item, null); |
||||
return new IconRecycleViewHolder(view); |
||||
} |
||||
|
||||
/** |
||||
* @param holder The ViewHolder which should be updated to represent the contents of the |
||||
* item at the given position in the data set. |
||||
* @param position The position of the item within the adapter's data set. |
||||
*/ |
||||
@Override |
||||
public void onBindViewHolder(@NonNull IconRecycleViewHolder holder, int position) { |
||||
SavedIcon icon = savedIconList.get(position); |
||||
holder.iconView.setImageDrawable(new IconicsDrawable(context) |
||||
.icon(icon.getIcon()) |
||||
.color(Integer.parseInt(icon.getColor())) |
||||
.sizeDp(icon.getSize())); |
||||
|
||||
holder.txtView.setText(icon.getIcon()); |
||||
} |
||||
|
||||
/** |
||||
* @return |
||||
*/ |
||||
@Override |
||||
public int getItemCount() { |
||||
return savedIconList.size(); |
||||
} |
||||
|
||||
public static String getIconClassName(Class<? extends IIcon> iconClass) { |
||||
String iconClassName = iconClass.getName(); |
||||
return iconClassName.substring(iconClassName.lastIndexOf(".") + 1, iconClassName.indexOf("$")); |
||||
|
||||
} |
||||
public static class IconRecycleViewHolder extends RecyclerView.ViewHolder { |
||||
|
||||
protected ImageView iconView; |
||||
protected TextView txtView; |
||||
|
||||
public IconRecycleViewHolder(@NonNull View itemView) { |
||||
super(itemView); |
||||
iconView = itemView.findViewById(R.id.icons_grid_item); |
||||
txtView = itemView.findViewById(R.id.icons_grid_txt); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,199 @@
@@ -0,0 +1,199 @@
|
||||
/* |
||||
* 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.Random; |
||||
import java.util.concurrent.atomic.AtomicLong; |
||||
|
||||
/** |
||||
* @author funkye |
||||
* @author selfishlover |
||||
*/ |
||||
public class Snowflake { |
||||
private static final Snowflake snowflake = new Snowflake(0L); |
||||
|
||||
public static long next_id() { |
||||
return 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 = 10; |
||||
|
||||
/** |
||||
* The number of bits occupied by timestamp |
||||
*/ |
||||
private final int timestampBits = 41; |
||||
|
||||
/** |
||||
* 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 Snowflake(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); |
||||
} |
||||
} |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
android:padding="10dp"> |
||||
|
||||
<ImageView |
||||
android:id="@+id/icons_grid_item" |
||||
android:layout_width="50dp" |
||||
android:layout_height="50dp" |
||||
android:layout_centerVertical="true" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/icons_grid_txt" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_toRightOf="@id/icons_grid_item" |
||||
android:layout_centerVertical="true" |
||||
android:layout_marginLeft="20dp" |
||||
android:textSize="14dp" /> |
||||
|
||||
</RelativeLayout> |
Loading…
Reference in new issue