7 changed files with 433 additions and 86 deletions
@ -0,0 +1,14 @@ |
|||||||
|
package cc.niushuai.dididone.ui.base; |
||||||
|
|
||||||
|
public interface InitAndSetListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* 初始化数据 |
||||||
|
*/ |
||||||
|
void init(); |
||||||
|
|
||||||
|
/** |
||||||
|
* 控件添加监听器 |
||||||
|
*/ |
||||||
|
void setListeners(); |
||||||
|
} |
@ -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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
<?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