gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Elasticsearch
    • Kafka
    • Flink
    • 数据仓库
    • 数据挖掘
    • flume
    • Kafka
    • Hive
    • shardingsphere
    • solr
  • 开发博客
    • Android
    • php
    • python
    • 运维
    • 技术架构
    • 数据库
  • 程序员网赚
  • bug清单
  • 量化投资
  • 在线查询工具
    • 去行号
    • 在线时间戳转换工具
    • 免费图片批量修改尺寸在线工具
    • SVG转JPG在线工具

Android记录文件日志工具类

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

  • 首页   /  
  • 作者: east
  • ( 页面69 )
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
Android 12月 11,2020

Android倒计时工具类

public abstract class TimeDownUtil {
    private final String TAG = getClass().getSimpleName();

    private long mCountDownInterval = 1000;
    private Timer mTimer;
    private TimerTask mTimerTask;

    /**
     * 时钟回调的次数
     */
    private int mCount = 0;

    /**
     * 倒计时时间,默认间隔单位为秒
     *
     * @param time 毫秒
     */
    public TimeDownUtil(final long time) {
        initTimer(time);
    }

    private void initTimer(long time) {
        mTimer = new Timer();
        mCount = (int) (time / mCountDownInterval);
        LogUtil.w(TAG, "count = " + mCount);
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                LogUtil.w(TAG, "mCount = " + mCount);
                if (mCount > 0) {
                    mCount--;
                    onTick(mCountDownInterval * mCount);
                } else {
                    onFinish();
                    cancel();
                }
            }
        };
    }

    /**
     * 倒计时时间,默认单位为秒
     *
     * @param time
     * @param countDownInterval 间隔时间,1000为1s
     */
    public TimeDownUtil(long time, long countDownInterval) {
        mCountDownInterval = countDownInterval;
        initTimer(time);
    }

    public void start() {
        mTimer.schedule(mTimerTask, 0, mCountDownInterval);
    }

    /**
     * Callback fired on regular interval.
     *
     * @param millisUntilFinished 距离结束还有多少时间
     */
    public abstract void onTick(long millisUntilFinished);

    /**
     * 倒计时结束的回调
     */
    public abstract void onFinish();

    public void cancel() {
        mTimer.cancel();
        mTimerTask.cancel();
    }


}
作者 east
Android 12月 11,2020

Android压缩解压工具


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class ZipUtil {
	private static final int BUFF_SIZE = 1024 * 1024; // 1M Byte
	
	/**
	 * 批量压缩文件(夹)
	 * 
	 * @param resFileList
	 *            要压缩的文件(夹)列表
	 * @param zipFile
	 *            生成的压缩文件
	 * @throws IOException
	 *             当压缩过程出错时抛出
	 */
	public static void zipFiles(Collection<File> resFileList, File zipFile)
			throws IOException {
		FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
		BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(
				fileOutputStream, BUFF_SIZE);
		ZipOutputStream zipout = new ZipOutputStream(bufferedOutputStream);

		for (File resFile : resFileList) {
			zipFile(resFile, zipout, "");
		}
		zipout.close();
	}

	/**
	 * 批量压缩文件(夹)
	 * 
	 * @param resFileList
	 *            要压缩的文件(夹)列表
	 * @param zipFile
	 *            生成的压缩文件
	 * @param comment
	 *            压缩文件的注释
	 * @throws IOException
	 *             当压缩过程出错时抛出
	 */
	public static void zipFiles(Collection<File> resFileList, File zipFile,
			String comment) throws IOException {
		ZipOutputStream zipout = new ZipOutputStream(new BufferedOutputStream(
				new FileOutputStream(zipFile), BUFF_SIZE));
		for (File resFile : resFileList) {
			zipFile(resFile, zipout, "");
		}
		zipout.setComment(comment);
		zipout.close();
	}

	/**
	 * 解压缩一个文件
	 * 
	 * @param zipFile
	 *            压缩文件
	 * @param folderPath
	 *            解压缩的目标目录
	 * @throws IOException
	 *             当解压缩过程出错时抛出
	 */
	public static void upZipFile(File zipFile, String folderPath)
			throws ZipException, IOException {
		File desDir = new File(folderPath);
		if (!desDir.exists()) {
			desDir.mkdirs();
		}
		
		ZipFile zf = new ZipFile(zipFile);
		for (Enumeration<?> entries = zf.entries(); entries.hasMoreElements();) {
			ZipEntry entry = ((ZipEntry) entries.nextElement());
			InputStream in = zf.getInputStream(entry);
			String str = folderPath + File.separator + entry.getName();
			str = new String(str.getBytes("8859_1"), "GB2312");
			File desFile = new File(str);
			if (!desFile.exists()) {
				File fileParentDir = desFile.getParentFile();
				if (!fileParentDir.exists()) {
					fileParentDir.mkdirs();
				}
				desFile.createNewFile();
			}
			OutputStream out = new FileOutputStream(desFile);
			byte buffer[] = new byte[BUFF_SIZE];
			int realLength;
			while ((realLength = in.read(buffer)) > 0) {
				out.write(buffer, 0, realLength);
			}
			in.close();
			out.close();
		}
	}

	/**
	 * 解压文件名包含传入文字的文件
	 * 
	 * @param zipFile
	 *            压缩文件
	 * @param folderPath
	 *            目标文件夹
	 * @param nameContains
	 *            传入的文件匹配名
	 * @throws ZipException
	 *             压缩格式有误时抛出
	 * @throws IOException
	 *             IO错误时抛出
	 */
	public static ArrayList<File> upZipSelectedFile(File zipFile,
			String folderPath, String nameContains) throws ZipException,
			IOException {
		ArrayList<File> fileList = new ArrayList<File>();

		File desDir = new File(folderPath);
		if (!desDir.exists()) {
			desDir.mkdir();
		}

		ZipFile zf = new ZipFile(zipFile);
		for (Enumeration<?> entries = zf.entries(); entries.hasMoreElements();) {
			ZipEntry entry = ((ZipEntry) entries.nextElement());
			if (entry.getName().contains(nameContains)) {
				InputStream in = zf.getInputStream(entry);
				String str = folderPath + File.separator + entry.getName();
				str = new String(str.getBytes("8859_1"), "GB2312");
				// str.getBytes("GB2312"),"8859_1" 输出
				// str.getBytes("8859_1"),"GB2312" 输入
				File desFile = new File(str);
				if (!desFile.exists()) {
					File fileParentDir = desFile.getParentFile();
					if (!fileParentDir.exists()) {
						fileParentDir.mkdirs();
					}
					desFile.createNewFile();
				}
				OutputStream out = new FileOutputStream(desFile);
				byte buffer[] = new byte[BUFF_SIZE];
				int realLength;
				while ((realLength = in.read(buffer)) > 0) {
					out.write(buffer, 0, realLength);
				}
				in.close();
				out.close();
				fileList.add(desFile);
			}
		}
		return fileList;
	}

	/**
	 * 获得压缩文件内文件列表
	 * 
	 * @param zipFile
	 *            压缩文件
	 * @return 压缩文件内文件名称
	 * @throws ZipException
	 *             压缩文件格式有误时抛出
	 * @throws IOException
	 *             当解压缩过程出错时抛出
	 */
	public static ArrayList<String> getEntriesNames(File zipFile)
			throws ZipException, IOException {
		ArrayList<String> entryNames = new ArrayList<String>();
		Enumeration<?> entries = getEntriesEnumeration(zipFile);
		while (entries.hasMoreElements()) {
			ZipEntry entry = ((ZipEntry) entries.nextElement());
			entryNames.add(new String(getEntryName(entry).getBytes("GB2312"),
					"8859_1"));
		}
		return entryNames;
	}

	/**
	 * 获得压缩文件内压缩文件对象以取得其属性
	 * 
	 * @param zipFile
	 *            压缩文件
	 * @return 返回一个压缩文件列表
	 * @throws ZipException
	 *             压缩文件格式有误时抛出
	 * @throws IOException
	 *             IO操作有误时抛出
	 */
	public static Enumeration<?> getEntriesEnumeration(File zipFile)
			throws ZipException, IOException {
		ZipFile zf = new ZipFile(zipFile);
		return zf.entries();

	}

	/**
	 * 取得压缩文件对象的注释
	 * 
	 * @param entry
	 *            压缩文件对象
	 * @return 压缩文件对象的注释
	 * @throws UnsupportedEncodingException
	 */
	public static String getEntryComment(ZipEntry entry)
			throws UnsupportedEncodingException {
		return new String(entry.getComment().getBytes("GB2312"), "8859_1");
	}

	/**
	 * 取得压缩文件对象的名称
	 * 
	 * @param entry
	 *            压缩文件对象
	 * @return 压缩文件对象的名称
	 * @throws UnsupportedEncodingException
	 */
	public static String getEntryName(ZipEntry entry)
			throws UnsupportedEncodingException {
		return new String(entry.getName().getBytes("GB2312"), "8859_1");
	}

	/**
	 * 压缩文件
	 * 
	 * @param resFile
	 *            需要压缩的文件(夹)
	 * @param zipout
	 *            压缩的目的文件
	 * @param rootpath
	 *            压缩的文件路径
	 * @throws FileNotFoundException
	 *             找不到文件时抛出
	 * @throws IOException
	 *             当压缩过程出错时抛出
	 */
	private static void zipFile(File resFile, ZipOutputStream zipout,
			String rootpath) throws FileNotFoundException, IOException {
		rootpath = rootpath
				+ (rootpath.trim().length() == 0 ? "" : File.separator)
				+ resFile.getName();
		rootpath = new String(rootpath.getBytes("8859_1"), "GB2312");
		if (resFile.isDirectory()) {
			File[] fileList = resFile.listFiles();
			for (File file : fileList) {
				zipFile(file, zipout, rootpath);
			}
		} else {
			byte buffer[] = new byte[BUFF_SIZE];
			BufferedInputStream in = new BufferedInputStream(
					new FileInputStream(resFile), BUFF_SIZE);
			ZipEntry zipEntry = new ZipEntry(rootpath);
			zipEntry.setTime(resFile.lastModified());
			zipout.putNextEntry(zipEntry);
			int realLength;
			while ((realLength = in.read(buffer)) != -1) {
				zipout.write(buffer, 0, realLength);
			}
			in.close();
			zipout.flush();
			zipout.closeEntry();
		}
	}
}
作者 east
Android 12月 11,2020

