- EventBus
- ThirdPart
- 折叠屏:
- android 国际化多语言
- android 多渠道(马甲包)开发
- 解决notifyDataSetChanged时导致图片闪烁
- Material Design
- View
- Java反射
- ffmpeg
- 云信IM
EventBus
-
先
EventBus.getDefault()生成一个EventBus()单例,并初始化EventBus所需数据 -
注册,注销EventBus a.
EventBus.getDefault().register(this)注册EventBus b.EventBus.getDefault().unregister(this)注销EventBus c.subscriber.getClass()获取每个注册的Class 放入 subscriptionsByEventType -
EventBus.getDefault().post("hello")调用post(Object event)方法,post方法执行:-
放入队列 用
ThreadLocal<PostingThreadState>创建currentPostingThreadState,PostingThreadState postingState = currentPostingThreadState.get(); List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event);把event装入eventQueue队列 -
获取event的类型 获取event的event放入eventTypes 获取event的Class和event的类型
(Object、String、Comparable、com.hande.common.event.Events$ClearMessageInList等类型)放入Map<Class<?>, List<Class<?>>> eventTypesCache -
遍历eventTypes 得到 eventType 再遍历 subscriptions
-
subscription.subscriberMethod.method.invoke(subscription.subscriber, event)发送事件 -
EmoticonPickerView 接收到事件
threadMode = ThreadMode.MAIN就是主线程处理事件
-
ThirdPart
腾讯X5webview:
tbs_sdk_thirdapp_v4.3.0.3_43903_sharewithdownloadwithfile_withoutGame_obfs_20200402_121309.jar
折叠屏
如有今日头条屏幕适配方案需去除
implementation 'me.jessyan:autosize:1.1.2'
<meta-data
android:name="design_width_in_dp"
android:value="375" />
<meta-data
android:name="design_height_in_dp"
android:value="667" />
华为折叠屏适配方案:
-
在每个activity里加:
android:configChanges="screenSize|smallestScreenSize|screenLayout" -
在 manifest 文件的 < application > 节点中增加 < meta-data > 数据:
<meta-data
android:name="android.min_aspect"
android:value="1.0" />
国际化多语言
-
获取本地国家
Locale.getDefault().getLanguage() -
获取本地区域(如:香港 HK、台湾 TW)
Locale.getDefault().getCountry()
多渠道(马甲包)开发
- 使用gradle进行动态配置
- 通过productFlavors配置打包渠道
在app/build.gradle里: productFlavors { anzhi { applicationId "com.muitlchannelpack.anzhi.jks" manifestPlaceholders = [ UMENG_APPKEY : UM_ANZHI, UMENG_CHANNEL: ANZHI, ] } wandoujia { applicationId "com.muitlchannelpack.wandoujia" manifestPlaceholders = [ UMENG_APPKEY : UM_HUAWEI, UMENG_CHANNEL: WANDOUJIA, ] } huawei { applicationId "com.muitlchannelpack.huawei" manifestPlaceholders = [ UMENG_APPKEY : UM_WANDOUJIA, UMENG_CHANNEL: HUAWEI, ] } } - 资源文件的替换
- 在app/src目录下面创建productFlavors对应的文件夹
- 分别在不同的渠道配置不同的AndroidManifest.xml启动项,在main下的AndroidManifest.xml可以让如公共项
- 用
BuildConfig.FLAVOR.equals("wandoujia")可以判断当前的渠道
解决notifyDataSetChanged时导致图片闪烁
- 调用方:
recyclerView.Adapter.setHasStableIds(true);
- recyclerView.Adapter里:
@Override
public long getItemId(int position) {
return position;
}
Material Design
- 普通背景:添加水纹: 有边界
android:foreground="?android:attr/selectableItemBackground"
android:background="?android:attr/selectableItemBackground"
无边界
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:background="?android:attr/selectableItemBackgroundBorderless"
- 按钮
<Button
android:id="@+id/bt_reject"
android:layout_width="60dp"
android:layout_height="26dp"
android:layout_margin="8dp"
android:background="@drawable/shape_color_e5e8eb_radius_16"
android:text="拒绝"
android:textColor="@color/color_black_ff666666" />
- cardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
<androidx.cardview.widget.CardView
android:id="@+id/cv_save"
android:layout_width="116dp"
android:layout_height="42dp"
android:layout_gravity="center"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="16dp"
card_view:cardElevation="2dp"
card_view:cardBackgroundColor="@color/color_ff3e3e"
card_view:cardUseCompatPadding="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="保存至相册"
android:textColor="@color/color_111111"
android:textSize="12sp" />
</androidx.cardview.widget.CardView>
- 阴影 elevation
android:elevation="8dp"
或 android:translationZ="20dp"
View
- 获取view 宽高
View view = findViewById(R.id.view);
view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
Log.e("view", view.getHeight() + "");
view.getViewTreeObserver().removeOnPreDrawListener(this);
return false;
}
});
Java反射
- 反射工具类 ReflectUtils
import android.text.TextUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
public class ReflectUtils {
/**
* 调用Class的静态方法
*/
public static <T> T invokeClassMethod(String classPath, String methodName, Class[] paramClasses, Object[] params) {
return (T) executeClassLoad(getClass(classPath), methodName, paramClasses, params);
}
/**
* 调用Class的无参静态方法
*/
public static Object invokeMethod(Object obj, String methodName, Object[] params) {
return invokeMethod(obj, methodName, null, params);
}
/**
* 通过类对象,运行指定方法
*
* @param obj 类对象
* @param methodName 方法名
* @param paramTypes 参数对应的类型(如果不指定,那么从params来判断,可能会判断不准确,例如把CharSequence 判断成String,导致反射时方法找不到)
* @param params 参数值
* @return 失败返回null
*/
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramTypes, Object[] params) {
if (obj == null || TextUtils.isEmpty(methodName)) {
return null;
}
Class<?> clazz = obj.getClass();
try {
if (paramTypes == null) {
if (params != null) {
paramTypes = new Class[params.length];
for (int i = 0; i < params.length; ++i) {
paramTypes[i] = params[i].getClass();
}
}
}
Method method = clazz.getMethod(methodName, paramTypes);
method.setAccessible(true);
return method.invoke(obj, params);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 反射获取对象属性值
*/
public static Object getFieldValue(Object obj, String fieldName) {
if (obj == null || TextUtils.isEmpty(fieldName)) {
return null;
}
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
e.printStackTrace();
}
clazz = clazz.getSuperclass();
}
return null;
}
/**
* 反射修改对象属性值
*/
public static void setFieldValue(Object obj, String fieldName, Object value) {
if (obj == null || TextUtils.isEmpty(fieldName)) {
return;
}
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
return;
} catch (Exception e) {
e.printStackTrace();
}
clazz = clazz.getSuperclass();
}
}
/**
* 获取Class所有的静态成员
*/
public static List<Field> getClassStaticField(Class clazz) {
Field[] fields = clazz.getFields();
List<Field> ret = new ArrayList<>();
for (Field field : fields) {
String m = Modifier.toString(field.getModifiers());
if (m.contains("static")) {
ret.add(field);
}
}
return ret;
}
/**
* 获取Class所有静态字段的值
*/
public static List<Object> getClassStaticFieldValue(Class clazz) {
Field[] fields = clazz.getFields();
List<Object> ret = new ArrayList<>();
for (Field field : fields) {
String m = Modifier.toString(field.getModifiers());
if (m.contains("static")) {
try {
ret.add(field.get(null));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return ret;
}
/**
* 获取某个字段的@annotation
*/
public static <A extends Annotation> A getFieldAnnotationsByType(Field field, Class<A> annotationType) {
return field.getAnnotation(annotationType);
}
/**
* 判断某个类是否包含某个方法,前提是这个类也存在
*/
public static boolean hasMethod(String classPath, String methodName, Class[] paramClasses) {
return getMethod(getClass(classPath), methodName, paramClasses) != null;
}
/**
* ****************************** basic ******************************
*/
private static Class getClass(String str) {
Class cls = null;
try {
cls = Class.forName(str);
} catch (ClassNotFoundException ignored) {
ignored.printStackTrace();
}
return cls;
}
private static Object executeClassLoad(Class cls, String str, Class[] clsArr, Object[] objArr) {
Object obj = null;
if (!(cls == null || checkObjExists(str))) {
Method method = getMethod(cls, str, clsArr);
if (method != null) {
method.setAccessible(true);
try {
obj = method.invoke(null, objArr);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
return obj;
}
private static Method getMethod(Class cls, String str, Class[] clsArr) {
Method method = null;
if (cls == null || checkObjExists(str)) {
return null;
}
try {
cls.getMethods();
cls.getDeclaredMethods();
return cls.getDeclaredMethod(str, clsArr);
} catch (Exception e) {
try {
return cls.getMethod(str, clsArr);
} catch (Exception e2) {
return cls.getSuperclass() != null ? getMethod(cls.getSuperclass(), str, clsArr) : method;
}
}
}
private static boolean checkObjExists(Object obj) {
return obj == null || obj.toString().equals("") || obj.toString().trim().equals("null");
}
}