gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Elasticsearch
    • Kafka
    • Flink
    • 数据仓库
    • 数据挖掘
    • flume
    • Kafka
    • Hive
    • shardingsphere
    • solr
  • 开发博客
    • Android
    • php
    • python
    • 运维
    • 技术架构
    • 数据库
  • 程序员网赚
  • bug清单

分类归档Android

精品微信小程序开发门户,代码全部亲测可用

  • 首页   /  
  • 分类归档: "Android"
Android 2月 11,2021

Android自定义采颜色对话框

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;

@SuppressLint({ “DrawAllocation” })
public class ColorPickerDialog extends Dialog {
private int mInitialColor;
private OnColorChangedListener mListener;

public ColorPickerDialog(Context paramContext,
        OnColorChangedListener paramOnColorChangedListener, int paramInt) {
    super(paramContext);
    this.mListener = paramOnColorChangedListener;
    this.mInitialColor = paramInt;
}

protected void onCreate(Bundle paramBundle) {
    super.onCreate(paramBundle);
    mListener = new OnColorChangedListener() {
        public void colorChanged(int paramAnonymousInt) {
            ColorPickerDialog.this.mListener
                    .colorChanged(paramAnonymousInt);
            ColorPickerDialog.this.dismiss();
        }
    };
    setContentView(new ColorPickerView(getContext(), mListener,
            this.mInitialColor));
    setTitle("Pick a Color");
}

private static class ColorPickerView extends View {
    private static final int CENTER_RADIUS = 32;
    private static int CENTER_X = 120;
    private static int CENTER_Y = 120;
    private static final float PI = 3.1415925F;
    private Paint mCenterPaint;
    private final int[] mColors;
    private boolean mHighlightCenter;
    private ColorPickerDialog.OnColorChangedListener mListener;
    private Paint mPaint;
    private boolean mTrackingCenter;

    ColorPickerView(
            Context paramContext,
            ColorPickerDialog.OnColorChangedListener paramOnColorChangedListener,
            int paramInt) {
        super(paramContext);
        this.mListener = paramOnColorChangedListener;
        this.mColors = new int[] { -65536, -65281, -16776961, -16711681,
                -16711936, 65280, -65536 };
        SweepGradient gradient = new SweepGradient(0.0F, 0.0F,
                this.mColors, null);
        this.mPaint = new Paint(1);
        this.mPaint.setShader(gradient);
        this.mPaint.setStyle(Paint.Style.STROKE);
        this.mPaint.setStrokeWidth(32.0F);
        this.mCenterPaint = new Paint(1);
        this.mCenterPaint.setColor(paramInt);
        this.mCenterPaint.setStrokeWidth(5.0F);
    }

    private int ave(int paramInt1, int paramInt2, float paramFloat) {
        return Math.round((paramInt2 - paramInt1) * paramFloat) + paramInt1;
    }

    private int interpColor(int[] paramArrayOfInt, float paramFloat) {
        if (paramFloat <= 0.0F) {
            return paramArrayOfInt[0];
        }
        if (paramFloat >= 1.0F) {
            return paramArrayOfInt[(paramArrayOfInt.length - 1)];
        }
        paramFloat *= (paramArrayOfInt.length - 1);
        int j = (int) paramFloat;
        paramFloat -= j;
        int i = paramArrayOfInt[j];
        j = paramArrayOfInt[(j + 1)];
        return Color.argb(ave(Color.alpha(i), Color.alpha(j), paramFloat),
                ave(Color.red(i), Color.red(j), paramFloat),
                ave(Color.green(i), Color.green(j), paramFloat),
                ave(Color.blue(i), Color.blue(j), paramFloat));
    }

    protected void onDraw(Canvas paramCanvas) {
        float f = CENTER_X - this.mPaint.getStrokeWidth() * 0.5F;
        paramCanvas.translate(CENTER_X, CENTER_X);
        paramCanvas.drawOval(new RectF(-f, -f, f, f), this.mPaint);
        paramCanvas.drawCircle(0.0F, 0.0F, 32.0F, this.mCenterPaint);
        int i;
        if (this.mTrackingCenter) {
            i = this.mCenterPaint.getColor();
            this.mCenterPaint.setStyle(Paint.Style.STROKE);
            if (this.mHighlightCenter) {
                this.mCenterPaint.setAlpha(255);
            } else {
                this.mCenterPaint.setAlpha(128);
            }
            paramCanvas.drawCircle(0.0F, 0.0F,
                    this.mCenterPaint.getStrokeWidth() + 32.0F,
                    this.mCenterPaint);
            this.mCenterPaint.setStyle(Paint.Style.FILL);
            this.mCenterPaint.setColor(i);

        }
    }

    protected void onMeasure(int paramInt1, int paramInt2) {
        setMeasuredDimension(CENTER_X * 2, CENTER_X * 2);
    }

    public boolean onTouchEvent(MotionEvent paramMotionEvent) {
        float f1 = paramMotionEvent.getX() - CENTER_X;
        float f2 = paramMotionEvent.getY() - CENTER_Y;
        boolean bool;
        if (Math.sqrt(f1 * f1 + f2 * f2) <= 32.0D) {
            bool = true;
        } else {
            bool = false;
        }
        switch (paramMotionEvent.getAction()) {
        case 0:
            return true;

        case 1:

            if (mTrackingCenter) {
                if (mTrackingCenter != bool) {
                    this.mHighlightCenter = bool;
                    invalidate();
                    return true;
                } else {
                    f2 = (float) Math.atan2(f2, f1) / 6.283185F;
                    f1 = f2;
                    if (f2 < 0.0F) {
                        f1 = f2 + 1.0F;
                    }
                    this.mCenterPaint
                            .setColor(interpColor(this.mColors, f1));
                    invalidate();
                    return true;
                }
            }
            break;

        case 2:

            if (mTrackingCenter) {
                if (bool) {
                    this.mListener.colorChanged(this.mCenterPaint
                            .getColor());
                }
                this.mTrackingCenter = false;
                invalidate();
                return true;
            }
        }

        return false;
    }
}

public static abstract interface OnColorChangedListener {
    public abstract void colorChanged(int paramInt);
}

}

作者 east
Android 2月 11,2021

Android手电筒后台Service

功能是后台service控制手电的打开和关闭。

public class ToggleFlashService extends Service {
	final String SMS_RECEIVED_STRING = "android.provider.Telephony.SMS_RECEIVED";
	AudioManager audioManager;
	int callState;
	int flashDuration;
	int flashInterval;
	boolean isCameraInUse = false;
	boolean isCameraOpen = false;
	boolean isFlashOn = false;
	Camera.Parameters params;
	Intent serviceIntent;
	TelephonyManager telephonyManager;
	Timer timer;
	TimerTask timerTask;

	public boolean isCameraInUse() {
		try {
			if ((ToggleFlashSettings.camera == null) && (!this.isCameraOpen)) {
				ToggleFlashSettings.camera = Camera.open();
				this.params = ToggleFlashSettings.camera.getParameters();
				this.isCameraOpen = true;
				return false;
			}			
		} catch (Exception localException) {
		}
		return true;
	}

	public void messageReceived() {
	}

	public IBinder onBind(Intent paramIntent) {
		return null;
	}

	public void onCreate() {
		this.telephonyManager = ((TelephonyManager) getSystemService("phone"));
		this.audioManager = ((AudioManager) getSystemService("audio"));
		this.callState = this.telephonyManager.getCallState();
		this.flashDuration = ToggleFlashPrefs
				.getCallFlashInterval(getApplicationContext());
		this.flashInterval = ToggleFlashPrefs
				.getCallFlashDuration(getApplicationContext());
		super.onCreate();
	}


	public void onDestroy() {
		Log.e("Toggle", "ToggleFlash Destroy");
		try {
			if (this.timer != null) {
				this.timer.cancel();
				this.timer = null;
			}
			if ((this.isFlashOn) && (ToggleFlashSettings.camera != null)) {
				this.isFlashOn = false;
				this.isCameraOpen = false;
				this.params = ToggleFlashSettings.camera.getParameters();
				List localList = this.params.getSupportedFlashModes();
				if ((localList.contains("torch"))
						|| (localList.contains("off"))
						|| (localList.contains("on"))) {
					this.params.setFlashMode("off");
					ToggleFlashSettings.camera.setParameters(this.params);
				}
				ToggleFlashSettings.camera.release();
				ToggleFlashSettings.camera = null;
			}			
		} catch (Exception localException) {
			if (ToggleFlashSettings.camera != null) {
				ToggleFlashSettings.camera.release();
				ToggleFlashSettings.camera = null;
			}
			localException.printStackTrace();
		}
	}


	public int onStartCommand(Intent paramIntent, int paramInt1, int paramInt2) {
		if (ToggleFlashSettings.camera != null) {
			ToggleFlashSettings.camera.release();
			ToggleFlashSettings.camera = null;
		}
		this.serviceIntent = paramIntent;
		this.telephonyManager.listen(new PhoneStateListener() {
			public void onCallStateChanged(int paramAnonymousInt,
					String paramAnonymousString) {
				switch (paramAnonymousInt) {
				default:
					ToggleFlashService.this.callState = 0;
					break;
				case 1:
					ToggleFlashService.this.callState = 1;
					break;
				case 2:
					ToggleFlashService.this.callState = 2;
					break;
				}

			}
		}, 32);
		this.timer = new Timer();
		this.timerTask = new TimerTask() {
			public void run() {
				ToggleFlashService.this.toggleFlash();
			}
		};
		if (this.flashDuration == 0) {
			this.timer.schedule(this.timerTask, this.flashInterval, 50L);
		} else {
			this.timer.schedule(this.timerTask, this.flashInterval,
					this.flashDuration);
		}
		return super.onStartCommand(paramIntent, paramInt1, paramInt2);
	}


