tiCourse

  1. Course
  2. CourseManager.getInstance().getCurrCourseId();
  3. tiCourse
  4. CetTypeLogic.getCetType()
  5. courseSetPrefix 对应 yy46j 通过 Const.CET 来索取
  6. tiCourse 对应 yy4j 或者 yy6j

连接四六级数据库命令

  1. mysql -h10.51.101.246 -p3306 -uenglish -p'English!@#' ape_english
  2. show databases;
  3. use ape_english;

怎么屏蔽掉一个 router

  1. com.fenbi.android.yingyu.router.MemberRightsPage
  2. @Route(value = {"/member/rights", "/{coursePrefix}/member/center", "/{coursePrefix2}/member", "/member/center"}, priority = 1)
  3. public class MemberRightsPage implements IRouting {
  4. // com.fenbi.android.module.vip.rights.MemberRightsActivity
  5. @Override
  6. public boolean routing(Context context, Page page, Callback callback) {
  7. // Cet has no vip logic
  8. return true;
  9. }
  10. }

取 Exception

Throwable

  1. debugParams.put("exception", ExceptionUtils.dump(e));

多文件上传

  1. com.fenbi.android.cet.camera.CameraApi#doUpload

intent 取数据

  1. 打印所有参数
  2. URLDecoder.decode(getIntent().toUri(0))
  3. LogUtils.e(URLDecoder.decode(getIntent().toUri(0)));
  4. 获取 router
  5. getIntent().getStringExtra(Const.KEY_ROUTER_PATH);
  6. @Override
  7. protected void onNewIntent(Intent intent) {
  8. super.onNewIntent(intent);
  9. if (intent != null) {
  10. tiCourse = intent.getStringExtra("tiCourse");
  11. // 必须先转成字符串
  12. tagId = Integer.parseInt(intent.getStringExtra("tagId"));
  13. tagName = intent.getStringExtra("tagName");
  14. }
  15. renderEntranceParams();
  16. recyclerView.scrollTo(0, 0);
  17. cetRefreshView.autoRefresh();
  18. }

页面参数

  1. 页面参数
  2. com.fenbi.android.business.cet.common.utils.CetPageUtil

复制到剪切板

  1. com.fenbi.android.module.yingyu.mkds.home.MkdsHomepageActivity#putTextIntoClip

用户昵称

  1. // com.fenbi.android.module.yingyu.training_camp.home.CampUtils#getUserAccountName
  2. public static String getUserAccountName() {
  3. String nickName = UserLogic.getInstance().getNickName();
  4. if (StringUtils.isEmpty(nickName)) {
  5. return UserLogic.getInstance().getUserAccount();
  6. }
  7. return nickName;
  8. }

用户头像.短地址

  1. public static String getNormalImageUrl(String image) {
  2. if (!TextUtils.isEmpty(image) && image.startsWith("http")) {
  3. return image;
  4. }
  5. return String.format(Locale.getDefault(), "%s/api/images/%s?width=%d&height=%d", KeApiUrl.getCdnRootUrl(), image, NORMAL_SIZE, NORMAL_SIZE);
  6. }

时间格式化

  1. com.fenbi.android.yingyu.home.home.adapter.CetHomeHeaderHolder#renderAppClockIn
  2. com.fenbi.android.yingyu.appsign.AppSignUtil#chartYPopText
  3. com.fenbi.android.yingyu.appsign.learndata.LearnDataActivity#getWatchLectureDurationFormat
  4. 每天零时零秒
  5. com.fenbi.android.ke.util.TimeUtils#getDayStart

数据转换

  1. @NonNull
  2. public static long[] toArray(@Nullable List<Long> list) {
  3. if (ObjectUtils.isEmpty(list)) {
  4. return new long[0];
  5. }
  6. long[] result = new long[list.size()];
  7. for (int i = 0; i < result.length; i++) {
  8. result[i] = list.get(i);
  9. }
  10. return result;
  11. }
  12. @NonNull
  13. public static List<Long> toList(@Nullable long[] array) {
  14. if (ObjectUtils.isEmpty(array)) {
  15. return new ArrayList<>();
  16. }
  17. List<Long> list = new ArrayList<>();
  18. for (long num : array) {
  19. list.add(num);
  20. }
  21. return list;
  22. }

