class reference {
private final String TAG = reference.class.getSimpleName();// 日志TAG
private final AuthenticationProvider authenticationProvider = null; // 成员待初始化,内部不变final,非必须
private final HealthKitService healthKitService; // 对象做成员
private HandlerThread mBTStatusHandlerThread = null; // 线程对象
private DeviceStatusHandler mStatusHandler = null; // handler对象
private static final Object lock = new Object(); // 对象锁
@BindView(R.id.ll_verifycode)
protected LinearLayout mLlVerifyCode;// 注意修饰符
// 界面类的第一个函数
@Override
public int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppUtils.setStatusTranslucent(this);
init(); // 初始化成员 层次分离
initView(); // 初始化界面
checkPermission(); // 其他逻辑
}
// 初始化成员
private void init() {
if (null == bridgeManager) {
projectCode = Constants.STUDY_ID;
bridgeManager = BridgeManager2.getInstance(projectCode);
authenticationProvider = bridgeManager.getAuthenticationProvider();
}
}
// 初始化界面
private void initView() {
}
// 单例写法instance
// 注意判空,哪怕是自定义的成员变量
// 线程
private void initRunThread() {
if (null != mBTStatusHandlerThread) {
mBTStatusHandlerThread = null;
}
// 实例化命令发送线程句柄
mBTStatusHandlerThread = new HandlerThread(TAG);
// 启动线程
mBTStatusHandlerThread.start();
// 实例化命令发送Handler
mStatusHandler = new DeviceStatusHandler(mBTStatusHandlerThread.getLooper());
}
// handler
private class DeviceStatusHandler extends Handler {
public DeviceStatusHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case DEVICE_STATUS_MSG:
checkDeviceStatus();
break;
}
}
}
//handler发送消息
mSendHandler.sendEmptyMessage(SYNC_HEALTH_SPORT_DATA);
mHandler.post/postDelayed(new Runnable())
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
RxBus.get().post(Constants.UPLOAD_SUCCESS_TASK, 0);
}
}, 1000);
RxBus.get().post(Constants.SYNC_DEVICE, syncBTDataStatus);RxBus.toObservable();
// 对象锁
private byte [] lock = new byte [ 0 ]; // 定一个instance变量
synchronized (lock) {
if (localDevices.contains(deviceInfo)) {
localDevices.remove(deviceInfo);
}
localDevices.add(deviceInfo);}
Lock lock = new XxxLock();
// ... boolean isLocked = lock.tryLock();
if (isLocked) {
try {
doBiz();
}
finally {
lock.unlock();
}
@Override
public toString(){
}
@Override
public int hashCode() {
return userId.hashCode();
}
@Override
public boolean equals(@Nullable Object obj) {
if (null == obj || !(obj instanceof ActivityData))
return false;
ActivityData other = (ActivityData) obj;
return Objects.equals(userId, other.getUserId()) && Objects.equals(dayStartTime, other.getDayStartTime());
}
}
线程:
MyThread extends Thread
@override run()
}
new MyThread ().start();
new Thread(() -> addRawSleepDataToDB(returnObject)).start();
MyRunnable implemnts Runnable{
@Override run()
}
new Thread(new MyRunnable()).start();
new Handler.post(new Runnable()); //lamadabc表达式
RxBus.get().post(Constants.DEVICE_CONNECT_TYPE, deviceInfo);
序列化Gson:
Type type = new TypeToken<List<SensorProDeviceInfo>>() {
}.getType();
if (!TextUtils.isEmpty(data)) {
List<SensorProDeviceInfo> deviceInfoList = new Gson().fromJson(data, type);
Object<->String,Gson,参考GsonUtils,to/fromJson (如: public String toString() {return GsonUtils.toString(this);})
gson = new GsonBuilder()
// 不过滤空值
.serializeNulls()
// 设置字段命名转换规则
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
// 设置字段序列化/反序列化过滤规则
.excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC)
// 自定义类型解析器,提高Gson容错性
.registerTypeHierarchyAdapter(List.class, listDeserial)
.create();
系统资源,通过context/PackageManager,获取项目的资源(包名,meta-signature,sha256,string.xml,assets,SharedPreferences): 本质上是流
String packageName = context.getPackageName();
String isCheckJoinResearch = context.getString(R.string.isCheckJoinResearch); 写在string.xml中
SharedPreferences sharedPreferences = applicationContext.getSharedPreferences(PREFERENCES_FILE + "_" + projectCode, Context.MODE_PRIVATE);
(ConnectivityManager) Utils.getApp().getSystemService(Context.CONNECTIVITY_SERVICE)).
BluetoothManager bluetoothManager = (BluetoothManager) Utils.getApp().getSystemService(Context.BLUETOOTH_SERVICE);
LocationManager locationManager = (LocationManager) Utils.getApp().getSystemService(Context.LOCATION_SERVICE);
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
获取apk包信息:getPackageInfo
获取App的运行模式:BUILDConfig等配置:build.gradle: buildTypes
获取自定义的属性attrs.xml文件。TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CircularPointBarView); mTypedArray.recycle();在xml中定属性的值
从不同位置获取Bitmap
//判断是否授权
private boolean checkPermissionGranted(String permission) {
return ContextCompat.checkSelfPermission(SensorApplication.getContext(), permission)
== PackageManager.PERMISSION_GRANTED;
}
context.getSharedPreferences(name, Context.MODE_PRIVATE);
参考sensorpro-AuthValidUtils
获取路径file.getName();
检查文件是否为空,判断长度即可 path-》 if (file.length() > 0) {
/**
* 新建文件路径
*
* @return
*/
public static String createFilePath() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.ENGLISH);
String timeStr = dateFormat.format(new Date());
String File_PATH = Environment.getExternalStorageDirectory() + "/sleepbigdata/sensordata/" + timeStr;
File filePath = new File(File_PATH);
if (!filePath.exists()) {
boolean pathMkdir = filePath.mkdirs();
if (!pathMkdir) {
return null;
}
}
return File_PATH;
}
连续配置: public ECGCommandGenerator setScene(String scene){
this.mScene = scene;
return this;
}
广播:
//注册监听系统时间发生变化广播
IntentFilter filterTimeChanged = new IntentFilter(Intent.ACTION_TIME_CHANGED);
mContext.registerReceiver(mTimeChangedReceiver, filterTimeChanged);
//发送广播
//接收广播
Rxjava:
1.sdk-RxSchedulersHelper:
public static <T> ObservableTransformer<T, T> io_io() {
return new ObservableTransformer<T, T>() {
@Override
public ObservableSource<T> apply(@NonNull Observable<T> upstream) {
return upstream.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io());
}
};
}
public <T> Observable<T> toObservable(final int code, final Class<T> eventType) {
return mBus.ofType(Message.class)
.filter(new Predicate<Message>() {
@Override
public boolean test(Message message) throws Exception {
//过滤code和eventType都相同的事件
return message.getCode() == code && eventType.isInstance(message.getObject());
}
})
.map(new Function<Message, Object>() {
@Override
public Object apply(Message message) throws Exception {
return message.getObject();
}
}).cast(eventType);
}
2.合并observable:UserInfoUpload: obsArgs = Observable.merge(uploadAvatarObs, uploadUserInfoObs);//合并多个observable
Observable<BannerResp> observableBanner = articleProviderTmp.getBannerList2();
Observable<ArticleInfoResp> observableArticle = articleProviderTmp.getArticleList(pageInfo);
Observable<Object> merge = Observable.merge(observableBanner, observableArticle);
final ArticleInfos[] banner = {new ArticleInfos()};
final ArticleInfos[] articleList = {new ArticleInfos()};
Observable.merge(observableBanner, observableArticle)
.subscribe(new Observer<Object>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Object articleInfoResp) {
if (articleInfoResp instanceof BannerResp) {
banner[0] = ((BannerResp) articleInfoResp).getData();
} else if (articleInfoResp instanceof ArticleInfoResp) {
articleList[0] = ((ArticleInfoResp) articleInfoResp).getData();
}
}
@Override
public void onError(Throwable e) {
mView.onLoadDiscoveriesFailed();
}
@Override
public void onComplete() {
mView.onDiscoveriesPrepared(banner[0], articleList[0]);
Log.d(TAG, "loadData:getDiscoveryData onComplete: ");
}
});
}
3.//将所有正在处理的Subscription都添加到CompositeSubscription中。统一退出的时候注销观察
private CompositeDisposable mCompositeDisposable;
//在界面退出等需要解绑观察者的情况下调用此方法统一解绑,防止Rx造成的内存泄漏
public void dispose() {
if (mCompositeDisposable != null && !mCompositeDisposable.isDisposed()) {
mCompositeDisposable.dispose();
}
}
4.Android SDK中 DefaultTransformer、NewThreadTransformer与compose : 对流进行变换操作
5.多个流事件一个接一个:包装成Observable,使用Observable流(flatmap)
多个observable封装flatmap,错误返回值与成功后要做的事的返回值是一样的。(如何确定每件事的返回值?根据是否需要传数据,后面的逻辑需要什么。)
将回调转为observable?为什么不能是完成后Observable.just出去?, 如何确定每件事的返回值?根据是否需要传数据 ?是否需要 MessageDataResponse<Data>
return Observable.create(new ObservableOnSubscribe<MessageResponse>() {方法 emitter出去}
public Observable<MessageDataResponse<Map<Long, List<SingleSportData>>>> getSingleSportDatas(long startTime, long endTime)
API返回observable
Observable.just() 万事皆可Observable.just,
flatmap流,多个接口流,return 第一个调返回Observabvle的接口,或者是自己Observable.just(万事)出来一个Observable.然后往下走flatmap (e.g. loginhelper.login()/getSportHealthDatas())
多个返回Observabvle的相同的接口/函数,for循环flatmap出obsStart=obsStart.flatmap()。注意,定义一个index,因为异步与调用主逻辑不在一个线程(e.g.getSingleSportData())
sportHealthData数据需要拼接,数据异步获取,每次flatmap成功保存中间数据,activityMaps[0] = resp.getData();sleepMaps[0] = resp.getData();最后mergeData(activityMaps[0], sleepMaps[0])
flatmap不是一上来就判断getsuccess(我们把上一步接口的返回值都包成Observable<MessageResponse>了,所以判断),需要根据业务(上传时,flatmap起始的Observable.just(activityData)就是判断if (null == activityDataList))
observable.flatMap(new Function<ResponseModel, ObservableSource<ResponseModel>>() {
@Override
public ObservableSource<ResponseModel> apply(ResponseModel responseModel) throws Exception {
-
6.生产一个observable
Observable.create(new ObservableOnSubscribe<List<SportSumData>>() {
@Override
public void subscribe(ObservableEmitter<List<SportSumData>> emitter) throws Exception {emitter.onNext(sportUploadList); emitter.onComplete(); } });
7.流有多个或者不确定是否上传,可以考虑将流都构造出来:Observable。create();或者本身就是Observable返回值的,统一使用concat/merge等操作符上传。
上传是异步的,使用AtomicInteger或计数串行上传。 AtomicInteger count = new AtomicInteger(0);
lamada表达式里需要更新的值,需要在外部定义成final
数据库:
预编译:// String sql = "delete from ? where ? = '?'";
// Connection connection = DriverManager.getConnection();
// PreparedStatement ps = connection.prepareStatement(sql);
// try {
// ps.setString(1, "tb_userinfo");
// ps.setString(2, "projectCode");
// ps.setString(3, projectCode);
// } catch (SQLException e) {
// e.printStackTrace();
// }
连着两步操作数据库,需要事务( database.beginTransaction();try{do some db operations database.setTransactionSuccessful(); }finally{database.setTransactionSuccessful();})
注解:
Hiresearch的注解的使用:
1.定义注解类、、(元注解的修饰,啥时候起作用,只针对哪些成员起作用,要继承不)
2.注解的处理逻辑定义(
3.注解继承,是否有效,,,需要添加@inherited注解,且父类的抽象方法不能被继承
//获取元数据名称及元数据版本号
@HiResearchMetadata
public HiResearchMetadataInfo getHiResearchMetadataInfo(Class<? extends HiResearchBaseMetadata> hClass) {
//如果没有HiResearchMetadata 注解,则取类名作为元数据名,默认版本号为"1"
HiResearchMetadataInfo hiResearchMetadataInfo = new HiResearchMetadataInfo(hClass.getSimpleName(), "1");
Annotation[] classAnnotations = hClass.getAnnotations();
if (null != classAnnotations) {
for (Annotation annotation : classAnnotations) {
if (annotation instanceof HiResearchMetadata) {
// 从注解中获取元数据名称及版本号
HiResearchMetadata hiResearchMetadata = (HiResearchMetadata) annotation;
hiResearchMetadataInfo.setName(hiResearchMetadata.name());
hiResearchMetadataInfo.setVersion(hiResearchMetadata.version());
break;
}
}
}
return hiResearchMetadataInfo;
})
@interface HiResearchField
( //从注解获取
Annotation[] annotations = field.getAnnotations();
if (null != annotations) {
for (Annotation annotation : annotations) {
if (annotation instanceof HiResearchField) {
HiResearchField hiResearchField = (HiResearchField) annotation;
if (!Strings.isNullOrEmpty(hiResearchField.name())) {
hiReseaerchMetadataSerializeField.setSerializeFieldName(hiResearchField.name());
}
break;
}
if (annotation instanceof HiResearchAttachmentField) {
HiResearchAttachmentField hiResearchField = (HiResearchAttachmentField) annotation;
if (!Strings.isNullOrEmpty(hiResearchField.name())) {
hiReseaerchMetadataSerializeField.setSerializeFieldName(hiResearchField.name());
}
hiReseaerchMetadataSerializeField.setFieldType(HiResearchDataType.ATTACHMENT);
break;
}
}
}
return hiReseaerchMetadataSerializeField;)
@HiResearchDataType
上面
@HiResearchAttachmentField:
枚举:SensorProUnitePPGConfigure ,最好@IntDef
@IntDef/@StringDef本身是个Android中提供的一种注解,用于替代枚举的使用。
使用:
添加依赖:compile 'com.android.support:support-annotations:22.0.0'
@IntDef({STRING,TEXT,BIGINT,BOOLEAN,DOUBLE,ATTACHMENT,
ARRAY,
HEARTRATE,RRI,
BLOODPRESSURE,BLOODSUGAR,
SLEEPSTATISTICS,
CALORIESBURNED,DISTANCE,STEPCOUNT,
BODYHEIGHT,BODYWEIGHT})
@Retention(RetentionPolicy.SOURCE)
public @interface HiResearchDataType { //通过枚举,限制其他值不能传入,但是为什么要定义HiResearchDataType注解类?在哪里解析?限制变量作用,无实际逻辑,知识做值。https://www.kancloud.cn/zhangzihao/articles/325612
public static final int STRING = 0x00000001;
public static final int TEXT = 0x00000002;
public static final int BIGINT = 0x00000003;
public static final int BOOLEAN = 0x00000004;
public static final int DOUBLE = 0x00000005;
public static final int ATTACHMENT = 0x00000006;
public static final int ARRAY = 0x00000010;
public static final int HEARTRATE = 0x00000021;
public static final int RRI = 0x00000022;
public static final int BLOODPRESSURE = 0x00000031;
public static final int BLOODSUGAR = 0x00000032;
public static final int SLEEPSTATISTICS = 0x00000041;
public static final int CALORIESBURNED = 0x00000051;
public static final int DISTANCE = 0x00000052;
public static final int STEPCOUNT = 0x00000053;
public static final int BODYHEIGHT = 0x00000061;
public static final int BODYWEIGHT = 0x00000062;
}
泛型:
void onResponse(int err_code, T objData);数据T转为需要的类型,例如List?
泛型参考:SharedPreferencesJsonDAO,注意提前声明类型<T>,记得通配符super和extends,
分类别处理逻辑时,instanceof分支(UserInfoDao)
<? extends T > 所有的泛型类必须<=类T,父类上限是T,?是T的子类。 不能往里存(子类的内容/粒度大于父类,不知道存哪里啊),只能往外取
<? super T> 所有的泛型类必须>=类T,子类的下限是T,?是T的父类。 存正常(基类的粒度/内容都小于T,都可以存下),取必须赋给OBject(不知道父类super向上究竟的界在哪里,只能取最大父类Object)
PECS:producer extends consumer super:频繁存/set要有最大粒度的底盘兜住,所以用super;频繁取/get,用extends,可以取出来放到指定盘子里。
类型转换原则:(内容少的->内容多的,粒度小的->粒度大的,内存小空间->大空间),少的部分赋默认值/方法。
int->double,可以,知识其他的内存填默认值0;
double->int,不可以,内容/精度丢失。
基类=子类(基类指向子类,基类小内容内存覆盖子类多内容,缺失的部分赋默认值,调用子类的默认构造函数);
子类=父类(子类大内存扣在父类小内存上,丢失)。
https://blog.csdn.net/sjm19901003/article/details/44743801
编码:
hexUtil&& Integer.parseInt(tlvs.get(l).getTag(), 16)
Base64.decode(输入String 二进制后,每6位分割,查找Base64的64个字符映射为另一个串)
String digest = BaseEncoding.base64().encode(messageDigest.digest());
加密:
encrypt(String key密钥, String ivParameter偏移向量, String data)
Java.Cipher加密器= EncryptUtil.initAESCipher(publicKey, ivParameter);
EncryptHelper(jkstore加密)&&EncryptUtil(SHA。AES加密)
蓝牙:
获取Mac(根据系统版本,不同方式获取Mac地址:getLocalMacAddressFromWifiInfo、getLocalInetAddress、根据IP地址获取MAC地址、android 7.0及以上扫描各个网络接口获取mac地址getMachineHardwareAddress、根据busybox获取本地Mac)
日期工具类:
common包 DateUtil/TimeUtils, Calender(获取日月天,丰富API) && Date && timeStamp
String.format(context.getString(R.string.format_total_time), hour, minute, second);
华为账号登录:(HMSAgent)
Hms登录需要的activity有没有在manifest中配置
HMSAgent:init()初始化在Mainapplication 中,Login时连接connect(),内部类Hwid.signIn()登录HMS
restful api:
为了适配不同终端平台(Web,iOS和Android),使用同一套接口访问资源。
URL::authservice/v1/auth/hwAccountSignIn
public <T> T getClient(Class<T> service) {
List<Converter.Factory> factories = new ArrayList<>();
factories.add(GsonConverterFactory.create(GsonUtils.GSON));
//OkHttpClient
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (证书可信) {
}
builder.connectTimeout().addInterceptor();//配置
builder.addInterceptor(interceptors);
OkHttpClient okHttpClient = builder.build();
//Retrofit
Retrofit.Builder builderRetrofit = new Retrofit.Builder();
设置URL和client(OkHttpClient)
Retrofit retrofit = builderRetrofit.addConverterFactory(factories)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
retrofit.create(service);
}
interceptor:
在OkHttp内部是使用拦截器来完成请求和响应,利用的是责任链设计模式,可以用来转换,重试,重写请求的机制。
覆写 @Override
public Response intercept(Chain chain) throws IOException实现想做的功能(压缩。日志等,例:ErrorResponseInterceptor)
factorires.add(GsonConverterFactory.create(GsonUtils.GSON));处理请求(Observable<Respone>),不然要覆写那四个函数,代码量少,可扩展(coede处理情况,修改的话,就直接修改factory)
实际请求执行:RealCall.execute(创建RealCall,各个interceptors,责任链执行,返回response: Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0, originalRequest);return chain.proceed(originalRequest);)
tips:
从SDK获取工具类
多个参数个数略有差异的函数,在最全的里面都定义好,其他的填充默认值(null等等看业务需要),构造函数
错误码值需要考虑分类,如服务端就5XX。
Convertor 参考bridge的Convertor:convert bean to map
UserAccountDao extends SharedPreferencesJsonDAO sharedpreferences的一个实现,考虑了不同signin信息的泛型类 ,instanceof Long
参数非空:@NonNull修饰,Optional
三目运算符的使用,if就想到
callback里面可以放置变量
多个参数,有的时候传入,有的时候不传入,需要构造一个通用的全参功能函数,其他传入默认值,在全参代码里需要判断。(多参构造函数)
不要在外面判断功能分支,在内部(setView(“无数据”);setView(“有数据”);-》setView(null);setView(data){if(null=data){}……})
页面与逻辑分离,页面的异步(通过控件进行异步等待,如登录控件。注意控件间的enalbe控制)
多个控件的监听,可以不单独写,类implements View.OnClickListener,直接.setOnClickListener(this);公用一个onClick{内部分id,实现逻辑} ,参考updateDialog
多用注解,清晰
异步:
RXjava,在结果里处理后续操作(页面,数据库……提前做成一个interface())
回调定义一个结束接口callback.onFinish(),后续在onFinish()里处理:例如,同步设备侧数据,写完数据库后调callback.onfinish,在onfinish里读取数据库
异步优势考虑使用标志位,结束就置位,其他地方一直检查,,, MonitorService.getInstance().updateStatus(getTaskType(), TaskStatus.START);
多样类似的事,考虑抽成抽象类,例如获取设备侧的不同数据,定一个abstract class syncHelper,syn抽象函数,greendao的session,读取泛型数据库函数,,,继承出多个如HRSyncHelper/SleepSyncHelper,实现具体行为
通用流程也可以考虑做成行为接口(public class RealTimeAccServiceImpl extends UploadDataService<List<AccData>> implements RealTimeService<List<AccData>> {),不一定都是抽象类
子类不喜欢,override父方法, @Override 重写,可实现多态
for里面不要新建变量/try-catch,性能差
一个类中常用的多个字段(计数,标志位),可以考虑抽取一个类
每个模块自己的错误码加前缀
画图注意有来有回,参考HMS或者网络通信图
日结表