	public boolean stopService(Intent paramIntent) {
		try {
			if (this.timer != null) {
				this.timer.cancel();
				this.timer = null;
			}
			if ((this.isFlashOn) && (ToggleFlashSettings.camera != null)) {
				this.isFlashOn = false;
				this.isCameraOpen = false;
				this.params = ToggleFlashSettings.camera.getParameters();
				List localList = this.params.getSupportedFlashModes();
				if ((localList.contains("torch"))
						|| (localList.contains("off"))
						|| (localList.contains("on"))) {
					this.params.setFlashMode("off");
					ToggleFlashSettings.camera.setParameters(this.params);
				}
				ToggleFlashSettings.camera.release();
				ToggleFlashSettings.camera = null;
			}
			this.isCameraOpen = false;
			this.isFlashOn = false;
			if (ToggleFlashSettings.camera != null) {
				ToggleFlashSettings.camera.release();
				ToggleFlashSettings.camera = null;
			}
			if (this.serviceIntent != null) {
				boolean bool = super.stopService(this.serviceIntent);
				return bool;
			}
		} catch (Exception localException) {
			localException.printStackTrace();
			if (ToggleFlashSettings.camera != null) {
				ToggleFlashSettings.camera.release();
				ToggleFlashSettings.camera = null;
			}
			ToggleFlashSettings.camera = null;
		}
		return super.stopService(paramIntent);
	}

	
	public void toggleFlash() {		
		try {
			this.isCameraInUse = isCameraInUse();
			if (this.isCameraInUse) {
				stopService(this.serviceIntent);
				Log.e("ToggleFlashServer", "is isCameraInUse ");     
				return;
			}
			if (this.callState != 1) {
				Log.e("ToggleFlashServer", "callState is 1 ");     
				return;
			}
			 List localList = this.params.getSupportedFlashModes();
			if (!this.isFlashOn) {
				if ((localList.contains("torch"))
						|| (localList.contains("off"))
						|| (localList.contains("on"))) {
					Log.e("ToggleFlashServer", "start torch.... ");    
					this.params.setFlashMode("torch");
					if (ToggleFlashSettings.camera != null) {
						ToggleFlashSettings.camera.setParameters(this.params);
						ToggleFlashSettings.camera.startPreview();
					}
				}
				this.isFlashOn = true;
				return;
			}
			
			if ((localList.contains("torch")) || (localList.contains("off"))
					|| (localList.contains("on"))) {
				this.params.setFlashMode("off");
				if (ToggleFlashSettings.camera != null) {
					ToggleFlashSettings.camera.setParameters(this.params);
					ToggleFlashSettings.camera.stopPreview();
				}
			}
			this.isFlashOn = false;
			stopService(this.serviceIntent);
			
		} catch (Exception localException) {
			localException.printStackTrace();

		}
		
	}
}

public class ToggleFlashPrefs {
	public static final String CALL_FLASH_DURATION = "call_flash_duration";
	public static final String CALL_FLASH_INTERVAL = "call_flash_interval";
	public static final String MSG_FLASH_DURATION = "msg_flash_duration";
	public static final String MSG_FLASH_INTERVAL = "msg_flash_interval";
	public static final String SERVICE_STARTED = "service_started";
	public static final String SET_ALARM_ENABLE = "set_alarm_enable";
	public static final String SET_CALL_ENABLE = "set_call_enable";
	public static final String SET_MESSAGE_ENABLE = "set_message_enable";
	public static final String SET_NOTIFICATION_ENABLE = "set_notification_enable";

	public static boolean getAlarmEnable(Context paramContext) {
		return getSharedPreferences(paramContext).getBoolean(
				"set_alarm_enable", false);
	}

	public static boolean getCallEnable(Context paramContext) {
		return getSharedPreferences(paramContext).getBoolean("set_call_enable",
				true);
	}

	public static int getCallFlashDuration(Context paramContext) {
		return getSharedPreferences(paramContext).getInt("call_flash_duration",
				250);
	}

	public static int getCallFlashInterval(Context paramContext) {
		return getSharedPreferences(paramContext).getInt("call_flash_interval",
				0);
	}

	public static int getMSGFlashDuration(Context paramContext) {
		return getSharedPreferences(paramContext).getInt("msg_flash_duration",
				250);
	}

	public static int getMSGFlashInterval(Context paramContext) {
		return getSharedPreferences(paramContext).getInt("msg_flash_interval",
				0);
	}

	public static boolean getMessageEnable(Context paramContext) {
		return getSharedPreferences(paramContext).getBoolean(
				"set_message_enable", true);
	}

	public static boolean getNotificationEnable(Context paramContext) {
		return getSharedPreferences(paramContext).getBoolean(
				"set_notification_enable", false);
	}

	public static boolean getServiceStarted(Context paramContext) {
		return getSharedPreferences(paramContext).getBoolean("service_started",
				false);
	}

	static SharedPreferences getSharedPreferences(Context paramContext) {
		return PreferenceManager.getDefaultSharedPreferences(paramContext);
	}

	public static void setAlarmEnable(Context paramContext, boolean paramBoolean) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putBoolean("set_alarm_enable", paramBoolean);
		editor.commit();
	}

	public static void setCallEnable(Context paramContext, boolean paramBoolean) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putBoolean("set_call_enable", paramBoolean);
		editor.commit();
	}

	public static void setCallFlashDuration(Context paramContext, int paramInt) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putInt("call_flash_duration", paramInt);
		editor.commit();
	}

	public static void setCallFlashInterval(Context paramContext, int paramInt) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putInt("call_flash_interval", paramInt);
		editor.commit();
	}

	public static void setMSGFlashDuration(Context paramContext, int paramInt) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putInt("msg_flash_duration", paramInt);
		editor.commit();
	}

	public static void setMSGFlashInterval(Context paramContext, int paramInt) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putInt("msg_flash_interval", paramInt);
		editor.commit();
	}

	public static void setMessageEnable(Context paramContext,
			boolean paramBoolean) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putBoolean("set_message_enable", paramBoolean);
		editor.commit();
	}

	public static void setNotificationEnable(Context paramContext,
			boolean paramBoolean) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putBoolean("set_notification_enable", paramBoolean);
		editor.commit();
	}

	public static void setServiceStarted(Context paramContext,
			boolean paramBoolean) {
		SharedPreferences.Editor editor = getSharedPreferences(paramContext)
				.edit();
		editor.putBoolean("service_started", paramBoolean);
		editor.commit();
	}
}
作者 east
Android 2月 11,2021

Android单行文本跑马灯控件

public class AutoScrollTextView extends TextView implements OnClickListener {
public final static String TAG = AutoScrollTextView.class.getSimpleName();
private int runNum = 1;// 滚动次数
private float textLength = 0f;// 文本长度
private float viewWidth = 0f;
private float step = 0f;// 文字的横坐标
private float y = 0f;// 文字的纵坐标
private float temp_view_plus_text_length = 0.0f;// 用于计算的临时变量
private float temp_view_plus_two_text_length = 0.0f;// 用于计算的临时变量
public boolean isStarting = false;// 是否开始滚动
private Paint paint = null;// 绘图样式
private Paint paint1 = null;// 绘图样式
private String text = “”;// 文本内容
private boolean isFade = true;// 是否加影子
private float layout_width = 168f;

public float getLayout_width() {
    return layout_width;
}

public void setLayout_width(float layoutWidth) {
    layout_width = layoutWidth;
}

public boolean isFade() {
    return isFade;
}

public void setFade(boolean isFade) {
    this.isFade = isFade;
}

public AutoScrollTextView(Context context) {
    super(context);
    initView();
}

public AutoScrollTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView();
}

public AutoScrollTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initView();
}

/** */
/**
 * 初始化控件
 */
private void initView() {
    setOnClickListener(this);
}

/** */
/**
 * 文本初始化,每次更改文本内容或者文本效果等之后都需要重新初始化一下
 */
public void init(WindowManager windowManager) {
    paint = getPaint();
    paint1 = new Paint();
    paint1.setColor(Color.WHITE);
    paint1.setTextSize(getTextSize());
    text = getText().toString();
    textLength = paint.measureText(text);
    viewWidth = layout_width * LogoActivity.screenHeight / 960;
    if (textLength > viewWidth * 2) {
        isStarting = true;
    }
    Log.e("    textLength      ", textLength + "         " + viewWidth);
    if (viewWidth == 0) {
        if (windowManager != null) {
            Display display = windowManager.getDefaultDisplay();
            viewWidth = display.getWidth();
        }
    }
    temp_view_plus_text_length = viewWidth + textLength;
    temp_view_plus_two_text_length = viewWidth + textLength * 2;
    step = temp_view_plus_text_length;
    y = getTextSize() + getPaddingTop();
}

@Override
public Parcelable onSaveInstanceState() {
    Parcelable superState = super.onSaveInstanceState();
    SavedState ss = new SavedState(superState);

    ss.step = step;
    ss.isStarting = isStarting;

    return ss;

}

@Override
public void onRestoreInstanceState(Parcelable state) {
    if (!(state instanceof SavedState)) {
        super.onRestoreInstanceState(state);
        return;
    }
    SavedState ss = (SavedState) state;
    super.onRestoreInstanceState(ss.getSuperState());

    step = ss.step;
    isStarting = ss.isStarting;

}

public static class SavedState extends BaseSavedState {
    public boolean isStarting = false;
    public float step = 0.0f;

    SavedState(Parcelable superState) {
        super(superState);
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        super.writeToParcel(out, flags);
        out.writeBooleanArray(new boolean[] { isStarting });
        out.writeFloat(step);
    }

    public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {

        public SavedState[] newArray(int size) {
            return new SavedState[size];
        }

        @Override
        public SavedState createFromParcel(Parcel in) {
            return new SavedState(in);
        }
    };

    private SavedState(Parcel in) {
        super(in);
        boolean[] b = null;
        in.readBooleanArray(b);
        if (b != null && b.length > 0)
            isStarting = b[0];
        step = in.readFloat();
    }
}

/** */
/**
 * 开始滚动
 */
public void startScroll() {
    isStarting = true;
    invalidate();
}

/** */
/**
 * 停止滚动
 */
public void stopScroll() {
    isStarting = false;
    runNum = 1;
    invalidate();

}

@Override
public void onDraw(Canvas canvas) {
    if (isFade)canvas.drawText(text, temp_view_plus_text_length - step, y, paint1);
    canvas.drawText(text, temp_view_plus_text_length - step, y - 1, paint);
    if (!isStarting) {
        return;
    }
    step += 1;
    if (step > temp_view_plus_two_text_length) {
        step = textLength - viewWidth;
        runNum--;

    }
    if (runNum == 0 && step == temp_view_plus_text_length) {
        isStarting = false;
    }
    invalidate();

}

@Override
public void onClick(View v) {

// if (isStarting)
// stopScroll();
// else
// startScroll();

}

}

作者 east
Android 2月 11,2021

Android游戏加载资源通用类

开发游戏,通常需要在Assets中加载图片和多语言包,下面有个封装类。

/**
 * 图片加载类.
 * 
 * @author 凉
 * 
 */
public class Assets {
	private static Map<String, Map<String, String>> drawables = new HashMap<String, Map<String, String>>();