线上日志调试

  1. implementation project(':lib:log-catcher')
  2. Map<String, String> params = new HashMap<>();
  3. params.put("isDestroyed", String.valueOf(isDestroyed()));
  4. params.put("viewName", "lectureBg");
  5. DebugLogger.getInstance().log("destroyed_activity", params, "");
  6. // 重新登录问题
  7. // * and __topic__ : Login_Fatal and uid: 83383113
  8. DebugLogger.getInstance().log("Login_Fatal", params, "");

数据精确度

  1. 四舍五入, 保留小数点后几位
  2. String.format(Locale.getDefault(), "%.0f%%", 100 * data.getRightRatio());
  3. String.format(Locale.getDefault(), "%.0f%%", 100 * data.getWinRate());
  4. 全舍
  5. String.format(Locale.getDefault(), "%d%%", (int)(100 * data.getRightRatio()));
  6. 格式化数字 W
  7. com.fenbi.android.business.cet.common.utils.RecommendUtil#formatCount

报时器

报时器, 每隔几秒回调一次, 除非主动取消

  1. com.fenbi.android.business.cet.common.logic.TimerLogic

倒计时

  1. com.fenbi.android.business.cet.common.logic.CountDownLogic

失败重试

  1. Observable<RunningStatus> statusObservable = RetrofitUtils.getInstance().getApi(Api.getPath(coursePrefix), Api.class)
  2. .mkdsStatusInfo(String.valueOf(jamId)).retryWhen(new RetryWhenFunction<>(5, new RunningStatus()));

播放本地视频

  1. com.fenbi.android.module.yingyu.training_camp.summary.adapter.LockableStepViewHolder#playSoundEffect
  2. player.setDateResource("rawresource:///" + R.raw.camp_step_open);

关掉 Native debugger

image.png

image.png

截图拼接二维码

image.png

  1. com.fenbi.android.cet.exercise.history.screenshot.ScreenShotViewModel#concatBitmap

不需要挂在 view 树上

  1. child.measure(View.MeasureSpec.makeMeasureSpec(ScreenUtils.getScreenWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.UNSPECIFIED);
  2. child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
  3. Bitmap shotBitmap = PrayDrawShotUtil.shot(shareBinding.bodyView);
  4. doShare(consumer, shotBitmap, path, share, null);

截图分享

SD 卡, 存储位置 “/storage/emulated/0/Download/1653969479078.jpg”

  1. com.fenbi.android.cet.exercise.history.screenshot.ScreenShotViewModel#generatePicPath
  2. com.fenbi.android.module.yingyu.ti.search.solution.SearchSolutionActivity#doShare

Gson

  1. "userAnswers": {
  2. "0": {
  3. "questionId": 4989280,
  4. "answer": {
  5. "answer": "",
  6. "type": 204
  7. }
  8. }
  9. }

怎么取最里面的 answer

  1. private JsonElement userAnswers;
  2. final JsonElement jsonElement = exercise.getUserAnswers();
  3. if (jsonElement == null) {
  4. continue;
  5. }
  6. final JsonElement element = jsonElement.getAsJsonObject().get("0");
  7. if (element == null || ObjectUtils.isEmpty(element.toString())) {
  8. continue;
  9. }
  10. final WriteAnswerWrapper userAnswer = GsonUtils.fromJson(element.toString(), WriteAnswerWrapper.class);

渲染耗时

  1. long timeMillis = System.currentTimeMillis();
  2. Log.e("LogTrack", "[LogTrack] render.100=" + (System.currentTimeMillis() - timeMillis));
  1. Observable<Object> viewObservable = Observable.create(emitter -> {
  2. final ViewZip zip = new ViewZip();
  3. emitter.onNext(zip);
  4. emitter.onComplete();
  5. }).compose(ViewCreatorDebug.debugLogTransformer()).onErrorReturn(throwable -> new ViewZip());
  6. viewObservable.subscribe(new BaseApiObserver<Object>(lifecycleOwner) {
  7. @Override
  8. protected void onSuccessResult(@NonNull Object data) {
  9. if (BoolUtil.isFalse(data instanceof ViewZip)) {
  10. return;
  11. }
  12. ViewZip zip = (ViewZip) data;
  13. // container.removeAllViews();
  14. // container.addView();
  15. }
  16. });