Android 获取已连接热点的设备信息

private static final String IP_CMD = “ip neighbor”;
private void getConnectInfo() {
BufferedReader reader = null;

try {
Process ipProc = Runtime.getRuntime().exec(IP_CMD);
ipProc.waitFor();
if (ipProc.exitValue() != 0) {
throw new Exception(“Unable to access ARP entries”);
}

reader = new BufferedReader(new InputStreamReader(ipProc.getInputStream(), “UTF-8”));
String line;
while ((line = reader.readLine()) != null) {
String[] neighborLine = line.split(“\\s+”);

// We don’t have a validated ARP entry for this case.
if (neighborLine.length <= 4) { continue; } String ipaddr = neighborLine[0]; InetAddress addr = InetAddress.getByName(ipaddr); if (addr.isLinkLocalAddress() || addr.isLoopbackAddress()) { continue; } String macAddress = neighborLine[4]; } } catch (Exception e) { } }

Android Autosize息屏造成页面布局混乱问题

应用为横屏时,切到其他应用再切回/息屏之后再切回等情况可能会造成页面混乱。
处理办法:
Manifest中对应Activity添加:
android:configChanges=”keyboardHidden|orientation|screenSize”
Activity:
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
AutoSize.autoConvertDensityOfGlobal(this); //如果没有自定义需求用这个方法
} else {
}
}

Android ANR文件分析

1、ANR文件第一个“main”线程是否有提示具体问题,如果有的话根据对应提示找到代码;
2、锁问题:ANR文件第一个”main”中如果有保护“mutator lock” shared held,这个可能是主线程中加了锁,而且与其他线程锁产生死锁等问题造成,然后根据下面文件找到项目中出问题的代码文件。这种大概率是Handler处理主线程与其他线程时造成了死锁。

Notification Service

public class KeepAppAliveService extends Service {
private NotificationManager mNotificationManager;
private String mNotificationId = “keepAppAliveId”;
private String mNotificationName = “Keep app alive”;

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onCreate() {
super.onCreate();
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(mNotificationId, mNotificationName, NotificationManager.IMPORTANCE_HIGH);
mNotificationManager.createNotificationChannel(channel);
}
startForeground(1, getNotification());
}

private Notification getNotification() {
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(“七牛推流”)
.setContentText(“后台运行中”);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(mNotificationId);
}
return builder.build();
}
}

Android AutoSize适配问题

部分设备上适配有问题(整体缩小或者放大)。
原因:autosize读取到的宽高反了;
解决办法:
只需在Application中手动设置宽高
AutoSizeConfig.getInstance()

//是否让框架支持自定义 Fragment 的适配参数, 由于这个需求是比较少见的, 所以须要使用者手动开启
//如果没有这个需求建议不开启
.setCustomFragment(true)

//是否屏蔽系统字体大小对 AndroidAutoSize 的影响, 如果为 true, App 内的字体的大小将不会跟随系统设置中字体大小的改变
//如果为 false, 则会跟随系统设置中字体大小的改变, 默认为 false
// .setExcludeFontScale(true)

//区别于系统字体大小的放大比例, AndroidAutoSize 允许 APP 内部可以独立于系统字体大小之外,独自拥有全局调节 APP 字体大小的能力
//当然, 在 APP 内您必须使用 sp 来作为字体的单位, 否则此功能无效, 不设置或将此值设为 0 则取消此功能
// .setPrivateFontScale(0.8f)

//屏幕适配监听器
.setOnAdaptListener(new onAdaptListener() {
@Override
public void onAdaptBefore(Object target, Activity activity) {
//使用以下代码, 可以解决横竖屏切换时的屏幕适配问题
//使用以下代码, 可支持 Android 的分屏或缩放模式, 但前提是在分屏或缩放模式下当用户改变您 App 的窗口大小时
//系统会重绘当前的页面, 经测试在某些机型, 某些情况下系统不会主动重绘当前页面, 所以这时您需要自行重绘当前页面
//ScreenUtils.getScreenSize(activity) 的参数一定要不要传 Application!!!
AutoSizeConfig.getInstance().setScreenWidth(ScreenUtils.getScreenSize(activity)[0]);
AutoSizeConfig.getInstance().setScreenHeight(ScreenUtils.getScreenSize(activity)[1]);
// MLog.d(“Application”,”orientation:”+ScreenUtils.getScreenSize(activity)[0]+”,”+ScreenUtils.getScreenSize(activity)[1]);

AutoSizeLog.d(String.format(Locale.ENGLISH, “%s onAdaptBefore!”, target.getClass().getName()));
}

@Override
public void onAdaptAfter(Object target, Activity activity) {
AutoSizeLog.d(String.format(Locale.ENGLISH, “%s onAdaptAfter!”, target.getClass().getName()));
}
});