	private static Map<String, String> raws = new HashMap<String, String>();

	/**
	 * 如果是中文,则从drawable-zh目录加载图片.如果没有,在从drawable里面加载.
	 * 
	 * @param name
	 * @return
	 */
	public static String get(String name) {
		String result = null;
		if (isLunarSetting()) {
			Map map = (Map) drawables.get("drawable-zh");
			if (map != null) {
				String str3 = get(map, name);
				MyLog.d("", ">>>>>>>>>>>path>>>cn>>drawables:" + str3
						+ "   name:" + name);
				if (str3 != null) {
					result = str3;
				} else {
					String str4 = get((Map) drawables.get("drawable"), name);
					MyLog.d("", ">>>>>>>>>>>path>>>en>1>drawables:" + str4
							+ "   name:" + name);
					if (str4 != null) {
						result = str4;
					}
				}
			} else {
				String str2 = get((Map) drawables.get("drawable"), name);
				MyLog.d("", ">>>>>>>>>>>path>>>en>2>drawables:" + str2
						+ "   name:" + name);
				if (str2 != null) {
					result = str2;
				}
			}
		} else {
			String str1 = get((Map) drawables.get("drawable"), name);
			MyLog.d("", ">>>>>>>>>>>path>>>en>3>drawables:" + str1 + "   name:"
					+ name);
			if (str1 != null) {
				result = str1;
			}
		}
		return result;
	}

	private static String get(Map<String, String> map, String name) {
		String str = null;
		if (map.get(name + ".png") != null)
			str = (String) map.get(name + ".png");
		else {
			if (map.get(name + ".jpg") != null) {
				str = (String) map.get(name + ".jpg");
			}
		}
		return str;
	}

	private static String getLanguageEnv() {
		Locale local = Locale.getDefault();
		String language = local.getLanguage();
		String country = local.getCountry().toLowerCase();
		if ("zh".equals(language)) {
			if ("cn".equals(country))
				language = "zh-CN";
			else if ("tw".equals(country)) {
				language = "zh-TW";
			}
		} else if ("pt".equals(language)) {
			if ("br".equals(country)) {
				language = "pt-BR";
			} else if ("pt".equals(country)) {
				language = "pt-PT";
			}
		}
		return language;
	}

	/**
	 * 获取.plist资源.
	 * 
	 * @param name
	 * @return
	 */
	public static String getRaw(String name) {
		return (String) raws.get(name + ".plist");
	}

	/**
	 * 把文件夹res下面的drawable和raw下面的文件路径全部缓存起来.
	 * 
	 * @param context
	 * @throws IOException
	 */
	public static void init(Context context) throws IOException {
		String[] arraystr = context.getAssets().list("res");
		int i = arraystr.length;
		for (int j = 0; j < i; j++) {
			String str1 = arraystr[j];
			String[] strings;
			HashMap drawable;
			if (str1.startsWith("drawable")) {
				strings = context.getAssets().list("res/" + str1);
				drawable = new HashMap();
				int n = strings.length;
				for (int i1 = 0; i1 < n; i1++) {
					String str3 = strings[i1];
					drawable.put(str3, "res/" + str1 + "/" + str3);
				}
				drawables.put(str1, drawable);
			} else if (str1.equals("raw")) {
				String[] lists = context.getAssets().list("res/" + str1);
				for (String str2 : lists)
					raws.put(str2, "res/" + str1 + "/" + str2);
			}
		}
	}

	/**
	 * 是否是中文.
	 * 
	 * @return
	 */
	public static boolean isLunarSetting() {
		String str = getLanguageEnv();
		return ((str != null) && ((str.trim().equals("zh-CN")) || (str.trim()
				.equals("zh-TW"))));
	}
}
作者 east
Android, bug清单 1月 5,2021

Android解决Only the original thread that created a view hierarchy can touch its views问题

 
比如在电话的应用程序中,有一个线程是RingTone,如果这个非UI线程中直接操作UI线程,会抛出android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views: 
   1. Why
       为什么会有这种异常产生呢?
       
      当每个应用程序apk第一次启动时,Android会同时启动一个对应的主线程(Main Thread),
      主线程负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,
      并把相关的事件分发到对应的组件进行处理,所以主线程通常又被叫做UI线程。


      但是在开发Android应用时必须遵守单线程模型的原则: 
      Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行,如果在非UI线程中直接操作UI线程,
      会抛出android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that 
      created a view hierarchy can touch its views,这与普通的java程序不同。


       由于UI线程负责事件的监听和绘图,因此,必须保证UI线程能够随时响应用户的需求,
       UI线程里的操作应该向中断事件那样短小,费时的操作(如网络连接)需要另开线程,
       否则,如果UI线程超过5s没有响应用户请求,会弹出对话框提醒用户终止应用程序(ANP)。


       如果在新开的线程中需要对UI进行设定,就可能违反单线程模型,
       因此android采用一种的Message Queue机制保证线程间通信。


       Message Queue是一个消息队列,用来存放通过Handler发送的消息。
       Android在第一启动程序时会默认会为UI thread创建一个关联的消息队列,
      可以通过Looper.myQueue()得到当前线程的消息队列,用来管理程序的一些上层组件,
      activities,broadcast receivers 等,你可以在自己的子线程中创建Handler与UI thread通讯。


      Handler会向message queue通过两种方法发送消息:send或post。
      这两种消息都会插在message queue队尾并按先进先出执行,
      但通过这两种方法发送的消息执行的方式略有不同:
      1)通过send发送的是一个message对象, 会被handler的 handleMessage()函数处理;
      2)而通过post方法发送的是一个runnable对象,则会自己执行。


      每个带图形界面的应用启动后,都会创建一个主线程,可称之为UI线程。
      这个线程自动就会创建一个message queue,来自于系统的消息都会投放到这个message queue里面,
      并按先进先出的顺序处理。


      UI线程图形界面中的view可通过post方法向GUI线程的message queue投递一个runnable。
     对于除UI线程以外的其他线程,创建时缺省并没有message queue,
     而对于UI线程,则可以直接(比如在onCreate)创建一个handler并重载handleMessage,
     省去创建message queue的过程。
作者 east
Android, bug清单 1月 5,2021

Volley解决接收数据出现中文显示乱码问题

Volley接收数据后,若收到的数据header内无charset定义,则使用其默认的”ISO-8859-1″格式进行解析,导致乱码出现。

解决方法:

1. 自定义request,重写parseNetworkResponse方法:

 
private class mJsonRequest extends JsonObjectRequest {  
  
        /** 
         * <p>Description:{转码}</p> 
         * @author:yangbiyao@163.com 
         * @see com.android.volley.toolbox.JsonObjectRequest#parseNetworkResponse(com.android.volley.NetworkResponse) 
         */  
        @Override  
        protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {  
            try {  
                response.headers.put("HTTP.CONTENT_TYPE", "utf-8");  
//                String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));  
                String jsonString = new String(response.data,"utf-8");  
                return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response));  
            }  
            catch (UnsupportedEncodingException e) {  
                return Response.error(new ParseError(e));  
            }  
            catch (JSONException je) {  
                return Response.error(new ParseError(je));  
            }  
        }  
  
        /** 
         * @param method 
         * @param url 
         * @param jsonRequest 
         * @param listener 
         * @param errorListener 
         */  
        public mJsonRequest(int method, String url, JSONObject jsonRequest, Listener<JSONObject> listener,  
                ErrorListener errorListener) {  
            super(method, url, jsonRequest, listener, errorListener);  
        }  
  
        /** 
         * @param url 
         * @param jsonRequest 
         * @param listener 
         * @param errorListener 
         */  
        public mJsonRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener,  
                ErrorListener errorListener) {  
            super(url, jsonRequest, listener, errorListener);  
        }  
  
    }  

 
String jsonString = new String(response.data,"utf-8");  

在此转为我们想要的utf-8格式即可。

方法 2:

直接将数据转码为我们想要的utf-8(或GBK):

new String(data.getBytes(“ISO-8859-1″),”utf-8”)

data为乱码的数据。

作者 east
Android 1月 5,2021

android http请求带中文参数会乱码(url编码)

URL url = new URL(“http://www.my400800.cn &search=400电话 “);   HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

时传递到服务端的中文字符时乱码,最后是将要发送的字符经过编号就可以了代码修改如下:

 URL url = new URL(“http://www.my400800.cn &search=”+java.net.URLEncoder.encode(“400电话 “));   HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

作者 east
Android 12月 16,2020

Android聊天输入框控件

public class ChatInputWidget extends LinearLayout implements OnClickListener {
    private final String TAG = getClass().getSimpleName();
    private ViewPager mEmojiPager;
    private GifEditText mEditText;
    private ImageView mEmojiImageView;
    private Button mSendButton;
    private View pagerView;
    private CircleIndicator circleIndicator;

    private Handler handler = new Handler();
    private List<Emoji> mEmojiList;

    private static final String FILE_NAME = "emoji.txt";
    private static final String GIFT_RES_FILE_PATH = "emoji";
    private static final String ASSETS_FILE_NAME = GIFT_RES_FILE_PATH + "/" + FILE_NAME;
    private final int pagerNum = 10;

    protected Context mContext;
//    protected InputMethodManager inputManager;

    private ChatInputMenuListener mListener;
    private int mToUserId;
    private int mToVipLevel;
    private String toUserName;

    public String getToUserName() {
        return toUserName;
    }

    public void setToUserName(String toUserName) {
        this.toUserName = toUserName;
    }

    public void setToVipLevel(int toVipLevel) {
        this.mToVipLevel = toVipLevel;
    }

    public ChatInputWidget(Context context) {
        super(context);
        if (context instanceof Activity) {
            ((Activity) context).getLayoutInflater().inflate(R.layout.widget_chat_input, this);
        } else {
            inflate(context, R.layout.widget_chat_input, this);
        }
        initView(context);
    }

    public ChatInputWidget(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (context instanceof Activity) {
            ((Activity) context).getLayoutInflater().inflate(R.layout.widget_chat_input, this);
        } else {
            inflate(context, R.layout.widget_chat_input, this);
        }
        initView(context);
    }

    private void initView(Context context) {
        this.mContext = context;
//        inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);

        mEditText = (GifEditText) findViewById(R.id.chat_et_message);
        mEmojiPager = (ViewPager) findViewById(R.id.chat_vp_face_pager);
        mEmojiImageView = (ImageView) findViewById(R.id.chat_iv_face);
        mSendButton = (Button) findViewById(R.id.chat_bt_send);
        pagerView = findViewById(R.id.rl_chat_pager);
        circleIndicator = (CircleIndicator) findViewById(R.id.indicator_chat_emoji);

    }

    public void init() {
        mSendButton.setOnClickListener(this);
        mEmojiImageView.setOnClickListener(this);
        mEditText.setOnClickListener(this);
        mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) {
                    hideEmojicon();
                }
            }
        });

        mEmojiList = getExpressionRes();
        List<View> views = new ArrayList<>();

        int pagerSize;

        if (mEmojiList.size() % pagerNum == 0) {
            pagerSize = mEmojiList.size() / pagerNum;
        } else {
            pagerSize = mEmojiList.size() / pagerNum + 1;
        }