Android高精确度的四则运算工具类


import java.math.BigDecimal;

/**
* 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精
* 确的浮点数运算,包括加减乘除和四舍五入。
*/
public class Arith { //默认除法运算精度
private static final int DEF_DIV_SCALE = 10; //这个类不能实例化

private Arith() {
}

/**
* 提供精确的加法运算。
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}

public static String add(String v1, String v2){
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2).stripTrailingZeros().toPlainString();
}

/**
* 提供精确的减法运算。
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}

public static String sub(String v1, String v2){
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.subtract(b2).stripTrailingZeros().toPlainString();
}

/**
* 提供精确的乘法运算。
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}

public static String mul(String v1, String v2){
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.multiply(b2).stripTrailingZeros().toPlainString();
}

/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
* 小数点以后10位,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}

/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入。
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}


public static String div(String v1, String v2, int scale){
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();
}

/**
* 提供精确的小数位四舍五入处理。
*
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
};
作者 east
Android 12月 11,2020

Android通用菜单项

public class MenuItemView extends RelativeLayout{
private TextView mTextView;
private TextView mLeftTextView;
private TextView mRightTextView;
private ImageView mImageView;
private ImageView mArrowIcon;
private CharSequence mTitle;
private CharSequence mRightText;
private int mTextColor;
private int mTextSize;
private int mIconResId;
private boolean mArrowVisibility;

public MenuItemView(Context context) {
    super(context);
    inflate(context, R.layout.widget_menu_item, this);
    initView();
}

public MenuItemView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public MenuItemView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    inflate(context, R.layout.widget_menu_item, this);

    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MenuItemView, defStyle, 0);
    mTitle = typedArray.getText(R.styleable.MenuItemView_text);
    mRightText = typedArray.getText(R.styleable.MenuItemView_rightText);
    mTextColor = typedArray.getColor(R.styleable.MenuItemView_textColor, 0);
    mTextSize = typedArray.getDimensionPixelSize(R.styleable.MenuItemView_textSize, 0);
    mIconResId = typedArray.getResourceId(R.styleable.MenuItemView_imageSrc, 0);
    mArrowVisibility = typedArray.getBoolean(R.styleable.MenuItemView_arrowVibility, true);
    typedArray.recycle();

    initView();
}

public void setArrowVisibility(int visibility) {
    mArrowIcon.setVisibility(visibility);
}

private void initView() {
    mTextView = (TextView) findViewById(R.id.menu_item_tv_title);
    mLeftTextView = (TextView) findViewById(R.id.menu_item_tv_left);
    mRightTextView = (TextView) findViewById(R.id.menu_item_tv_right);
    mImageView = (ImageView) findViewById(R.id.menu_item_iv_icon);
    mArrowIcon = (ImageView) findViewById(R.id.menu_item_iv_arrow);
    //标题
    mTextView.setText(mTitle);

    if (mIconResId != 0) {
        mImageView.setImageResource(mIconResId);
    }
    if (mTextColor != 0) {
        mTextView.setTextColor(mTextColor);
    }
    if (mTextSize != 0) {
        mTextView.setTextSize(mTextSize);
    }
    if (!mArrowVisibility) {
        mArrowIcon.setVisibility(View.GONE);
    }

    //右边文字
    if (mRightText != null) {
        mRightTextView.setVisibility(View.VISIBLE);
        mRightTextView.setText(mRightText);
    }
    this.setClickable(true);
}


public void setText(String text) {
    mTextView.setText(text);
}

public void setLeftText(String text) {
    //左边文字
    mLeftTextView.setVisibility(View.VISIBLE);
    mLeftTextView.setText(text);
}

public void setRightText(int resId) {
    //右边文字
    mRightTextView.setVisibility(View.VISIBLE);
    mRightTextView.setText(resId);
}

public void setRightText(String text) {
    //右边文字
    mRightTextView.setVisibility(View.VISIBLE);
    mRightTextView.setText(text);
}

public void setRightTextColor(int resId) {
    //右边文字
    mRightTextView.setVisibility(View.VISIBLE);
    mRightTextView.setTextColor(resId);
}


public void setRightTextVisibility(int visibility) {
    mRightTextView.setVisibility(visibility);
}

public void hideLeftText() {
    mLeftTextView.setVisibility(View.GONE);
}

}

<?xml version="1.0" encoding="utf-8"?><!-- 菜单item -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:paddingBottom="10dp"
    android:paddingTop="10dp">

    <ImageView
        android:id="@+id/menu_item_iv_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true" />

    <TextView
        android:id="@+id/menu_item_tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="@dimen/content_margin"
        android:layout_toRightOf="@+id/menu_item_iv_icon"
        android:textColor="@color/text_black"
        android:textSize="@dimen/text_size_4x" />


    <TextView
        android:id="@+id/menu_item_tv_left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@+id/menu_item_tv_title"
        android:textColor="@color/text_black"
        android:textSize="16sp"
        android:visibility="gone" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:gravity="center_vertical">

        <TextView
            android:id="@+id/menu_item_tv_right"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:textColor="@color/text_black"
            android:textSize="16sp"
            android:visibility="gone" />

        <ImageView
            android:id="@+id/menu_item_iv_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:src="@drawable/home_point_icon" />
    </LinearLayout>
</RelativeLayout>
作者 east
Android 12月 11,2020

Android自定义带未读信息红点TextView

public class RedPointTextView extends TextView {
private static final int DEFAULT_MIN_SIZE_DIP = 18; //最小尺寸
private static final int DEFAULT_TB_PADDING_DIP = 3; //上下边距
private static final int DEFAULT_LR_PADDING_DIP = 6; //左右边距
private static final int DEFAULT_TEXT_SIZE = 11; //dp
private static final int DEFAULT_TEXT_COLOR = Color.WHITE;
private int mLeftPadding;
private int mTopPadding;
private int mMinSize;

public RedPointTextView(Context context) {
    super(context);
    init();
}

public RedPointTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public RedPointTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init() {
    mLeftPadding = dipToPixels(DEFAULT_LR_PADDING_DIP);
    mTopPadding = dipToPixels(DEFAULT_TB_PADDING_DIP);
    mMinSize = dipToPixels(DEFAULT_MIN_SIZE_DIP);

    setIncludeFontPadding(false);
    setGravity(Gravity.CENTER);
    setMinWidth(mMinSize);
    setMinHeight(mMinSize);
    setTextColor(DEFAULT_TEXT_COLOR);
    setTextSize(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_TEXT_SIZE);
    setBackgroundResource(R.drawable.shape_oval_pink);
    setVisibility(View.GONE);
}

private int dipToPixels(int dip) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
}

public void setUnreadCount(int count) {
    if (count <= 0) {
        setVisibility(GONE);
    } else {
        setVisibility(GONE);
        if (count < 10) {
            setPadding(0, 0, 0, 0);
        } else {
            setPadding(mLeftPadding, mTopPadding, mLeftPadding, mTopPadding);
        }
        if (count > 99) {
            setText("99+");
        } else {
            setText(String.valueOf(count));
        }
    }
}

}

作者 east
Android 12月 11,2020

Android自定义富文本控件

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Parcel;
import android.support.annotation.IntDef;
import android.support.annotation.IntRange;
import android.support.annotation.Nullable;
import android.text.Html;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.method.Touch;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.text.style.URLSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import pl.droidsonroids.gif.GifDrawable;

public class RichTextView extends GifSpanTextView implements Drawable.Callback, View.OnAttachStateChangeListener {

private static Pattern IMAGE_TAG_PATTERN = Pattern.compile("\\<img(.*?)\\>");
private static Pattern IMAGE_WIDTH_PATTERN = Pattern.compile("width=\"(.*?)\"");
private static Pattern IMAGE_HEIGHT_PATTERN = Pattern.compile("height=\"(.*?)\"");
private static Pattern IMAGE_SRC_PATTERN = Pattern.compile("src=\"(.*?)\"");
private static Pattern IMAGE_BIG_SRC_PATTERN = Pattern.compile("bigsrc=\"(.*?)\"");
private static Pattern IMAGE_HREF_PATTERN = Pattern.compile("href=\"(.*?)\"");

private Drawable placeHolder, errorImage;//占位图,错误图
private OnImageClickListener onImageClickListener;//图片点击回调
private OnURLClickListener onURLClickListener;//超链接点击回调
//    private HashSet<Target> targets;

// private HashSet targets;
private HashMap mImages;
private HashMap mBigImages;
private ImageFixListener mImageFixListener;
private int d_w = 200;
private int d_h = 100;
private boolean isScroll = true;

private String imageHost;
private boolean dontConsumeNonUrlClicks = true;
private boolean linkHit;
private Context mContext;
private GlideImageGeter glideImageGeter;

public RichTextView(Context context) {
    this(context, null);
}

public RichTextView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public RichTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    init(context, attrs);
}

private void init(Context context, AttributeSet attrs) {
    mContext = context;
 //   targets = new HashSet<>();
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RichTextView);
    placeHolder = typedArray.getDrawable(R.styleable.RichTextView_placeHolder);
    errorImage = typedArray.getDrawable(R.styleable.RichTextView_errorImage);

    d_w = typedArray.getDimensionPixelSize(R.styleable.RichTextView_defaultWidth, Utils.Dp2Px(context, d_w));
    d_h = typedArray.getDimensionPixelSize(R.styleable.RichTextView_defaultHeight, Utils.Dp2Px(context, d_h));

    isScroll = typedArray.getBoolean(R.styleable.RichTextView_isScroll, isScroll);

    if (placeHolder == null) {
        placeHolder = new ColorDrawable(Color.GRAY);
    }
    placeHolder.setBounds(0, 0, d_w, d_h);
    if (errorImage == null) {
        errorImage = new ColorDrawable(Color.GRAY);
    }
    errorImage.setBounds(0, 0, d_w, d_h);
    typedArray.recycle();
}


/**
 * 设置富文本
 *
 * @param text 富文本
 */
public void setRichText(String text) {
    try {
        glideImageGeter = new GlideImageGeter(getContext(), this);
     //   targets.clear();
        matchImages(text);

        if (text != null) {
            text = text.replaceAll(" ", "\t");  //替换空格
        }
        Spanned spanned = Html.fromHtml(text, glideImageGeter, null);
        SpannableStringBuilder spannableStringBuilder;
        if (spanned instanceof SpannableStringBuilder) {
            spannableStringBuilder = (SpannableStringBuilder) spanned;
        } else {
            spannableStringBuilder = new SpannableStringBuilder(spanned);
        }

        // 处理图片得点击事件
        ImageSpan[] imageSpans = spannableStringBuilder.getSpans(0, spannableStringBuilder.length(), ImageSpan.class);
        final List<String> imageUrls = new ArrayList<>();

        for (int i = 0, size = imageSpans.length; i < size; i++) {
            ImageSpan imageSpan = imageSpans[i];
            String imageUrl = imageSpan.getSource();
            String bigImageUrl = mBigImages.get(imageUrl);
            if (!TextUtils.isEmpty(bigImageUrl)) {
                imageUrl = bigImageUrl;
            }
            int start = spannableStringBuilder.getSpanStart(imageSpan);
            int end = spannableStringBuilder.getSpanEnd(imageSpan);
            imageUrl = imageUrl.startsWith("http") ? imageUrl : imageHost + imageUrl;
            if (imageUrl.endsWith(".gif") || imageUrl.endsWith(".bmp") || imageUrl.endsWith(".jpg") || imageUrl.endsWith(".jpeg") || imageUrl.endsWith(".JPG") || imageUrl.endsWith(".JPEG") || imageUrl.endsWith(".png") || imageUrl.endsWith(".PNG")) {
                imageUrls.add(imageUrl);
            }
            final int finalI = i;
            ClickableSpan clickableSpan = new ClickableSpan() {
                @Override
                public void onClick(View widget) {
                    if (onImageClickListener != null) {
                        onImageClickListener.imageClicked(imageUrls, finalI);
                    }
                }
            };
            ClickableSpan[] clickableSpans = spannableStringBuilder.getSpans(start, end, ClickableSpan.class);
            if (clickableSpans != null && clickableSpans.length != 0) {
                for (ClickableSpan cs : clickableSpans) {
                    spannableStringBuilder.removeSpan(cs);
                }
            }
            spannableStringBuilder.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        // 处理超链接点击事件
        URLSpan[] urlSpans = spannableStringBuilder.getSpans(0, spannableStringBuilder.length(), URLSpan.class);

        for (int i = 0, size = urlSpans == null ? 0 : urlSpans.length; i < size; i++) {
            URLSpan urlSpan = urlSpans[i];

            int start = spannableStringBuilder.getSpanStart(urlSpan);
            int end = spannableStringBuilder.getSpanEnd(urlSpan);

            spannableStringBuilder.removeSpan(urlSpan);
            spannableStringBuilder.setSpan(new CallableURLSpan(urlSpan.getURL(), onURLClickListener), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

        //表情转义
        final Matcher matcher = EmojiHelper.getInstance().getEmojiMatcher(spanned.toString());

        while (matcher.find()) {
            final String name = matcher.group(1);

            final GifDrawable drawable = EmojiHelper.getInstance().getGifDrawable(name);
            if (drawable != null) {
                final ImageSpan gifSpan = new GifImageSpan(drawable);
                spannableStringBuilder.setSpan(gifSpan, matcher.start(), matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }

        super.setText(spanned);
        if (isScroll) {
            setMovementMethod(LocalLinkMovementMethod.getInstance());    //解决ListView里TextView设置LinkMovementMethod后导致其ItemClick失效的问题
        }
        setLongClickable(false);    //屏蔽长按事件,防止部分手机Spannable长按时崩溃
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

/*
private void addTarget(ImageTarget target) {
targets.add(target);
}
/ /*
* 从文本中拿到标签,并获取图片url和宽高
*/
private void matchImages(String text) {
mImages = new HashMap<>();
mBigImages = new HashMap<>();
ImageHolder holder;
Matcher imageMatcher, srcMatcher, bigSrcMatcher, widthMatcher, heightMatcher, hrefMatcher;
int position = 0;
hrefMatcher = IMAGE_HREF_PATTERN.matcher(text);
String hrefImageUrl = null;
if (hrefMatcher.find()) {
hrefImageUrl = getTextBetweenQuotation(hrefMatcher.group().trim().substring(4));
}
imageMatcher = IMAGE_TAG_PATTERN.matcher(text);
while (imageMatcher.find()) {
String image = imageMatcher.group().trim();
srcMatcher = IMAGE_SRC_PATTERN.matcher(image);
String src = null;
if (srcMatcher.find()) {
src = getTextBetweenQuotation(srcMatcher.group().trim().substring(4));
}
if (TextUtils.isEmpty(src)) {
continue;
}
bigSrcMatcher = IMAGE_BIG_SRC_PATTERN.matcher(image);
String bigSrc = null;
if (bigSrcMatcher.find()) {
bigSrc = getTextBetweenQuotation(bigSrcMatcher.group().trim().substring(4));
}
if (TextUtils.isEmpty(bigSrc)) {
if (!TextUtils.isEmpty(hrefImageUrl)) {
bigSrc = hrefImageUrl;
} else {
bigSrc = src;
}
}

        holder = new ImageHolder(src, bigSrc, position);
        widthMatcher = IMAGE_WIDTH_PATTERN.matcher(image);
        if (widthMatcher.find()) {
            holder.width = parseStringToInteger(getTextBetweenQuotation(widthMatcher.group().trim().substring(6)));
        }

        heightMatcher = IMAGE_HEIGHT_PATTERN.matcher(image);
        if (heightMatcher.find()) {
            holder.height = parseStringToInteger(getTextBetweenQuotation(heightMatcher.group().trim().substring(6)));
        }

        mImages.put(holder.src, holder);
        mBigImages.put(holder.src, holder.bigSrc);
        position++;
    }
}

private int parseStringToInteger(String integerStr) {
    int result = -1;
    if (!TextUtils.isEmpty(integerStr)) {
        try {
            result = Integer.parseInt(integerStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return result;
}

/**
 * 从双引号之间取出字符串
 */
@Nullable
private static String getTextBetweenQuotation(String text) {
    Pattern pattern = Pattern.compile("\"(.*?)\"");
    Matcher matcher = pattern.matcher(text);
    if (matcher.find()) {
        return matcher.group(1);
    }
    return null;
}

  


@Override
public boolean onTouchEvent(MotionEvent event) {
linkHit = false;
boolean res = super.onTouchEvent(event);

    if (dontConsumeNonUrlClicks)
        return linkHit;
    return res;

}

public static class LocalLinkMovementMethod extends LinkMovementMethod {
    static LocalLinkMovementMethod sInstance;


    public static LocalLinkMovementMethod getInstance() {
        if (sInstance == null)
            sInstance = new LocalLinkMovementMethod();

        return sInstance;
    }


    @Override
    public boolean onTouchEvent(TextView widget,
                                Spannable buffer, MotionEvent event) {
        int action = event.getAction();

        if (action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_DOWN) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            x -= widget.getTotalPaddingLeft();
            y -= widget.getTotalPaddingTop();

            x += widget.getScrollX();
            y += widget.getScrollY();

            Layout layout = widget.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            ClickableSpan[] link = buffer.getSpans(
                    off, off, ClickableSpan.class);

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    link[0].onClick(widget);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(link[0]),
                            buffer.getSpanEnd(link[0]));
                }

                if (widget instanceof RichTextView) {
                    ((RichTextView) widget).linkHit = true;
                }
                return true;

            } else {
                Selection.removeSelection(buffer);
                Touch.onTouchEvent(widget, buffer, event);
                return false;
            }
        }
        return Touch.onTouchEvent(widget, buffer, event);
    }
}


private static final class URLDrawable extends Drawable {
    private Drawable drawable;

    @Override
    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {

    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return 0;
    }

    @Override
    public void draw(Canvas canvas) {
        if (drawable != null)
            drawable.draw(canvas);
    }

    public void setDrawable(Drawable drawable) {
        this.drawable = drawable;
    }
}

private static class CallableURLSpan extends URLSpan {

    private OnURLClickListener onURLClickListener;

    public CallableURLSpan(String url, OnURLClickListener onURLClickListener) {
        super(url);
        this.onURLClickListener = onURLClickListener;
    }

    @SuppressWarnings("unused")
    public CallableURLSpan(Parcel src, OnURLClickListener onURLClickListener) {
        super(src);
        this.onURLClickListener = onURLClickListener;
    }

    @Override
    public void onClick(View widget) {
        if (onURLClickListener != null && onURLClickListener.urlClicked(getURL())) {
            return;
        }
        super.onClick(widget);
    }
}

public static class ImageHolder {
    public static final int DEFAULT = 0;
    public static final int CENTER_CROP = 1;
    public static final int CENTER_INSIDE = 2;

    @IntDef({DEFAULT, CENTER_CROP, CENTER_INSIDE})
    public @interface ScaleType {
    }

    private final String src;
    private final String bigSrc;
    private final int position;
    private int width = -1, height = -1;
    private int scaleType = DEFAULT;

    public ImageHolder(String src, String bigSrc, int position) {
        this.src = src;
        this.bigSrc = bigSrc;
        this.position = position;
    }

    public String getSrcUrl() {
        return src;
    }

    public String getBigSrcUrl() {
        return bigSrc;
    }

    public int getHeight() {
        return height;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    @ScaleType
    public int getScaleType() {
        return scaleType;
    }

    public void setScaleType(@ScaleType int scaleType) {
        this.scaleType = scaleType;
    }
}

@SuppressWarnings("unused")
public ImageHolder getImageHolder(String url) {
    return mImages.get(url);
}

@SuppressWarnings("unused")
public void setPlaceHolder(Drawable placeHolder) {
    this.placeHolder = placeHolder;
    this.placeHolder.setBounds(0, 0, d_w, d_h);
}

@SuppressWarnings("unused")
public void setErrorImage(Drawable errorImage) {
    this.errorImage = errorImage;
    this.errorImage.setBounds(0, 0, d_w, d_h);
}

public void setOnImageClickListener(OnImageClickListener onImageClickListener) {
    this.onImageClickListener = onImageClickListener;
}

public void setImageFixListener(ImageFixListener mImageFixListener) {
    this.mImageFixListener = mImageFixListener;
}

/**
 * 设置超链接点击回调事件(需在setRichText方法之前调用)
 *
 * @param onURLClickListener 回调
 */
public void setOnURLClickListener(OnURLClickListener onURLClickListener) {
    this.onURLClickListener = onURLClickListener;
}

@Override
public void onViewAttachedToWindow(View v) {

}

@Override
public void onViewDetachedFromWindow(View v) {
    glideImageGeter.recycle();
}

public interface OnImageClickListener {
    /**
     * 图片被点击后的回调方法
     *
     * @param imageUrls 本篇富文本内容里的全部图片
     * @param position  点击处图片在imageUrls中的位置
     */
    void imageClicked(List<String> imageUrls, int position);
}

public interface OnURLClickListener {

    /**
     * 超链接点击得回调方法
     *
     * @param url 点击得url
     * @return true:已处理,false:未处理(会进行默认处理)
     */
    boolean urlClicked(String url);
}

public interface ImageFixListener {
    /**
     * 修复图片尺寸的方法
     *
     * @param holder ImageHolder对象
     */
    void onFix(ImageHolder holder);

}

public void configure(String imageHostPrefix) {
    imageHost = imageHostPrefix;
}

}

作者 east
Android 12月 11,2020

Android身份证合法性校验工具类



import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
* <p>
* 身份证合法性校验
* </p>
*
* <pre>
* --15位身份证号码:第7、8位为出生年份(两位数),第9、10位为出生月份,第11、12位代表出生日期,第15位代表性别,奇数为男,偶数为女。
* --18位身份证号码:第7、8、9、10位为出生年份(四位数),第11、第12位为出生月份,第13、14位代表出生日期,第17位代表性别,奇数为男,偶数为女。
* 最后一位为校验位
* </pre>
*
*
@author
*/

public class IdcardValidator {
/**
* <pre>
* 省、直辖市代码表:
* 11 : 北京 12 : 天津 13 : 河北 14 : 山西 15 : 内蒙古
* 21 : 辽宁 22 : 吉林 23 : 黑龙江 31 : 上海 32 : 江苏
* 33 : 浙江 34 : 安徽 35 : 福建 36 : 江西 37 : 山东
* 41 : 河南 42 : 湖北 43 : 湖南 44 : 广东 45 : 广西 46 : 海南
* 50 : 重庆 51 : 四川 52 : 贵州 53 : 云南 54 : 西藏
* 61 : 陕西 62 : 甘肃 63 : 青海 64 : 宁夏 65 : 新疆
* 71 : 台湾
* 81 : 香港 82 : 澳门
* 91 : 国外
* </pre>
*/
private static String cityCode[] = { "11", "12", "13", "14", "15", "21",
"22", "23", "31", "32", "33", "34", "35", "36", "37", "41", "42",
"43", "44", "45", "46", "50", "51", "52", "53", "54", "61", "62",
"63", "64", "65", "71", "81", "82", "91" };

/**
* 每位加权因子
*/
private static int power[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5,
8, 4, 2 };

/**
* 验证所有的身份证的合法性
*
*
@param idcard
* 身份证
*
@return 合法返回true,否则返回false
*/
public static boolean isValidatedAllIdcard(String idcard) {
if (idcard == null || "".equals(idcard)) {
return false;
}
if (idcard.length() == 15) {
return validate15IDCard(idcard);
}
return validate18Idcard(idcard);
}

/**
* <p>
* 判断18位身份证的合法性
* </p>
* 根据〖中华人民共和国国家标准GB11643-1999〗中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。
* 排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
* <p>
* 顺序码: 表示在同一地址码所标识的区域范围内,对同年、同月、同 日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配 给女性。
* </p>
* <p>
* 1.前1、2位数字表示:所在省份的代码; 2.第3、4位数字表示:所在城市的代码; 3.第5、6位数字表示:所在区县的代码;
* 4.第7~14位数字表示:出生年、月、日; 5.第15、16位数字表示:所在地的派出所的代码;
* 6.第17位数字表示性别:奇数表示男性,偶数表示女性;
* 7.第18位数字是校检码:也有的说是个人信息码,一般是随计算机的随机产生,用来检验身份证的正确性。校检码可以是0~9的数字,有时也用x表示。
* </p>
* <p>
* 第十八位数字(校验码)的计算方法为: 1.将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7 9 10 5 8 4
* 2 1 6 3 7 9 10 5 8 4 2
* </p>
* <p>
* 2.将这17位数字和系数相乘的结果相加。
* </p>
* <p>
* 3.用加出来和除以11,看余数是多少
* </p>
* 4.余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3
* 2。
* <p>
* 5.通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。
* </p>
*
*
@param idcard
* @return
*/
public static boolean validate18Idcard(String idcard) {
if (idcard == null) {
return false;
}

// 非18位为假
if (idcard.length() != 18) {
return false;
}
// 获取前17位
String idcard17 = idcard.substring(0, 17);

// 前17位全部为数字
if (!isDigital(idcard17)) {
return false;
}

String provinceid = idcard.substring(0, 2);
// 校验省份
if (!checkProvinceid(provinceid)) {
return false;
}

// 校验出生日期
String birthday = idcard.substring(6, 14);

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

try {
Date birthDate = sdf.parse(birthday);
String tmpDate = sdf.format(birthDate);
if (!tmpDate.equals(birthday)) {// 出生年月日不正确
return false;
}

} catch (ParseException e1) {

return false;
}

// 获取第18位
String idcard18Code = idcard.substring(17, 18);

char c[] = idcard17.toCharArray();

int bit[] = converCharToInt(c);

int sum17 = 0;

sum17 = getPowerSum(bit);

// 将和值与11取模得到余数进行校验码判断
String checkCode = getCheckCodeBySum(sum17);
if (null == checkCode) {
return false;
}
// 将身份证的第18位与算出来的校码进行匹配,不相等就为假
if (!idcard18Code.equalsIgnoreCase(checkCode)) {
return false;
}

return true;
}

/**
* 校验15位身份证
*
* <pre>
* 只校验省份和出生年月日
* </pre>
*
*
@param idcard
* @return
*/
public static boolean validate15IDCard(String idcard) {
if (idcard == null) {
return false;
}
// 非15位为假
if (idcard.length() != 15) {
return false;
}

// 15全部为数字
if (!isDigital(idcard)) {
return false;
}

String provinceid = idcard.substring(0, 2);
// 校验省份
if (!checkProvinceid(provinceid)) {
return false;
}

String birthday = idcard.substring(6, 12);

SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");

try {
Date birthDate = sdf.parse(birthday);
String tmpDate = sdf.format(birthDate);
if (!tmpDate.equals(birthday)) {// 身份证日期错误
return false;
}

} catch (ParseException e1) {

return false;
}

return true;
}

/**
* 将15位的身份证转成18位身份证
*
*
@param idcard
* @return
*/
public static String convertIdcarBy15bit(String idcard) {
if (idcard == null) {
return null;
}

// 非15位身份证
if (idcard.length() != 15) {
return null;
}

// 15全部为数字
if (!isDigital(idcard)) {
return null;
}

String provinceid = idcard.substring(0, 2);
// 校验省份
if (!checkProvinceid(provinceid)) {
return null;
}

String birthday = idcard.substring(6, 12);

SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");

Date birthdate = null;
try {
birthdate = sdf.parse(birthday);
String tmpDate = sdf.format(birthdate);
if (!tmpDate.equals(birthday)) {// 身份证日期错误
return null;
}

} catch (ParseException e1) {
return null;
}

Calendar cday = Calendar.getInstance();
cday.setTime(birthdate);
String year = String.valueOf(cday.get(Calendar.YEAR));

String idcard17 = idcard.substring(0, 6) + year + idcard.substring(8);

char c[] = idcard17.toCharArray();
String checkCode = "";

// 将字符数组转为整型数组
int bit[] = converCharToInt(c);

int sum17 = 0;
sum17 = getPowerSum(bit);

// 获取和值与11取模得到余数进行校验码
checkCode = getCheckCodeBySum(sum17);

// 获取不到校验位
if (null == checkCode) {
return null;
}
// 将前17位与第18位校验码拼接
idcard17 += checkCode;
return idcard17;
}

/**
* 校验省份
*
*
@param provinceid
* @return 合法返回TRUE,否则返回FALSE
*/
private static boolean checkProvinceid(String provinceid) {
for (String id : cityCode) {
if (id.equals(provinceid)) {
return true;
}
}
return false;
}

/**
* 数字验证
*
*
@param str
* @return
*/
private static boolean isDigital(String str) {
return str.matches("^[0-9]*$");
}

/**
* 将身份证的每位和对应位的加权因子相乘之后,再得到和值
*
*
@param bit
* @return
*/
private static int getPowerSum(int[] bit) {

int sum = 0;

if (power.length != bit.length) {
return sum;
}

for (int i = 0; i < bit.length; i++) {
for (int j = 0; j < power.length; j++) {
if (i == j) {
sum = sum + bit[i] * power[j];
}
}
}
return sum;
}

/**
* 将和值与11取模得到余数进行校验码判断
*
*
*
@param sum17
* @return 校验位
*/
private static String getCheckCodeBySum(int sum17) {
String checkCode = null;
switch (sum17 % 11) {
case 10:
checkCode = "2";
break;
case 9:
checkCode = "3";
break;
case 8:
checkCode = "4";
break;
case 7:
checkCode = "5";
break;
case 6:
checkCode = "6";
break;
case 5:
checkCode = "7";
break;
case 4:
checkCode = "8";
break;
case 3:
checkCode = "9";
break;
case 2:
checkCode = "x";
break;
case 1:
checkCode = "0";
break;
case 0:
checkCode = "1";
break;
}
return checkCode;
}

/**
* 将字符数组转为整型数组
*
*
@param c
* @return
* @throws NumberFormatException
*/
private static int[] converCharToInt(char[] c) throws NumberFormatException {
int[] a = new int[c.length];
int k = 0;
for (char temp : c) {
a[k++] = Integer.parseInt(String.valueOf(temp));
}
return a;
}

}
作者 east
Android 12月 9,2020

Android系统工具类

public class SystemUtils {

public static final Context appContext = BaseApplication.getInstance();

public static final String TAG = SystemUtils.class.getSimpleName();

/**
* FlyMe版本号
*/
public static final String FLY_ME_VERSION = getFlyMeVersion();
/**
* 云OS版本号
*/
public static final String YUN_OS_VERSION = getYunOSVersion();

/**
* 小米特别处理
*/
public static final String MIUI_VERSION = SystemUtils.getMiuiVersion();

public static final long FIRST_INSTALL_TIME = SystemUtils.getFirstInstallTime();

public static final long LAST_UPDATE_TIME = SystemUtils.getLastUpdateTime();


public static boolean isYunOS() {
return StringUtil.isNotEmpty(YUN_OS_VERSION);
}

/**
* @return
*/
public static boolean isMiui() {
return StringUtil.isNotEmpty(SystemUtils.MIUI_VERSION);
}

public static boolean isFlyMe() {
return StringUtil.isNotEmpty(SystemUtils.FLY_ME_VERSION);
}

public static String getYunOSVersion() {
return getSystemProperty("ro.yunos.version");
}

/**
* 判断是否flyme,并返回版本号
*
* @return
*/
public static String getFlyMeVersion() {
String display = getSystemProperty("ro.build.version.incremental");
Pattern p = Pattern.compile("Flyme_OS_([\\d\\.]+)");
Matcher m = p.matcher(display);
String version = "";
if (m.find()) {
version = m.group(1);
}
return version;
}

public static String getApplicationName() {
try {
PackageManager packageManager = null;
ApplicationInfo applicationInfo = null;
try {
packageManager = appContext.getPackageManager();
applicationInfo = packageManager.getApplicationInfo(appContext.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
applicationInfo = null;
}
String applicationName = (String) packageManager.getApplicationLabel(applicationInfo);
return applicationName;
}catch (Exception ex){
ex.printStackTrace();
return "";
}
}

public static String getMiuiVersion() {
return getSystemProperty("ro.miui.ui.version.name");
}


// 返回状态栏的高度
public static int getStatusBarHeight(Context ctx) {
int result = 0;
int resourceId = ctx.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = ctx.getResources().getDimensionPixelSize(resourceId);
}
return result;
}

public static void setViewTop(Context ctx, View view) {
int stHeight = SystemUtils.getStatusBarHeight(ctx);
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
params.setMargins(0, stHeight, 0, 0);
view.setLayoutParams(params);
}

/**
* 判断是否存在魅族的SmartBar
*
* @return
*/
public static boolean hasMeiZuSmartBar() {
try {
// 可用反射调用Build.hasSmartBar()
Method method = Class.forName("android.os.Build").getMethod("hasSmartBar");
return ((Boolean) method.invoke(null)).booleanValue();
} catch (Exception e) {
e.printStackTrace();
}

if (Build.DEVICE.equals("mx2")) {
return true;
} else if (Build.DEVICE.equals("mx") ||
Build.DEVICE.equals("m9")) {
return false;
}
return false;
}

public static String getDataDir() {
return appContext.getFilesDir().getParent() + "/";
}

public static boolean canReadExternalStorage() {
String state = Environment.getExternalStorageState();
return state.equals(Environment.MEDIA_MOUNTED) || state.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
}

public static boolean canWriteExternalStorage() {
String state = Environment.getExternalStorageState();
return state.equals(Environment.MEDIA_MOUNTED);
}

public static String getDeviceId() {
return BaseApplication.deviceId;
}

public static int getMyVersionCode(Context ctx) {
try {
return ctx.getPackageManager().getPackageInfo(
ctx.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "error", e);
return 1;
}
}

public static int getMyVersionCode() {
return getMyVersionCode(appContext);
}

/**
* 获取系统记录的首次安装时间
*
* @return
*/
public static long getFirstInstallTime() {
try {
return appContext.getPackageManager().getPackageInfo(appContext.getPackageName(), 0).firstInstallTime;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "error", e);
return 0;
}
}

/**
* 获取上次更新时间
*
* @return
*/
public static long getLastUpdateTime() {
try {
return appContext.getPackageManager().getPackageInfo(appContext.getPackageName(), 0).lastUpdateTime;
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "error", e);
return 0;
}
}

public static String getMyPackageName() {
return appContext.getPackageName();
}

public static String getMyVersion() {
return getMyVersion(appContext);
}

public static String getMyVersion(Context ctx) {
try {
PackageManager packageManager = ctx.getPackageManager();
// getPackageName()是你当前类的包名,0代表是获取版本信息
PackageInfo packInfo = packageManager.getPackageInfo(ctx.getPackageName(), 0);
return packInfo.versionName;
} catch (Exception e) {
// MobclickAgent.reportError(ctx, e);
}
return "";
}

public static String getMyVersionWithoutBuild() {
String versionName = SystemUtils.getMyVersion();
if (versionName.contains("." + SystemUtils.getMyVersionCode())) {
versionName = versionName.replace("." + SystemUtils.getMyVersionCode(), "");
}
return versionName;
}


private static long serviceBootTime = -1;

/**
* 获取服务运行时间
*
* @return
*/
public static long getServiceBootTime() {
return serviceBootTime;
}

public static void setServiceBootTime(long sbt) {
serviceBootTime = sbt;
}

public static void restartSelf() {
Intent intent = appContext.getPackageManager().getLaunchIntentForPackage(appContext.getPackageName());
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
appContext.startActivity(intent);
ActivitiesManager.getInstance().exit();
}

/**
* 服务运行时间
*
* @return
*/
public static long serviceElapsedTime() {
if (serviceBootTime < 0) {
return -1;
}
return System.currentTimeMillis() - serviceBootTime;
}

public static String getSystemProperty(String propName) {
String line = "";
BufferedReader reader = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + propName);
reader = new BufferedReader(new InputStreamReader(p.getInputStream()), 512);
line = reader.readLine();
} catch (IOException ex) {
Log.e(TAG, "Unable to read system property " + propName, ex);
} finally {
StreamUtils.closeQuiet(reader);
}
return line;
}

public static Map<String, String> getSystemProperties() {
Map<String, String> map = new HashMap<String, String>();
BufferedReader reader = null;
try {
Process p = Runtime.getRuntime().exec("getprop");
reader = new BufferedReader(new InputStreamReader(p.getInputStream()), 5120);
String line = reader.readLine();
while (line != null) {
Pattern pattern = Pattern.compile("\\[(.+)\\]\\s*:\\s*\\[(.+)\\]");
Matcher m = pattern.matcher(line);
if (m.find()) {
String key = m.group(1);
String value = m.group(2);
map.put(key, value);
}
line = reader.readLine();
}
} catch (IOException ex) {
Log.e(TAG, "Unable to read system properties.", ex);
} finally {
StreamUtils.closeQuiet(reader);
}
return map;
}

public static void appendValue(Context context, SpannableStringBuilder builder, int span, String str) {
appendValue(context, builder, span, str, (int) context.getResources().getDimension(R.dimen.gen_title_size));
}

public static void appendValue(Context context, SpannableStringBuilder builder, int span, String str, int fontSize) {
appendValue(context, builder, span, str, fontSize, -1);
}

public static void appendValue(Context context, SpannableStringBuilder builder, int span, String str, int fontSize, int color) {
int size = builder.length();
builder.append(str);
builder.setSpan(new AbsoluteSizeSpan(fontSize), size, size + span, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
if (color != -1) {
builder.setSpan(new ForegroundColorSpan(color), size, size + span, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
}
}

public static String getSystemProperty2(String s) {
String s1;
try {
s1 = Class.forName("android.os.SystemProperties").getMethod("get", new Class[]{String.class}).invoke(null, new Object[]{
s
}).toString();
} catch (Exception exception) {
Log.e("SystemUtils", exception);
return null;
}
return s1;
}

public static Map<String, String> dumpSystemInfo() {
Map<String, String> map = new HashMap<String, String>();
map.put("Version", getMyVersion(appContext));
map.put("VersionCode", String.valueOf(getMyVersionCode(appContext)));
map.put("Auid", BaseApplication.deviceId);
// map.put("DeviceId", XGPushConfig.getToken(appContext));
map.put("MIUI", getMiuiVersion());
map.put("FlyMe", getFlyMeVersion());
map.put("YunOS", getYunOSVersion());
map.put("CPU_ABI", Build.CPU_ABI);
map.put("TAGS", Build.TAGS);
map.put("MODEL", Build.MODEL);
map.put("SDK", String.valueOf(Build.VERSION.SDK_INT));
map.put("DEVICE", Build.DEVICE);
map.put("DISPLAY", Build.DISPLAY);
map.put("BRAND", Build.BRAND);
map.put("BOARD", Build.BOARD);
map.put("ID", Build.ID);
map.put("MANUFACTURER", Build.MANUFACTURER);
map.put("FINGERPRINT", Build.FINGERPRINT);
map.put("TYPE", Build.TYPE);
map.put("HARDWARE", Build.HARDWARE);
map.put("SERIAL", Build.SERIAL);
map.put("TIME", String.valueOf(Build.TIME));
map.put("USER", Build.USER);
map.put("HOST", Build.HOST);
map.put("VERSION.INCREMENTAL", Build.VERSION.INCREMENTAL);
map.put("VERSION.RELEASE", Build.VERSION.RELEASE);
map.put("VERSION.CODENAME", Build.VERSION.CODENAME);
map.put("VERSION_CODES.BASE", String.valueOf(Build.VERSION_CODES.BASE));
map.put("PKG_FIRST_INSTALL_TIME", DateUtil.simpleFormat(SystemUtils.getFirstInstallTime()));
map.put("PKG_LAST_UPDATE_TIME", DateUtil.simpleFormat(SystemUtils.getLastUpdateTime()));
return map;
}

/**
* 设备制造商,例如 XiaoMi
*
* @return
*/
public static String getManufacture() {
return Build.MANUFACTURER;
}

/**
* 手机设备型号,例如 MI2
*
* @return
*/
public static String getDeviceModel() {
return Build.MODEL;
}

public static String getDevice() {
return Build.DEVICE;
}

public static String getDeviceBrand() {
return Build.BRAND;
}

public static String getDisplay() {
return Build.DISPLAY;
}

public static String getUmengChannel() {
return getAppMetaData(appContext, "UMENG_CHANNEL");
}

/**
* 获取application中指定的meta-data
* @return 如果没有获取成功(没有对应值,或者异常),则返回值为空
*/
public static String getAppMetaData(Context ctx, String key) {
if (ctx == null || TextUtils.isEmpty(key)) {
return null;
}
String resultData = null;
try {
PackageManager packageManager = ctx.getPackageManager();
if (packageManager != null) {
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(ctx.getPackageName(), PackageManager.GET_META_DATA);
if (applicationInfo != null) {
if (applicationInfo.metaData != null) {
resultData = applicationInfo.metaData.getString(key);
}
}

}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}

return resultData;
}

/**
* 操作系统版本,例如 4.4.4
*
* @return
*/
public static String getOSVersion() {
return Build.VERSION.RELEASE;
}

public static int getSDKInt() {
return Build.VERSION.SDK_INT;
}

public static String getTimeZone() {
return TimeZone.getDefault().getID();
}

public static String getCountry() {
return Locale.getDefault().getCountry();
}

public static String getLanguage() {
return Locale.getDefault().getLanguage();
}

public static Context getContext() {
Context ac = ActivitiesManager.getInstance().currentActivity();
return ac != null ? ac : appContext;
}


public static boolean isTopRunningApp(Context ctx) {
ActivityManager am = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
String pkgName = "";
try {
//处理android 5.0和云os版本不能获取的bug
if (Build.VERSION.SDK_INT >= 21 || isYunOS()) {
pkgName = getTopRunningAppForL(am, ctx);
} else {
ActivityManager.RunningTaskInfo taskInfo = am.getRunningTasks(1).get(0);
pkgName = taskInfo.topActivity.getPackageName();//获取当前在前台的应用;
}
} catch (Exception e) {
Exception ex = new Exception("failed to get top running app", e);
Log.e(TAG, ex.getMessage(), ex);
// MobclickAgent.reportError(ctx, ex);
}
return StringUtil.isEqual(pkgName, getMyPackageName());
}

public static String getTopRunningAppForL(ActivityManager am, Context ctx) {
List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
List<String> runningApps = new ArrayList<String>(processInfos.size());
for (ActivityManager.RunningAppProcessInfo processInfo : processInfos) {
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
runningApps.addAll(Arrays.asList(processInfo.pkgList));
}
}
Log.v(TAG, "Current running processes: " + TextUtils.join(", ", runningApps));
if (runningApps.size() > 0)
return runningApps.get(0);
return "";
}


/**
* 判断服务是否正在运行
*
* @param context
* @param className 判断的服务名字:包名+类名
* @return true在运行 false 不在运行
*/
public static boolean isServiceRunning(Context context, String className) {
boolean isRunning = false;
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
//获取所有的服务
List<ActivityManager.RunningServiceInfo> services= activityManager.getRunningServices(Integer.MAX_VALUE);
if(services!=null&&services.size()>0){
for(ActivityManager.RunningServiceInfo service : services){
if(className.equals(service.service.getClassName())){
isRunning=true;
break;
}
}
}
return isRunning;
}

public static String getProvidersName(Context context) {
String IMSI;
String ProvidersName = null;
TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
// 返回唯一的用户ID;就是这张卡的编号神马的
IMSI = telephonyManager.getSubscriberId();
// IMSI号前面3位460是国家,紧接着后面2位00 02是中国移动,01是中国联通,03是中国电信。
if(StringUtil.isEmpty(IMSI)){
return "";
}
if (IMSI.startsWith("46000") || IMSI.startsWith("46002")) {
ProvidersName = "中国移动";
} else if (IMSI.startsWith("46001")) {
ProvidersName = "中国联通";
} else if (IMSI.startsWith("46003")) {
ProvidersName = "中国电信";
}
return ProvidersName;
}
}
作者 east
Android 12月 9,2020

Android自定义Toast工具类


public class ToastUtil {

private static Handler handler = new Handler(Looper.getMainLooper());

private static Toast toast = null;

private final static Object synObj = new Object();

private static Toast toastCenter = null;

/**
* 弹出自定义toast
* @param msg 消息内容
* @param duration 消息显示时长
*/
public static void showMessageCenter(final String msg, final int duration){
if(null == toastCenter){
LayoutInflater inflater = LayoutInflater.from(BaseApplication.getInstance().getApplicationContext());
View layout = inflater.inflate(R.layout.toast_center_custom, null);
toastCenter = new Toast(BaseApplication.getInstance().getApplicationContext());
toastCenter.setView(layout);
}
toastCenter.setDuration(duration);
toastCenter.setGravity(Gravity.CENTER, 0, 0);
((TextView)toastCenter.getView().findViewById(R.id.toast_message)).setText(msg);
toastCenter.show();
}

public static void showMessage(final CharSequence msg) {
showMessage(msg, Toast.LENGTH_SHORT);
}

/**
* 根据设置的文本显示
* @param msg
*/
public static void showMessage(final int msg) {
showMessage(msg, Toast.LENGTH_SHORT);
}

/**
* 显示一个文本并且设置时长
* @param msg
* @param len
*/
public static void showMessage(final CharSequence msg, final int len) {
if (msg == null || msg.equals("")) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
synchronized (synObj) { //加上同步是为了每个toast只要有机会显示出来
if (toast != null) {
//toast.cancel();
toast.setText(msg);
toast.setDuration(len);
} else {
toast = Toast.makeText(BaseApplication.getInstance(), msg, len);
}
toast.show();
}
}
});
}

public static void showMessageForGravity(final CharSequence msg) {
if (msg == null || msg.equals("")) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
synchronized (synObj) { //加上同步是为了每个toast只要有机会显示出来
if (toast != null) {
//toast.cancel();
toast.setText(msg);
toast.setDuration(Toast.LENGTH_SHORT);
} else {
toast = Toast.makeText(BaseApplication.getInstance(), msg, Toast.LENGTH_SHORT);
}
toast.setGravity(Gravity.TOP, 0, 0);
toast.show();
}
}
});
}