界面自定义尺寸:
1、实现CustomAdapt
@Override
public boolean isBaseOnWidth() {
return AutoSizeConfig.getInstance().getInitScreenWidthDp()>AutoSizeConfig.getInstance().getInitScreenHeightDp();//这边页面是横屏所以宽大于高,如果是竖屏使用高大于宽
}

@Override
public float getSizeInDp() {
return 960;//实际适配宽
}

Android 画图擦除

擦除方式:
1、擦除与橡皮轨迹相交的线
用Path.op方法
例如:
int index = -1;
Path tpath = new Path();
for(Path path:paths){
i++;
tpath.op(path,tempPath, Path.Op.INTERSECT)
if(!tpath.isEmpty()){
index = i;
}
}
if(index>=0) {
paths.remove(index);
}
2、擦除橡皮轨迹相交的所有点
设置橡皮擦轨迹属性
mPorterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
mErasePaint.setXfermode(mPorterDuffXfermode);

Android textview 文字拼接/文字展开收起

1、文本拼接:
private SpannableStringBuilder setGross(String haveReadGross, String taskGross) {
StringBuffer stringBuffer = new StringBuffer();
String haveRead = “已阅总量”;
String task = “\n\n任务总量”;

stringBuffer.append(haveRead);
stringBuffer.append(haveReadGross);
stringBuffer.append(task);
stringBuffer.append(taskGross);

SpannableStringBuilder style = new SpannableStringBuilder(stringBuffer.toString());

int start_1 = haveRead.length();
int end_1 = start_1 + haveReadGross.length();
style.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.color_0089FF)), start_1, end_1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);

int start_2 = end_1 + task.length();
int end_2 = start_2 + taskGross.length();
style.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.color_222222)), start_2, end_2, Spannable.SPAN_INCLUSIVE_INCLUSIVE);

return style;
}
textview.setText(setGross(“value1″,”value2”));

2、展开收起
String expand = “[展开]”;
String collapse = “[收起]”;

/**
* 是否需要添加展开处理
* @param contentTextView
* @param expandLine
* @param textValue
*/
private void expandText(TextView contentTextView,int expandLine,String textValue) {
CharSequence text = contentTextView.getText();
int width = contentTextView.getWidth();
TextPaint paint = contentTextView.getPaint();
Layout layout = contentTextView.getLayout();
int line = layout.getLineCount();
if (line > expandLine) {
int start = layout.getLineStart((expandLine-1));
int end = layout.getLineVisibleEnd(expandLine-1);
CharSequence lastLine = text.subSequence(start, end);

float expandWidth = paint.measureText(expand);
float remain = width – expandWidth;

CharSequence ellipsize =
TextUtils.ellipsize(lastLine,
paint,
remain,
TextUtils.TruncateAt.END);

ClickableSpan clickableSpan = new ClickableSpan() {

@Override
public void onClick(@NonNull View widget) {

collapseText(contentTextView,expandLine,textValue);
}
};

SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(text.subSequence(0, start));
ssb.append(ellipsize);
ssb.append(expand);
ssb.setSpan(new ForegroundColorSpan(Color.parseColor(“#0089FF”)),
ssb.length() – expand.length(), ssb.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ssb.setSpan(clickableSpan,
ssb.length() – expand.length(), ssb.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
contentTextView.setMovementMethod(LinkMovementMethod.getInstance());
contentTextView.setText(ssb);
}
}

/**
* 收起处理
* @param tv
* @param expandLine
* @param textString
*/
private void collapseText(TextView tv, int expandLine, String textString){
ClickableSpan clickableSpan = new ClickableSpan() {

@Override
public void onClick(@NonNull View widget) {
expandText(tv,expandLine,textString);
}
};
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(textString);
ssb.append(collapse);
ssb.setSpan(new ForegroundColorSpan(Color.rgb(0,137,255)),
ssb.length() – collapse.length(), ssb.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
ssb.setSpan(clickableSpan,
ssb.length() – collapse.length(), ssb.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
tv.setText(ssb);
}
备注:展开收起的字体颜色可能设置无效,这个颜色会受colors.xml中的colorAccent影响

Android Webview造成AutoSize显示异常

自定义Webview,实现setOverScrollMode方法
public class EWebView extends WebView {
public EWebView(Context context) {
super(context);
}

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

@Override
public void setOverScrollMode(int mode) {
super.setOverScrollMode(mode);
AutoSize.autoConvertDensityOfGlobal((Activity) getContext());
}
}