//        LogUtil.w(TAG, "pagerSize === " + pagerSize);

        for (int i = 0; i < pagerSize; i++) {
            if (i == pagerSize - 1) {
                views.add(getGridChildView(mEmojiList.subList(i * pagerNum, mEmojiList.size())));
            } else {
                views.add(getGridChildView(mEmojiList.subList(i * pagerNum, (i + 1) * pagerNum)));
            }
        }
        mEmojiPager.setAdapter(new EmojiPagerAdapter(views));
        circleIndicator.setViewPager(mEmojiPager);
    }

    /**
     * 显示或隐藏表情页
     */
    private void toggleEmojicon() {
        if (pagerView.getVisibility() == View.GONE) {
            hideKeyboard();
            handler.postDelayed(new Runnable() {
                public void run() {
                    showEmojicon();
                }
            }, 100);
        } else {
            hideEmojicon();
            handler.postDelayed(new Runnable() {
                public void run() {
                    showKeyboard();
                }
            }, 100);
        }
    }

    /**
     * 隐藏表情页
     */
    public void hideEmojicon() {
        pagerView.setVisibility(View.GONE);
        mEmojiImageView.setSelected(false);
    }

    private void showEmojicon() {
        pagerView.setVisibility(View.VISIBLE);
        mEmojiImageView.setSelected(true);
    }

    /**
     * 隐藏表情按钮
     */
    public void hideEmojiButton() {
        mEmojiImageView.setVisibility(View.GONE);
    }

    public void setHint(String hint) {
        mEditText.setHint(hint);
    }

    public void setHint(int resid) {
        mEditText.setHint(resid);
    }

    public String getText() {
        return mEditText.getText().toString();
    }

    public void setText(String text) {
        mEditText.setText(text);
        if (text != null) {    //光标移到最后
            mEditText.setSelection(text.length());
        }
    }

    public void setText(int resid) {
        mEditText.setText(resid);
    }

    public void setFocus() {
        mEditText.setFocusable(true);
        mEditText.setFocusableInTouchMode(true);
        mEditText.requestFocus();
        mEditText.requestFocusFromTouch();
        mEditText.postDelayed(new Runnable() {
            @Override
            public void run() {
                AppUtil.showInputMethod(mEditText);
            }
        }, 50);
    }

    public View getEditText() {
        return mEditText;
    }

    /**
     * 隐藏软键盘
     */
    public void hideKeyboard() {
        AppUtil.hideInputMethod(mEditText);
    }

    public void showKeyboard() {
        AppUtil.showInputMethod(mEditText);
    }

    /**
     * 系统返回键被按时调用此方法
     *
     * @return 返回false表示返回键时扩展菜单栏时打开状态,true则表示按返回键时扩展栏是关闭状态<br/>
     * 如果返回时打开状态状态,会先关闭扩展栏再返回值
     */
    public boolean onBackPressed() {
        if (pagerView.getVisibility() == View.VISIBLE) {    //隐藏表情
            hideEmojicon();
            return false;
        } else {
            return true;
        }

    }

    private void sendMessage() {
        //通过回调通知发送消息
        if (mListener != null) {
            String message = StrUtil.escapeForXML(mEditText.getText().toString());
            if (mListener.onSendMessage(message, mToUserId, mToVipLevel, toUserName)) {
                //清空内容
                mEditText.setText(null);
            }
        }
    }

    public void setToUserId(int userId) {
        mToUserId = userId;
    }

    public int getToUserId() {
        return mToUserId;
    }

    /**
     * 清除输入框内容
     */
    public void clearText() {
        mEditText.setText(null);
    }

    public void setChatInputMenuListener(ChatInputMenuListener listener) {
        this.mListener = listener;
    }

    private void insertEmoji(String name) {
        final int pos = mEditText.getSelectionStart();
        final String faceString = "[$" + name + "$]";
        final Editable text = (Editable) mEditText.getText();
        text.insert(pos, faceString);
        final GifDrawable drawable = EmojiHelper.getInstance().getGifDrawable(name);
        if (drawable != null) {
            final ImageSpan gifSpan = new GifImageSpan(drawable);
            text.setSpan(gifSpan, pos, pos + faceString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }

    private List<Emoji> getExpressionRes() {
        List<Emoji> reslist = new ArrayList<>();
        String emojiJson = FileUtil.readAssetsByName(mContext, ASSETS_FILE_NAME);

        try {
            reslist = parseGiftList(new JSONObject(emojiJson));
        } catch (Exception e) {
            LogUtil.e(TAG, "read local gift error:" + e.toString());
        }
        return reslist;
    }

    private List<Emoji> parseGiftList(JSONObject json) throws Exception {
        List<Emoji> giftList = new ArrayList<>();
        JSONArray jsonArray = json.getJSONArray("emoji");
        if (jsonArray != null) {
            for (int i = 0; i < jsonArray.length(); i++) {
                giftList.add(parseGift(jsonArray.getJSONObject(i)));
            }
        }
        return giftList;
    }

    private Emoji parseGift(JSONObject json) throws Exception {
        Emoji emoji = new Emoji();
        emoji.setId(json.getString("id"));
        emoji.setName(json.getString("name"));
        return emoji;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.chat_iv_face:
                toggleEmojicon();
                break;
            case R.id.chat_et_message:
                hideEmojicon();
                break;
            case R.id.chat_bt_send:
                sendMessage();
                break;
        }
    }

    /**
     * 获取表情的gridview的子view
     *
     * @param
     * @return
     */
    private View getGridChildView(List<Emoji> list) {
        final EmojiGridAdapter expressionAdapter = new EmojiGridAdapter(mContext, list);
        GridView gridView = (GridView) LayoutInflater.from(mContext).inflate(R.layout.layout_emoji_grid, null);
        gridView.setAdapter(expressionAdapter);
        gridView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                try {
                    // 文字输入框可见时,才可输入表情
                    if (mEditText.getVisibility() == View.VISIBLE) {
                        insertEmoji(expressionAdapter.getItem(position).getId());
                    }
                } catch (Exception e) {
                }

            }
        });
        return gridView;
    }

    public class EmojiPagerAdapter extends PagerAdapter {

        private List<View> views;

        public EmojiPagerAdapter(List<View> views) {
            this.views = views;
        }

        @Override
        public int getCount() {
            return views.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ((ViewPager) container).addView(views.get(position));
            return views.get(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            ((ViewPager) container).removeView(views.get(position));

        }

    }

    private class EmojiGridAdapter extends QuickAdapter<Emoji> {

        public EmojiGridAdapter(Context context, List<Emoji> objects) {
            super(context, R.layout.item_emoji, objects);
        }

        @Override
        protected void convert(BaseAdapterHelper helper, Emoji item) {
            helper.setText(R.id.emoji_tv_expression, item.getName());
            helper.setImageDrawable(R.id.emoji_iv_expression, EmojiHelper.getInstance().getPngDrawable(item.getId()));
        }

    }

    public int getChatInputLength() {
        if (null != mEditText) {
            return mEditText.getChatInputLength();
        } else {
            return 0;
        }
    }

    public interface ChatInputMenuListener {
        /**
         * 发送消息按钮点击
         *
         * @param content  文本内容
         * @param toUserId
         */
        boolean onSendMessage(String content, int toUserId, int toVipLevel, String toUserName);

    }

}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              xmlns:skin="http://schemas.android.com/android/skin"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:background="@drawable/skin_label_gray_bg"
              android:orientation="vertical"
              skin:enable="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:gravity="center_vertical|right"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1.00"
            android:background="@drawable/skin_label_white_bg"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            android:paddingBottom="8dp"
            android:paddingRight="5dp"
            android:paddingTop="8dp"
            skin:enable="true">

            <LinearLayout
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1.00"
                android:gravity="center_vertical|right"
                android:orientation="horizontal">

                <!-- <LinearLayout
                    android:id="@+id/chat_ll_to"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal" >

                    <TextView
                        android:id="@+id/chat_tv_to"
                        android:layout_width="60dp"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_vertical"
                        android:layout_marginLeft="5dp"
                        android:drawablePadding="5dp"
                        android:drawableRight="@drawable/small_up_arrow"
                        android:ellipsize="end"
                        android:gravity="right"
                        android:singleLine="true"
                        android:text="@string/chat_text_toall"
                        android:textColor="@color/common_blue"
                        android:textSize="14sp" />

                    <View
                        android:layout_width="1px"
                        android:layout_height="match_parent"
                        android:layout_marginLeft="5dp"
                        android:background="@color/line_view_item" />
                </LinearLayout> -->

                <com.gift.view.GifEditText
                    android:id="@+id/chat_et_message"
                    style="?android:attr/editTextStyle"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="5dp"
                    android:background="@null"
                    android:focusable="true"
                    android:focusableInTouchMode="true"
                    android:gravity="center_vertical"
                    android:hint="@string/chat_hint_message"
                    android:imeOptions="actionNone"
                    android:inputType="textMultiLine"
                    android:maxHeight="100dp"
                    android:maxLength="200"
                    android:textColor="@color/text_content"
                    android:textColorHint="@color/text_prompt_input"
                    android:textSize="14sp"/>
            </LinearLayout>

            <ImageView
                android:id="@+id/chat_iv_face"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="5dp"
                android:src="@drawable/button_selector_chat_face"/>
        </LinearLayout>

        <Button
            android:id="@+id/chat_bt_send"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="5dp"
            android:background="@drawable/skin_button_bg_white"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:text="@string/chat_text_send"
            android:textColor="@color/button_text_color"
            android:textSize="14sp"
            skin:enable="true"/>
    </LinearLayout>

    <RelativeLayout
        android:id="@+id/rl_chat_pager"
        android:layout_width="match_parent"
        android:layout_height="270dp"
        android:background="@color/white"
        android:paddingBottom="27dp"
        android:visibility="gone"
        >

        <android.support.v4.view.ViewPager
            android:id="@+id/chat_vp_face_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:persistentDrawingCache="animation"
            />

        <com.gift.view.infiniteview.CircleIndicator
            android:id="@+id/indicator_chat_emoji"
            android:layout_width="match_parent"
            android:layout_height="6dp"
            android:layout_alignParentBottom="true"
            app:ci_background="@color/banner_indicator_selected"
            app:ci_gravity="center"
            app:ci_margin="5dp"
            app:ci_mode="solo"
            app:ci_radius="3dp"
            app:ci_selected_background="@color/text_orange"
            />

    </RelativeLayout>