/**
* 资源文件方式显示文本
* @param msg
* @param len
*/
public static void showMessage(final int msg, final int len) {
handler.post(new Runnable() {
@Override
public void run() {
synchronized (synObj) {
if (toast != null) {
//toast.cancel();
toast.setText(msg);
toast.setDuration(len);
} else {
toast = Toast.makeText(BaseApplication.getInstance(), msg, len);
}
toast.show();
}
}
});
}

public static void showMessage(final View v, final CharSequence msg) {
((TextView) v).setText(msg);
}
}
作者 east
Android 12月 9,2020

Android上传文件工具类




import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;



public class UploadUtil {
private static UploadUtil uploadUtil;
private static final String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
private static final String PREFIX = "--";
private static final String LINE_END = "\r\n";
private static final String CONTENT_TYPE = "multipart/form-data"; // 内容类型
private UploadUtil() {

}

/**
* 单例模式获取上传工具类
*
@return
*/
public static UploadUtil getInstance() {
if (null == uploadUtil) {
uploadUtil = new UploadUtil();
}
return uploadUtil;
}

private static final String TAG = "UploadUtil";
private int readTimeOut = 10 * 1000; // 读取超时
private int connectTimeout = 10 * 1000; // 超时时间
/***
* 请求使用多长时间
*/
private static int requestTime = 0;

private static final String CHARSET = "utf-8"; // 设置编码

/***
* 上传成功
*/
public static final int UPLOAD_SUCCESS_CODE = 1;
/**
* 文件不存在
*/
public static final int UPLOAD_FILE_NOT_EXISTS_CODE = 2;
/**
* 服务器出错
*/
public static final int UPLOAD_SERVER_ERROR_CODE = 3;
protected static final int WHAT_TO_UPLOAD = 1;
protected static final int WHAT_UPLOAD_DONE = 2;

/**
* android上传文件到服务器
*
*
@param filePath
* 需要上传的文件的路径
*
@param fileKey
* 在网页上<input type=file name=xxx/> xxx就是这里的fileKey
*
@param RequestURL
* 请求的URL
*/
public void uploadFile(String filePath, String fileKey, String RequestURL,
Map<String, String> param) {
if (filePath == null) {
sendMessage(UPLOAD_FILE_NOT_EXISTS_CODE,"文件不存在");
return;
}
try {
File file = new File(filePath);
uploadFile(file, fileKey, RequestURL, param);
} catch (Exception e) {
sendMessage(UPLOAD_FILE_NOT_EXISTS_CODE,"文件不存在");
e.printStackTrace();
return;
}
}

/**
* android上传文件到服务器
*
*
@param file
* 需要上传的文件
*
@param fileKey
* 在网页上<input type=file name=xxx/> xxx就是这里的fileKey
*
@param RequestURL
* 请求的URL
*/
public void uploadFile(final File file, final String fileKey,
final String RequestURL, final Map<String, String> param) {
if (file == null || (!file.exists())) {
sendMessage(UPLOAD_FILE_NOT_EXISTS_CODE,"文件不存在");
return;
}

Log.i(TAG, "请求的URL=" + RequestURL);
Log.i(TAG, "请求的fileName=" + file.getName());
Log.i(TAG, "请求的fileKey=" + fileKey);
new Thread(new Runnable() { //开启线程上传文件
@Override
public void run() {
toUploadFile(file, fileKey, RequestURL, param);
}
}).start();

}

private void toUploadFile(File file, String fileKey, String RequestURL,
Map<String, String> param) {
String result = null;
requestTime= 0;

long requestTime = System.currentTimeMillis();
long responseTime = 0;

try {
URL url = new URL(RequestURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(readTimeOut);
conn.setConnectTimeout(connectTimeout);
conn.setDoInput(true); // 允许输入流
conn.setDoOutput(true); // 允许输出流
conn.setUseCaches(false); // 不允许使用缓存
conn.setRequestMethod("POST"); // 请求方式
conn.setRequestProperty("Charset", CHARSET); // 设置编码
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("user-agent", ApiHelper.getUserAgent());
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
// conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

/**
* 当文件不为空,把文件包装并且上传
*/
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
StringBuffer sb = null;
String params = "";

/***
* 以下是用于上传参数
*/
if (param != null && param.size() > 0) {
Iterator<String> it = param.keySet().iterator();
while (it.hasNext()) {
sb = null;
sb = new StringBuffer();
String key = it.next();
String value = param.get(key);
sb.append(PREFIX).append(BOUNDARY).append(LINE_END);
sb.append("Content-Disposition: form-data; name=\"").append(key).append("\"").append(LINE_END).append(LINE_END);
sb.append(value).append(LINE_END);
params = sb.toString();
Log.i(TAG, key+"="+params+"##");
dos.write(params.getBytes());
// dos.flush();
}
}

sb = null;
params = null;
sb = new StringBuffer();
/**
* 这里重点注意: name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
* filename是文件的名字,包含后缀名的 比如:abc.png
*/
sb.append(PREFIX).append(BOUNDARY).append(LINE_END);
sb.append("Content-Disposition:form-data; name=\"" + fileKey
+ "\"; filename=\"" + file.getName() + "\"" + LINE_END);
sb.append("Content-Type:"+ MimeTypesTools.getMimeType(BaseApplication.getInstance(), file.getName()) + LINE_END); // 这里配置的Content-type很重要的 ,用于服务器端辨别文件的类型的
sb.append(LINE_END);
params = sb.toString();
sb = null;

Log.i(TAG, file.getName()+"=" + params+"##");
dos.write(params.getBytes());
/**上传文件*/
InputStream is = new FileInputStream(file);
onUploadProcessListener.initUpload((int)file.length());
byte[] bytes = new byte[1024];
int len = 0;
int curLen = 0;
while ((len = is.read(bytes)) != -1) {
curLen += len;
dos.write(bytes, 0, len);
onUploadProcessListener.onUploadProcess(curLen);
}
is.close();

dos.write(LINE_END.getBytes());

byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
dos.write(end_data);
dos.flush();
//
// dos.write(tempOutputStream.toByteArray());
/**
* 获取响应码 200=成功 当响应成功,获取响应的流
*/
int res = conn.getResponseCode();
responseTime = System.currentTimeMillis();
UploadUtil.requestTime = (int) ((responseTime-requestTime)/1000);
Log.e(TAG, "response code:" + res);
if (res == 200) {
Log.e(TAG, "request success");
InputStream input = conn.getInputStream();
BufferedReader bufReader = null;
try {
bufReader = new BufferedReader(new InputStreamReader(
input, "utf-8"));
StringBuffer sb1 = new StringBuffer();
String line;
while ((line = bufReader.readLine()) != null) {
sb1.append(line);
}
result = sb1.toString();
Log.e(TAG, "result : " + result);
sendMessage(UPLOAD_SUCCESS_CODE, result);

} catch (IOException e) {

}finally {
try {
if (bufReader != null) {
bufReader.close();
}
} catch (IOException e) {

}
}

return;
} else {
Log.e(TAG, "request error");
sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:code=" + res);
return;
}
} catch (MalformedURLException e) {
sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:error=" + e.getMessage());
e.printStackTrace();
return;
} catch (IOException e) {
sendMessage(UPLOAD_SERVER_ERROR_CODE,"上传失败:error=" + e.getMessage());
e.printStackTrace();
return;
}
}

/**
* 发送上传结果
*
@param responseCode
* @param responseMessage
*/
private void sendMessage(int responseCode,String responseMessage)
{
onUploadProcessListener.onUploadDone(responseCode, responseMessage);
}

/**
* 下面是一个自定义的回调函数,用到回调上传文件是否完成
*
*
@author shimingzheng
*
*/
public interface OnUploadProcessListener {
/**
* 上传响应
*
@param responseCode
* @param message
*/
void onUploadDone(int responseCode, String message);
/**
* 上传中
*
@param uploadSize
*/
void onUploadProcess(int uploadSize);
/**
* 准备上传
*
@param fileSize
*/
void initUpload(int fileSize);
}
private OnUploadProcessListener onUploadProcessListener;



public void setOnUploadProcessListener(
OnUploadProcessListener onUploadProcessListener) {
this.onUploadProcessListener = onUploadProcessListener;
}

public int getReadTimeOut() {
return readTimeOut;
}

public void setReadTimeOut(int readTimeOut) {
this.readTimeOut = readTimeOut;
}

public int getConnectTimeout() {
return connectTimeout;
}

public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
/**
* 获取上传使用的时间
*
@return
*/
public static int getRequestTime() {
return requestTime;
}

public interface uploadProcessListener{

}




}

作者 east

上一 1 … 68 69 70 … 92 下一个

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。回复”chatgpt”获取免注册可用chatgpt。回复“大数据”获取多本大数据电子书

标签

AIGC AI创作 bert chatgpt github GPT-3 gpt3 GTP-3 hive mysql O2O tensorflow UI控件 不含后台 交流 共享经济 出行 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 日历 机器学习 深度学习 物流 用户系统 电商 画图 画布(canvas) 社交 签到 联网 读书 资讯 阅读 预订

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • MQTT完全解析和实践
  • 解决运行Selenium报错:self.driver = webdriver.Chrome(service=service) TypeError: __init__() got an unexpected keyword argument ‘service’
  • python 3.6使用mysql-connector-python报错:SyntaxError: future feature annotations is not defined
  • 详解Python当中的pip常用命令
  • AUTOSAR如何在多个供应商交付的配置中避免ARXML不兼容?
  • C++thread pool(线程池)设计应关注哪些扩展性问题?
  • 各类MCAL(Microcontroller Abstraction Layer)如何与AUTOSAR工具链解耦?
  • 如何设计AUTOSAR中的“域控制器”以支持未来扩展?
  • C++ 中避免悬挂引用的企业策略有哪些?
  • 嵌入式电机:如何在低速和高负载状态下保持FOC(Field-Oriented Control)算法的电流控制稳定?

文章归档

  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年1月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 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 (73)
  • bug清单 (79)
  • C++ (34)
  • Fuchsia (15)
  • php (4)
  • python (45)
  • sklearn (1)
  • 云计算 (20)
  • 人工智能 (61)
    • chatgpt (21)
      • 提示词 (6)
    • Keras (1)
    • Tensorflow (3)
    • 大模型 (1)
    • 智能体 (4)
    • 深度学习 (14)
  • 储能 (44)
  • 前端 (4)
  • 大数据开发 (490)
    • CDH (6)
    • datax (4)
    • doris (31)
    • Elasticsearch (15)
    • Flink (78)
    • flume (7)
    • Hadoop (19)
    • Hbase (23)
    • Hive (41)
    • Impala (2)
    • Java (71)
    • Kafka (10)
    • neo4j (5)
    • shardingsphere (6)
    • solr (5)
    • Spark (99)
    • spring (11)
    • 数据仓库 (9)
    • 数据挖掘 (7)
    • 海豚调度器 (10)
    • 运维 (34)
      • Docker (3)
  • 小游戏代码 (1)
  • 小程序代码 (139)
    • O2O (16)
    • UI控件 (5)
    • 互联网类 (23)
    • 企业类 (6)
    • 地图定位 (9)
    • 多媒体 (6)
    • 工具类 (25)
    • 电商类 (22)
    • 社交 (7)
    • 行业软件 (7)
    • 资讯读书 (11)
  • 嵌入式 (71)
    • autosar (63)
    • RTOS (1)
    • 总线 (1)
  • 开发博客 (16)
    • Harmony (9)
  • 技术架构 (6)
  • 数据库 (32)
    • mongodb (1)
    • mysql (13)
    • pgsql (2)
    • redis (1)
    • tdengine (4)
  • 未分类 (6)
  • 程序员网赚 (20)
    • 广告联盟 (3)
    • 私域流量 (5)
    • 自媒体 (5)
  • 量化投资 (4)
  • 面试 (14)

功能

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

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