</LinearLayout>
作者 east
Android 12月 16,2020

Android直播间刷礼物动画控件

public class GiftWidget extends LinearLayout implements OnClickListener, GiftNumberChangeListener {
    private ViewPager mViewPager;
    private Button mGiveButton;
    private View mNumberView;
    private TextView mBalanceTextView;
    private TextView mNumberTextView;
    private LinearLayout mIndicatorView;
    private TextView pay;

    private final static int GIFT_MAX_ITEM_SIZE = 10;
    private int indicatorSpace = 5;
    private int mNumber;
    private String mSelectedGiftId;

    private GiftNumberPopup mGiftNumberPopup;
    private List<GiftGridAdapter> mAdapterList = new ArrayList<GiftGridAdapter>();

    private GiftGiveClickListener mGiftGiveListener;
    private Context mContext;

    public GiftWidget(Context context) {
        super(context);
        if (context instanceof Activity) {
            ((Activity) context).getLayoutInflater()
                    .inflate(R.layout.widget_gift, this);
        } else {
            inflate(context, R.layout.widget_gift, this);
        }
        initView(context);
    }

    public GiftWidget(Context context, AttributeSet attrs) {
        super(context, attrs);
        if (context instanceof Activity) {
            ((Activity) context).getLayoutInflater()
                    .inflate(R.layout.widget_gift, this);
        } else {
            inflate(context, R.layout.widget_gift, this);
        }
        initView(context);
    }

    private void initView(Context context) {
        this.mContext = context;
        mViewPager = (ViewPager) findViewById(R.id.gift_vp_pager);
        mGiveButton = (Button) findViewById(R.id.gift_bt_give);
        mNumberView = findViewById(R.id.gift_ll_number);
        mBalanceTextView = (TextView) findViewById(R.id.gift_tv_balance);
        mNumberTextView = (TextView) findViewById(R.id.gift_tv_number);
        mIndicatorView = (LinearLayout) findViewById(R.id.gift_ll_indicator);
        pay = (TextView) findViewById(R.id.gift_tv_balance_cz);
        mNumberView.setOnClickListener(this);
        mGiveButton.setOnClickListener(this);
        pay.setOnClickListener(this);
    }

    public void initGift(List<Gift> giftList) {
        if (giftList == null) {
            return;
        }
        mAdapterList.clear();
        if (giftList.size() > 0 && mSelectedGiftId == null) {    //默认选中第一个礼物
            mSelectedGiftId = giftList.get(0).getId();
        }
        final List<View> views = new ArrayList<View>();
        int start = 0;
        while (start < giftList.size()) {
            int count;
            if (giftList.size() - start > GIFT_MAX_ITEM_SIZE) {
                count = GIFT_MAX_ITEM_SIZE;
            } else {
                count = giftList.size() - start;
            }
            List<Gift> list = giftList.subList(start, start + count);
            start = start + count;
            views.add(getGridChildView(list));
        }
        initIndicator(views.size());

        mViewPager.setAdapter(new GiftPagerAdapter(views));
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                switchIndicator(position);
                //刷新旧的选中状态
                if (mAdapterList.size() > position) {
                    GiftGridAdapter adapter = mAdapterList.get(position);
                    adapter.notifyDataSetChanged();
                }
            }
        });
        switchIndicator(0);
    }

    private void initIndicator(int count) {
        mIndicatorView.removeAllViews();
        for (int i = 0; i < count; i++) {
            ImageView indicator = new ImageView(getContext());
            indicator.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            indicator.setPadding(indicatorSpace, indicatorSpace, indicatorSpace, indicatorSpace);
            indicator.setImageResource(R.drawable.icon_indicator);
            mIndicatorView.addView(indicator);
        }
    }

    private void switchIndicator(int position) {
        for (int i = 0; i < mIndicatorView.getChildCount(); i++) {
            ((ImageView) mIndicatorView.getChildAt(i)).setSelected(i == position ? true : false);
        }
    }

    private View getGridChildView(List<Gift> giftList) {
        final GiftGridAdapter adapter = new GiftGridAdapter(getContext(), 0, giftList);
        mAdapterList.add(adapter);
        GridView gridView = (GridView) LayoutInflater.from(getContext()).inflate(R.layout.layout_gift_grid, null);
        gridView.setAdapter(adapter);
        gridView.setChoiceMode(GridView.CHOICE_MODE_SINGLE);
        gridView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                mSelectedGiftId = adapter.getItem(position).getId();
                adapter.notifyDataSetChanged();
            }
        });
        return gridView;
    }

    public class GiftPagerAdapter extends PagerAdapter {

        private List<View> views;

        public GiftPagerAdapter(List<View> views) {
            this.views = views;
        }

        @Override
        public int getCount() {
            return views.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ((ViewPager) container).addView(views.get(position));
            return views.get(position);
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            ((ViewPager) container).removeView(views.get(position));

        }

    }

    private class GiftGridAdapter extends ArrayAdapter<Gift> {

        public GiftGridAdapter(Context context, int textViewResourceId, List<Gift> giftList) {
            super(context, textViewResourceId, giftList);
        }


        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                if (getContext() instanceof Activity) {
                    convertView = ((Activity) getContext()).getLayoutInflater().inflate(R.layout.item_gift, null);
                } else {
                    convertView = View.inflate(getContext(), R.layout.item_gift, null);
                }
                holder = new ViewHolder();
                holder.root = convertView.findViewById(R.id.gift_item_ll_root);
                holder.imageView = (ImageView) convertView.findViewById(R.id.gift_item_iv_gift);
                holder.nameTextView = (TextView) convertView.findViewById(R.id.gift_item_tv_name);
                holder.priceTextView = (TextView) convertView.findViewById(R.id.gift_item_tv_price);
                holder.line = convertView.findViewById(R.id.line);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            if (position > 4) {
                holder.line.setVisibility(View.GONE);
            } else {
                holder.line.setVisibility(View.VISIBLE);
            }
            Gift gift = getItem(position);
            try {
                GiftHelper.getInstance().setPngDrawable(holder.imageView, gift);
                holder.nameTextView.setText(gift.getName());
                holder.priceTextView.setText(gift.getPrice());
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (gift.getId().equals(mSelectedGiftId)) {    //选中
                holder.root.setSelected(true);
            } else {
                holder.root.setSelected(false);
            }

            return convertView;
        }

        private class ViewHolder {
            View root;
            View line;
            ImageView imageView;
            TextView nameTextView;
            TextView priceTextView;
        }
    }

    public void initGiftNumber(Activity activity) {
        if (mGiftNumberPopup == null) {
            mGiftNumberPopup = new GiftNumberPopup(activity);
            mGiftNumberPopup.setNumberChangeListener(this);
        }
        //默认显示数量1
        setGiftNumber(1);
    }

    private void showGiftNumber(View view) {
        mGiftNumberPopup.showPopupWindow(view);
    }

    public void dismissGiftNumber() {
        mGiftNumberPopup.dismiss();
    }

    public void setBalance(String text) {
        mBalanceTextView.setText(text);
    }

    private void setGiftNumber(int number) {
        mNumber = number;
        mNumberTextView.setText(String.valueOf(number));
    }

    public void setGiveGift(OnClickListener listener) {
        mGiveButton.setOnClickListener(listener);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.gift_bt_give:
                if (mGiftGiveListener != null && mSelectedGiftId != null) {
                    mGiftGiveListener.onGiftGiveClick(Integer.parseInt(mSelectedGiftId), mNumber);
                }
                break;
            case R.id.gift_ll_number:
                showGiftNumber(v);
                break;
            case R.id.gift_tv_balance_cz:
                RechargeActivity.startActivity(mContext);
                mGiftGiveListener.dismiss();
                break;
        }
    }

    @Override
    public void onGiftNumberChange(int number) {
        setGiftNumber(number);
    }

    public void setOnGiftGiveClickListener(GiftGiveClickListener listener) {
        mGiftGiveListener = listener;
    }

    public interface GiftGiveClickListener {
        public void onGiftGiveClick(int giftId, int number);

        public void dismiss();
    }
}
<?xml version="1.0" encoding="utf-8"?>
<!-- 礼物控件layout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:skin="http://schemas.android.com/android/skin"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="vertical">


    <com.giflist.view.AdjustHeightViewPager
        android:id="@+id/gift_vp_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:flipInterval="300"
        android:persistentDrawingCache="animation"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="5dp"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/gift_ll_indicator"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal"/>

        <View
            android:layout_width="match_parent"
            android:layout_height="2px"
            android:layout_marginTop="7dp"
            android:background="@color/line_list"
            skin:enable="true"/>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp">

            <TextView
                android:id="@+id/gift_tv_balance_label"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:text="@string/gift_text_balance"
                android:textColor="@color/text_content"
                android:textSize="14sp"/>

            <TextView
                android:id="@+id/gift_tv_balance"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginRight="5dp"
                android:layout_toLeftOf="@+id/gift_tv_balance_cz"
                android:layout_toRightOf="@+id/gift_tv_balance_label"
                android:ellipsize="end"
                android:singleLine="true"
                android:textColor="@color/text_content"
                android:textSize="14sp"/>

            <TextView
                android:id="@+id/gift_tv_balance_cz"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginRight="@dimen/top_margin"
                android:layout_toLeftOf="@+id/gift_ll_number"
                android:text="@string/recharge_title"
                android:textColor="@color/skin_selector_text_color"
                android:textSize="14sp"
                skin:enable="true"/>


            <LinearLayout
                android:id="@+id/gift_ll_number"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_centerVertical="true"
                android:paddingBottom="10dp"
                android:paddingTop="10dp"
                android:layout_marginRight="10dp"
                android:layout_toLeftOf="@+id/gift_bt_give"
                android:background="@drawable/button_gray_selector"
                android:clickable="true"
                android:gravity="right|center_vertical"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/gift_tv_number"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:textColor="@color/skin_selector_text_color"
                    android:textSize="14sp"
                    android:minWidth="50dp"
                    android:gravity="center"
                    android:text="1"
                    skin:enable="true"/>
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingRight="10dp"
                    android:src="@drawable/video_present_number_point_skin_n"/>
            </LinearLayout>

            <Button
                android:id="@+id/gift_bt_give"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:background="@drawable/skin_button_orange_selector"
                android:paddingBottom="10dp"
                android:paddingLeft="25dp"
                android:paddingRight="25dp"
                android:paddingTop="10dp"
                android:text="@string/gift_text_give"
                android:textColor="@color/white"
                skin:enable="true"/>
        </RelativeLayout>
    </LinearLayout>

</LinearLayout>
作者 east
Android 12月 11,2020

Android自定义交易密码框


/**
 * 交易密码弹出框
 * Created by Administrator on 2016/4/18.
 */
public class TradePasswordPopup extends BasePopupWindow {

    private Button popupSure, popcancel;
    private MyGridPasswordView passwordEdit;
    private LinearLayout tip_text_layout;
    private TextView incorrect_password;
    private OnFocus onFocus;
    private OnClickListener mListener;

    public TradePasswordPopup(Activity context) {
        super(context, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mGravity = Gravity.CENTER;
    }

    protected boolean getFocusable() {
        return true;
    }

    @Override
    protected void initView(Activity context) {
        popupSure = (Button) mPopupView.findViewById(R.id.room_password_ok);
        popcancel = (Button) mPopupView.findViewById(R.id.room_password_cancel);
        passwordEdit = (MyGridPasswordView) mPopupView.findViewById(R.id.password_edit);
        incorrect_password = (TextView) mPopupView.findViewById(R.id.tx_tradepassword_error);
        tip_text_layout = (LinearLayout) mPopupView.findViewById(R.id.passworld_edit);
      /*  incorrect_password.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);
        incorrect_password.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mListener != null) {
                    mListener.onClick(incorrect_password);
                }
                dismiss();
            }
        }); */
        popupSure.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                onFocus.focus(passwordEdit.getPassWord());
            }
        });
        popcancel.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
               dismiss();
            }
        });
        passwordEdit.clearPassword();
        passwordEdit.forceInputViewGetFocus();
        showInputMethod(passwordEdit.getInputView(), 100);
    }

    public void showPopupWindow() {
       super.showPopupWindow();

    }

    public void clearPassword(){
        passwordEdit.clearPassword();
    }

    public void setAskPasswordListener(OnClickListener listener) {
        mListener = listener;
    }

    public void setListener(OnFocus onFocus) {
        this.onFocus = onFocus;
    }

    public interface OnFocus {
        void focus(String txt);
    }

    @Override
    protected Animation getShowAnimation() {
        return null;
    }

    @Override
    protected View getClickToDismissView() {
        return null;
    }

    @Override
    public View getPopupView() {
        return getPopupViewById(R.layout.popup_trade_password_view);
    }

    @Override
    public View getAnimaView() {
        return mPopupView;
    }

    @Override
    public boolean getPopupTransparent() {
        return false;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/passworld_edit"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="bottom"
    android:gravity="center"
    android:orientation="vertical">


    <LinearLayout

        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/popup_dialog_bg"
        android:gravity="center"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:orientation="vertical"
        android:visibility="visible">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Button
                android:id="@+id/room_password_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:background="@drawable/white_gray_bottomleft_radius"
                android:paddingBottom="20dp"
                android:paddingTop="20dp"
                android:text="@string/cancel"
                android:textColor="@color/text_b2"
                android:textSize="16sp" />

            <TextView
                android:id="@+id/room_password_prompt_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:gravity="center"
                android:padding="10dp"
                android:text="@string/trade_input_trade_password"
                android:textColor="#343434"
                android:textSize="16dp" />


            <Button
                android:id="@+id/room_password_ok"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:background="@drawable/white_gray_bottomright_radius"
                android:paddingBottom="20dp"
                android:paddingTop="20dp"
                android:text="@string/ok"
                android:textColor="@color/bg_title"
                android:textSize="16sp" />
        </RelativeLayout>

        <com.bitvf.bitcoinWallet.view.MyGridPasswordView
            android:id="@+id/password_edit"
            android:layout_width="fill_parent"
            android:layout_height="50dip"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="@dimen/verify_code_edit_margin_bottom"
            android:layout_marginLeft="@dimen/verify_code_margin"
            android:layout_marginRight="@dimen/verify_code_margin"
            android:layout_marginTop="30dp"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:gravity="center"
            app:gpvLineColor="@color/divive_line"
            app:gpvLineWidth="@dimen/verify_code_border_width"
            app:gpvPasswordLength="6"
            app:gpvPasswordTransformation="●"
            app:gpvPasswordType="textPassword"
            app:gpvTextSize="18sp" />

        <TextView
            android:id="@+id/tx_tradepassword_error"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dip"
            android:textSize="14sp"
            android:layout_marginTop="5dip"
            android:layout_marginBottom="40dip"
            android:textColor="@color/text_warn"
            tools:text="密码错误,请重新输入"
            />


    </LinearLayout>
</LinearLayout>
作者 east
Android 12月 11,2020

Android记录文件日志工具类



import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.util.Log;

import com.bitvf.bitcoinWallet.base.JJApplication;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class FileLogger {
	private static final String TAG = "FileLogger";
	private static final long MB = 1024 * 1024;
	private static final long LOG_LIMIT = 1 * 1024 * 1024;
	private static final long FREE_SPACE_LIMIT = 5 * 1024 * 1024;
	private static final long FREE_SPACE_TIMER = 20 * 60 * 1000;
	private static final int DAY_LIMIT = 3;	//日志保存的天数
	private static final String INFO_COLOR = "green";
	private static final String ERROR_COLOR = "red";
	private static final String WARN_COLOR = "orange";
	private static final String DEBUG_COLOR = "blue";
	private ExecutorService singleThreadService = Executors.newSingleThreadExecutor();
	private Timer timer = null;
	private boolean spaceAvailable = true;

	void d(String tag, String msg) {
		startThreadService(DEBUG_COLOR, "[" + tag + "]" + msg);
	}

	void e(String tag, String msg) {
		startThreadService(ERROR_COLOR, "[" + tag + "]" + "[ERROR]" + msg);
	}

	void i(String tag, String msg) {
		startThreadService(INFO_COLOR, "[" + tag + "]" + msg);
	}

	void w(String tag, String msg) {
		startThreadService(WARN_COLOR, "[" + tag + "]" + "[WARN]" + msg);
	}

	void v(String tag, String msg) {
		startThreadService(INFO_COLOR, "[" + tag + "]" + msg);
	}

	private void startThreadService(String tag, String msg) {
		File file = getLogRoot();
		if ((file == null) || (!file.exists())) {
			return;
		}
		singleThreadService.execute(getWriterRunnable(tag, msg));
	}

	private Runnable getWriterRunnable(final String tag, final String msg) {
		Runnable runnable = new Runnable() {
			public void run() {
				try {
					File file = getLogRoot();
					if ((file == null) || (!file.exists())) {
						return;
					}
					if ((timer == null) && (!freeSpace())) {
						return;
					}
					FileLogger.this.startCleanUpTimer();
					File availableFile = FileLogger.this.getAvailableFile();
					if (availableFile == null) {
						return;
					}
					boolean available = false;
					if (!availableFile.exists()) {
						try {
							availableFile.createNewFile();
							available = true;
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					if (!availableFile.exists()) {
						return;
					}
					FileOutputStream fileOutputStream = null;
					try {
						fileOutputStream = new FileOutputStream(availableFile, true);
						if (available) {
							String header = "<header>"
									+ "<meta http-equiv=" + "\""
									+ "Content-Type" + "\"" + " content="
									+ "\"" + "text/html; charset=UTF-8" + "\">"
									+ "</header>";
							fileOutputStream.write(header.getBytes());
						}
						SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
						String strDate = simpleDateFormat.format(new Date());
						String body = "<p><font color =\"" + tag + "\">" + strDate + " " + msg.replaceAll(">", ">").replaceAll("<", "<") + "</p>";
						fileOutputStream.write(body.getBytes());
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					} finally {
						try {
							if (fileOutputStream != null) {
								fileOutputStream.close();
							}
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					return;
				} catch (NullPointerException e) {
					e.printStackTrace();
					if(null != e) {
						Log.e(TAG, e.getMessage());
					}
				} catch (Exception e) {
					e.printStackTrace();
					if(null != e) {
						Log.e(TAG, e.getMessage());
					}
				}
			}
		};
		return runnable;
	}

	private File getAvailableFile() {
		File rootFile = getLogRoot();
		if ((rootFile == null) || (!rootFile.exists())) {
			return null;
		}
		removeOldFolders();
		File file = getLogFolder();
		int index = 0;
		List<File> fileList = null;
		File[] files = file.listFiles();
		if ((files != null) && (files.length > 0)) {
			fileList = Arrays.asList(files);
			if (fileList.size() > 1) {
				getSortedFileListByName(fileList);
				files = (File[]) fileList.toArray();
			}
			String name = files[0].getName();
			String cntName = name.substring(0, name.indexOf("."));
			try {
				index = Integer.parseInt(cntName);
			} catch (Exception e) {
				e.printStackTrace();
				Log.e(TAG, "Wrong cntName! : " + cntName);
			}
			if (files[0].length() >= MB / 2) {
				index++;
			}
		}
		String fileName = getLogFileName(index);
		return new File(file, fileName);
	}

	private static String getLogFileName(int index) {
		return String.format("%03d", index) + ".html";
	}

	private File getLogFolder() {
		File rootFile = getLogRoot();
		File file = new File(rootFile, getCurrentDate());
		if (!file.exists()) {
			file.mkdirs();
		}
		return file;
	}

	private void removeFolderBeforeDay(String strDate, int offset) {
		String strBeforeDate = getSpecifiedDayBefore(strDate, offset);
		File rootFile = getLogRoot();
		File file = new File(rootFile, strBeforeDate);
		if (file.exists()) {
			deleteFile(file);
		}
	}

	private void removeOldFolders() {
		File file = getLogRoot();
		if ((file == null) || (!file.exists())) {
			return;
		}
		String strDate = getCurrentDate();
		String strYesterdayDate = getSpecifiedDayBefore(strDate, -1);
		String strBeforeYesterdayDate = getSpecifiedDayBefore(strDate, -2);
		File[] files = file.listFiles();
		if (files == null) {
			return;
		}
		for (File subFile : files) {
			if (subFile.isDirectory()) {
				String fileName = subFile.getName();
				if (!fileName.contains(strDate) && !fileName.contains(strYesterdayDate) && !fileName.contains(strBeforeYesterdayDate)) {
					deleteFile(subFile);
				}
			} else {
				subFile.delete();
			}
		}
	}

	private static void deleteFile(File file) {
		if (file == null) {
			return;
		}
		if (file.exists()) {
			if (file.isDirectory()) {
				File[] files = file.listFiles();
				if (files != null) {
					for (File subFile : files) {
						deleteFile(subFile);
					}
				}
				file.delete();
			} else {
				file.delete();
			}
		}
	}

	private static long getDirSize(File floder) {
		if (floder == null) {
			return 0L;
		}
		if (floder.isDirectory()) {
			long size = 0L;
			File[] files = floder.listFiles();
			if (files != null) {
				for (File subFile : files) {
					size += getDirSize(subFile);
				}
			}
			return size;
		}
		return floder.length();
	}

	private static String getSpecifiedDayBefore(String strDate, int offset) {
		Calendar calendar = Calendar.getInstance();
		Date date = null;
		try {
			date = new SimpleDateFormat("yyyyMMdd").parse(strDate);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		calendar.setTime(date);
		calendar.add(Calendar.DATE, offset);
		String dateTime = new SimpleDateFormat("yyyyMMdd").format(calendar.getTime());
		return dateTime;
	}

	private static File getStorageDir() {
		if (Environment.getExternalStorageState().equals("mounted")) {
			return Environment.getExternalStorageDirectory();
		}
		return Environment.getDataDirectory();
	}

	private static void getSortedFileListByName(List<File> fileList) {
		Collections.sort(fileList, new Comparator<File>() {
			public int compare(File lhs, File rhs) {
				return lhs.getName().compareTo(rhs.getName());
			}
		});
	}

	private boolean spaceIsAlearting() {
		return getCurrentAvailabeSpace() < FREE_SPACE_LIMIT;
	}

	private boolean logSizeAlearting() {
		return getDirSize(getLogRoot()) > LOG_LIMIT;
	}

	boolean freeSpace() {
		File file = getLogRoot();
		if ((file == null) || (!file.exists())) {
			return false;
		}
		if (spaceIsAlearting()) {
			Log.w(TAG, "there is no availabe free space and try to free space");
			freeLogFolder();
			return !spaceIsAlearting();
		}
		checkAndFreeLogFiles();
		return true;
	}

	private void freeLogFolder() {
		deleteFile(getLogRoot());
	}

	private void freeOldFolders() {
		File[] files = getLogRoot().listFiles();
		for (File file : files) {
			if ((file.isDirectory()) && (!file.getName().contains(getCurrentDate()))) {
				deleteFile(file);
			} else {
				file.delete();
			}
		}
	}
	
	private String getCurrentDate() {
		return new SimpleDateFormat("yyyyMMdd").format(new Date());
	}

	private void freeOldFiles() {
		File[] files = getLogFolder().listFiles();
		if (files != null) {
			List<File> fileList = Arrays.asList(files);
			getSortedFileListByName(fileList);
			if (fileList.size() > 5) {
				int i = fileList.size();
				for (int j = 5; j < i; j++) {
					Log.w(TAG, "try to delete file : " + fileList.get(j).getAbsoluteFile());
					fileList.get(j).delete();
				}
			}
		}
	}

	@TargetApi(18)
	private static long getCurrentAvailabeSpace() {
		StatFs statFs = new StatFs(getStorageDir().getPath());
		if (Build.VERSION.SDK_INT >= 18) {
			return statFs.getAvailableBytes();
		}
		long availableBlocks = statFs.getAvailableBlocks();
		long blockSize = statFs.getBlockSize();
		return availableBlocks * blockSize;
	}

	File getLogRoot() {
		try {
			Context context = JJApplication.getInstance();
			String filePath = "/Android/data/" + context.getPackageName() + "/log/";
			File file = new File(getStorageDir(), filePath);
			synchronized (this) {
				if (!file.exists()) {
					file.mkdirs();
				}
			}
			return file;
		} catch (Throwable e) {
			return null;
		}
	}

	void checkAndFreeLogFiles() {
		if (logSizeAlearting()) {
			Log.w(TAG, "the log size is > 8M, try to free log files");
			freeOldFolders();
			Log.w(TAG, "old folders are deleted");
			if (logSizeAlearting()) {
				Log.w(TAG, "try to delete old log files");
				freeOldFiles();
			}
		}
	}

	private void startCleanUpTimer() {
		synchronized (this) {
			if (timer == null) {
				timer = new Timer();
				TimerTask task = new TimerTask() {
					public void run() {
						singleThreadService.execute(new Runnable() {
							public void run() {
								try {
									File file = getLogRoot();
									if ((file == null) || (!getLogRoot().exists())) {
										return;
									}
									spaceAvailable = freeSpace();
								} catch (NullPointerException e) {
									e.printStackTrace();
									Log.e(TAG, e.getMessage());
								} catch (Exception e) {
									e.printStackTrace();
									Log.e(TAG, e.getMessage());
								}
							}
						});
					}
				};
				timer.schedule(task, FREE_SPACE_TIMER, FREE_SPACE_TIMER);
			}
		}
	}
}
作者 east
Android 12月 11,2020

Android常用图片操作工具类


public final class ImageTools {

    /**
     * 将View转化为Bitmap
     *
     * @param view
     * @return
     */
    public static Bitmap convertViewToBitmap(View view) {
        view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        // view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        view.buildDrawingCache();
        Bitmap bitmap = view.getDrawingCache();
        return bitmap;
    }

    /**
     * 质量压缩法
     *
     * @param image
     * @return
     */
    public static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.PNG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
            baos.reset();// 重置baos即清空baos
            options -= 10;// 每次都减少10
            if (options > 0 && options < 100)
                image.compress(Bitmap.CompressFormat.PNG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
        return bitmap;
    }

    /**
     * 图片按比例大小压缩方法(根据路径获取图片并压缩)
     *
     * @param srcPath
     * @return
     */
    public static Bitmap getimage(String srcPath) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空

        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = 180f;// 这里设置高度为800f
        float ww = 500f;// 这里设置宽度为480f

        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;// be=1表示不缩放
        if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;// 设置缩放比例
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
        return bitmap;// compressImage(bitmap);// 压缩好比例大小后再进行质量压缩
    }

    /**
     * 图片按比例大小压缩方法(根据路径获取图片并压缩)
     *
     * @param srcPath
     * @return
     */
    public static Bitmap getImageFromSDCard(String srcPath) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空

        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = 50f;// 这里设置高度为800f
        float ww = 50f;// 这里设置宽度为480f
        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;// be=1表示不缩放
        if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;// 设置缩放比例
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
        return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩
    }

    public static Bitmap getBitmapByPath(String srcPath) {
        return comp(BitmapFactory.decodeFile(srcPath));
    }

    /**
     * 图片按比例大小压缩方法(根据Bitmap图片压缩)
     *
     * @param image
     * @return
     */
    public static Bitmap comp(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.PNG, 100, baos);
        if (baos.toByteArray().length / 1024 > 1024) {// 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
            baos.reset();// 重置baos即清空baos
            image.compress(Bitmap.CompressFormat.PNG, 50, baos);// 这里压缩50%,把压缩后的数据存放到baos中
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = 800f;// 这里设置高度为800f
        float ww = 480f;// 这里设置宽度为480f
        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;// be=1表示不缩放
        if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;// 设置缩放比例
        newOpts.inPreferredConfig = Config.RGB_565;// 降低图片从ARGB888到RGB565
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        isBm = new ByteArrayInputStream(baos.toByteArray());
        bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
        return bitmap;// 压缩好比例大小后再进行质量压缩
    }

    /**
     * Transfer drawable to bitmap
     *
     * @param drawable
     * @return
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();

        Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                : Bitmap.Config.RGB_565;
        Bitmap bitmap = Bitmap.createBitmap(w, h, config);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }

    /**
     * Bitmap to drawable
     *
     * @param bitmap
     * @return
     */
    public static Drawable bitmapToDrawable(Bitmap bitmap) {
        return new BitmapDrawable(bitmap);
    }

    /**
     * Input stream to bitmap
     *
     * @param inputStream
     * @return
     * @throws Exception
     */
    public static Bitmap inputStreamToBitmap(InputStream inputStream)
            throws Exception {
        return BitmapFactory.decodeStream(inputStream);
    }

    /**
     * Byte transfer to bitmap
     *
     * @param byteArray
     * @return
     */
    public static Bitmap byteToBitmap(byte[] byteArray) {
        if(byteArray!=null){
            if (byteArray.length != 0) {
                return BitmapFactory
                        .decodeByteArray(byteArray, 0, byteArray.length);
            } else {
                return null;
            }
        }else{
            return null;
        }

    }

    /**
     * Byte transfer to drawable
     *
     * @param byteArray
     * @return
     */
    public static Drawable byteToDrawable(byte[] byteArray) {
        ByteArrayInputStream ins = null;
        if (byteArray != null) {
            ins = new ByteArrayInputStream(byteArray);
        }
        return Drawable.createFromStream(ins, null);
    }

    /**
     * Bitmap transfer to bytes
     *
     * @return
     */
    public static byte[] bitmapToBytes(Bitmap bm) {
        byte[] bytes = null;
        if (bm != null) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
            bytes = baos.toByteArray();
        }
        return bytes;
    }

    /**
     * Drawable transfer to bytes
     *
     * @param drawable
     * @return
     */
    public static byte[] drawableToBytes(Drawable drawable) {
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        Bitmap bitmap = bitmapDrawable.getBitmap();
        byte[] bytes = bitmapToBytes(bitmap);
        ;
        return bytes;
    }

    /**
     * Base64 to byte[] //
     */
    // public static byte[] base64ToBytes(String base64) throws IOException {
    // byte[] bytes = Base64.decode(base64);
    // return bytes;
    // }
    //
    // /**
    // * Byte[] to base64
    // */
    // public static String bytesTobase64(byte[] bytes) {
    // String base64 = Base64.encode(bytes);
    // return base64;
    // }

    /**
     * Create reflection images
     *
     * @param bitmap
     * @return
     */
    public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) {
        final int reflectionGap = 4;
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        Matrix matrix = new Matrix();
        matrix.preScale(1, -1);

        Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w,
                h / 2, matrix, false);

        Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2),
                Config.ARGB_8888);

        Canvas canvas = new Canvas(bitmapWithReflection);
        canvas.drawBitmap(bitmap, 0, 0, null);
        Paint deafalutPaint = new Paint();
        canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint);

        canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null);

        Paint paint = new Paint();
        LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,
                bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff,
                0x00ffffff, TileMode.CLAMP);
        paint.setShader(shader);
        // Set the Transfer mode to be porter duff and destination in
        paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
        // Draw a rectangle using the paint with our linear gradient
        canvas.drawRect(0, h, w, bitmapWithReflection.getHeight()
                + reflectionGap, paint);

        return bitmapWithReflection;
    }

    /**
     * Get rounded corner images
     *
     * @param bitmap
     * @param roundPx
     *            5 10
     * @return
     */
    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, w, h);
        final RectF rectF = new RectF(rect);
        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);

        return output;
    }

    /**
     * Resize the bitmap
     *
     * @param bitmap
     * @param width
     * @param height
     * @return
     */
    public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {
        Bitmap newbmp = null;
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        // 960*1280

        if (w > 960 && h > 1280) {
            Matrix matrix = new Matrix();
            float scaleWidth = ((float) width / w);
            float scaleHeight = ((float) height / h);
            matrix.postScale(scaleWidth, scaleHeight);
            newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
            bitmap.recycle();
        } else {
            newbmp = bitmap;
        }

        return newbmp;
    }

    /**
     * Resize the drawable
     *
     * @param drawable
     * @param w
     * @param h
     * @return
     */
    public static Drawable zoomDrawable(Drawable drawable, int w, int h) {
        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap oldbmp = drawableToBitmap(drawable);
        Matrix matrix = new Matrix();
        float sx = ((float) w / width);
        float sy = ((float) h / height);
        matrix.postScale(sx, sy);
        Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
                matrix, true);
        return new BitmapDrawable(newbmp);
    }

    /**
     * Get images from SD card by path and the name of image
     *
     * @param photoName
     * @return
     */
    public static Bitmap getPhotoFromSDCard(String path, String photoName) {
        Bitmap photoBitmap = BitmapFactory.decodeFile(path + "/" + photoName
                + ".png");
        if (photoBitmap == null) {
            return null;
        } else {
            return photoBitmap;
        }
    }

    public static Bitmap getPhotoFromSDCard(String path) {
        Bitmap photoBitmap = BitmapFactory.decodeFile(path);
        if (photoBitmap == null) {
            return null;
        } else {
            return photoBitmap;
        }
    }

    /**
     * Check the SD card
     *
     * @return
     */
    public static boolean checkSDCardAvailable() {
        return android.os.Environment.getExternalStorageState().equals(
                android.os.Environment.MEDIA_MOUNTED);
    }

    /**
     * Get image from SD card by path and the name of image
     *
     * @param path
     * @return
     */
    public static boolean findPhotoFromSDCard(String path, String photoName) {
        boolean flag = false;

        if (checkSDCardAvailable()) {
            File dir = new File(path);
            if (dir.exists()) {
                File folders = new File(path);
                File photoFile[] = folders.listFiles();
                for (int i = 0; i < photoFile.length; i++) {
                    String fileName = photoFile[i].getName().split("\\.")[0];
                    if (fileName.equals(photoName)) {
                        flag = true;
                    }
                }
            } else {
                flag = false;
            }
            // File file = new File(path + "/" + photoName + ".jpg" );
            // if (file.exists()) {
            // flag = true;
            // }else {
            // flag = false;
            // }

        } else {
            flag = false;
        }
        return flag;
    }

    /**
     * Save image to the SD card
     *
     * @param photoBitmap
     * @param photoName
     * @param path
     */
    public static void savePhotoToSDCard(Bitmap photoBitmap, String path,
                                         String photoName) {
        if (checkSDCardAvailable()) {
            File dir = new File(path);
            if (!dir.exists()) {
                dir.mkdirs();
            }

            File photoFile = new File(path, photoName);
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(photoFile);
                if (photoBitmap != null) {
                    if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100,
                            fileOutputStream)) {
                        fileOutputStream.flush();
                        // fileOutputStream.close();
                    }
                }
            } catch (FileNotFoundException e) {
                photoFile.delete();
                e.printStackTrace();
            } catch (IOException e) {
                photoFile.delete();
                e.printStackTrace();
            } finally {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Delete the image from SD card
     *
     * @param path
     *            file:///sdcard/temp.jpg
     */
    public static void deleteAllPhoto(String path) {
        if (checkSDCardAvailable()) {
            File folder = new File(path);
            File[] files = folder.listFiles();
            for (int i = 0; i < files.length; i++) {
                files[i].delete();
            }
        }
    }

    public static void deletePhotoAtPathAndName(String path, String fileName) {
        if (checkSDCardAvailable()) {
            File folder = new File(path);
            File[] files = folder.listFiles();
            for (int i = 0; i < files.length; i++) {
                LogUtil.d("libImageTools", files[i].getName());
                if (files[i].getName().equals(fileName)) {
                    files[i].delete();
                }
            }
        }
    }

    public static Bitmap getBitmap(String localStr){
        Bitmap photoBitmap = BitmapFactory.decodeFile(localStr);
        return photoBitmap;
    }

    public static Bitmap getImagesFromSDCard(String path, String photoName) {
        Bitmap photoBitmap = BitmapFactory.decodeFile(path.concat(photoName));
        if (photoBitmap == null) {
            return null;
        } else {
            return compressBitmap(path.concat(photoName));
        }
    }

    public static Bitmap compressBitmap(String photoPath) {
        BitmapFactory.Options newOpts = new BitmapFactory.Options();
        // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
        newOpts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(photoPath, newOpts);// 此时返回bm为空

        newOpts.inJustDecodeBounds = false;
        int w = newOpts.outWidth;
        int h = newOpts.outHeight;
        // 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
        float hh = 320f;// 这里设置高度为800f
        float ww = 240f;// 这里设置宽度为480f
        // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
        int be = 1;// be=1表示不缩放
        if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
            be = (int) (newOpts.outWidth / ww);
        } else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放
            be = (int) (newOpts.outHeight / hh);
        }
        if (be <= 0)
            be = 1;
        newOpts.inSampleSize = be;// 2;// 设置缩放比例 width,hight设为原来的十分一
        // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
        bitmap = BitmapFactory.decodeFile(photoPath, newOpts);

        // BitmapFactory.Options options = new BitmapFactory.Options();
        // options.inJustDecodeBounds = true;
        // Bitmap bitmap = BitmapFactory.decodeFile(photoPath, options);
        // //此时返回bm为空
        // options.inJustDecodeBounds = false;
        // //缩放比
        // int be = (int)(options.outHeight / (float)200);
        // if (be <= 0)
        // be = 1;
        // options.inSampleSize = be;
        // //重新读入图片,注意这次要把options.inJustDecodeBounds 设为 false哦
        // bitmap=BitmapFactory.decodeFile(photoPath,options);
        return bitmap;// compressImage(bitmap);

    }


    public static DisplayImageOptions getChatDisplayImageOptions() {
        return mChatDiaplayOptions;
    }

    static DisplayImageOptions mChatDiaplayOptions = new DisplayImageOptions.Builder()
            .cacheInMemory(true)// 设置下载的图片是否缓存在内存中
            .cacheOnDisk(true)// 设置下载的图片是否缓存在SD卡中
            .considerExifParams(true) // 是否考虑JPEG图像EXIF参数(旋转,翻转)
            .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)// 设置图片以如何的编码方式显示
            .bitmapConfig(Bitmap.Config.RGB_565)// 设置图片的解码类型//
            .displayer(new FadeInBitmapDisplayer(500))
            .build();

    public static DisplayImageOptions.Builder getChatDisplayImageOptionsBuilder() {
        return new DisplayImageOptions.Builder().cacheInMemory(true)// 设置下载的图片是否缓存在内存中
                .cacheOnDisk(true)// 设置下载的图片是否缓存在SD卡中
                .considerExifParams(true) // 是否考虑JPEG图像EXIF参数(旋转,翻转)
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)// 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.RGB_565)// 设置图片的解码类型//
                .displayer(new FadeInBitmapDisplayer(500));
    }
}
作者 east

1 2 3 下一个

标签

flex布局 github mysql O2O UI控件 不含后台 交流 体育 共享经济 出行 单机类 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 旅游 日历 时钟 流量主 物流 用户系统 电商 画图 画布(canvas) 社交 签到 算命 联网 装修 解锁 评论 读书 读音 资讯 阅读 预订

关注公众号“康波之道”回复“小程序”获取1000个小程序打包源码

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • 微信小程序语音识别、语音合成(微信同声传译)使用代码实例
  • 切换城市微信小程序代码
  • 辩论倒计时微信小程序源码
  • 东航订机票微信小程序源码
  • 仿车源宝微信小程序代码
  • 语音跟读微信小程序代码
  • 各国货币汇率微信小程序源代码
  • 仿小红书购物推荐微信小程序
  • 带富文本解析折线图的财经微信小程序
  • 摇一摇切换文章微信小程序代码

文章归档

  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年7月
  • 2018年6月

分类目录

  • Android (34)
  • bug清单 (63)
  • Fuchsia (15)
  • php (2)
  • python (6)
  • 人工智能 (4)
  • 大数据开发 (160)
    • Elasticsearch (12)
    • Flink (9)
    • flume (3)
    • Hadoop (11)
    • Hbase (12)
    • Hive (4)
    • Java (31)
    • Kafka (3)
    • shardingsphere (3)
    • solr (2)
    • Spark (47)
    • spring (8)
    • 数据仓库 (1)
    • 数据挖掘 (5)
    • 运维 (8)
  • 小游戏代码 (1)
  • 小程序代码 (133)
    • O2O (16)
    • UI控件 (4)
    • 互联网类 (22)
    • 企业类 (5)
    • 地图定位 (9)
    • 多媒体 (6)
    • 工具类 (23)
    • 电商类 (21)
    • 社交 (7)
    • 行业软件 (7)
    • 资讯读书 (11)
  • 开发博客 (6)
  • 技术架构 (4)
  • 数据库 (2)
  • 未分类 (5)
  • 程序员网赚 (1)

功能

  • 登录
  • 文章RSS
  • 评论RSS
  • WordPress.org

All Rights Reserved by Gitweixin.本站收集网友上传代码, 如有侵犯版权,请发邮件联系yiyuyos@gmail.com删除.