---
# System prepended metadata

title: 环节一 自夸：秀出本方代码的亮点和特点

---

# 环节一 自夸：秀出本方代码的亮点和特点

1. 0error0warring

2. 




# 环节二 互捧：找出对方代码的闪光点

1. 使用了开源的插件化框架small，项目功能相对独立，可以供其他项目自由组合加载
2. 布局xml文件命名清新











# 环节三 自惭： 找出自己代码的不足和问题

1. 出于统一处理的原因，所有的view外会有一层多余的FrameLayout，也一直在想办法去掉

2. MagicCarousel.kt 

```kotlin
// 要判断isDisposed()后再dispose

override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        mTimer?.dispose()
    }

```

3. MagicRecyclerAdapter.kt

```kotlin
// 禁止重用时设置viewId使用Random.nextInt()实现 无法确保唯一性 

fun addItem(item: BaseWidgetModel) {

        val typeIndex = WidgetMapping.indexForType(item.type)
        if (item.adapterTypeId == 0) {
            if (item.reuseId == 0) {
                //不重用
                item.adapterTypeId = (items.size + Random.nextInt(10000)) * 100 + typeIndex
            } else {
                //重用
                item.adapterTypeId = item.reuseId * 100 + typeIndex
            }
        }
        items.add(IMagicAdapterItem(WidgetMapping.indexForType(item.type), item))
    }

```

4. MagicContainerView.kt

```kotlin
fun analysis(model: MagicPagerModel) {
         // toJsonString 在页面复杂时解析耗时 卡页面 
        toJsonString()
        //先清空****
        clean()
       
        ...
```





# 环节四 互踩：揪出对方代码的漏洞和不足

1. ui设计所有资源文件中text文本写死，没有考虑扩展，复用，语言适配
```
    <TextView
        android:id="@+id/content"
        android:layout_width="210dp"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="290dp"
        android:layout_marginLeft="50dp"
        android:layout_marginTop="15dp"
        android:gravity="right"
        android:text="如接受挑战，本场欢乐斗惩罚时间结束后，将立刻与对方主播开启欢乐斗复仇挑战点击弹窗以外的地方可收起弹窗"
        android:textColor="#80ffffff"
        android:textSize="13sp" />

    <TextView
        android:id="@+id/ok_btn"
        android:layout_width="200dp"
        android:layout_height="44dp"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="220dp"
        android:layout_marginLeft="55dp"
        android:layout_marginTop="38dp"
        android:background="@drawable/bg_ave_btn_3"
        android:gravity="center"
        android:text="我知道了"
        android:textColor="#ffdd00"
        android:textSize="15sp" />
```

2. 错误的清除动画，mTextView.startAnimation开启的动画 translateAnimation.cancel()是无效的
需要调用mTextView.clearAnimation();
  ```
... 
   mTextView.startAnimation(translateAnimation);

//清除属性动画
public void reserverAnimation() {
if  (translateAnimation != null) {
translateAnimation.cancel();
translateAnimation = null;
}
}
```


3. 包名应小写
![](https://i.imgur.com/kNFqixF.png)

4. 基类应该写成抽象类
```
public class PkBaseFragment extends Component 
...
public class PkBasePopupComponent extends BasePopupComponent 
...
public class BasicController implements EventCompat, Disposable {
```


5. 多处类名、成员变量命名不规范，类名：首字母大写，多个单词连接，单词首字母大写，变量：首字母小写，多个单词连接，第二个单词开始首字母大写， 使用拼音命名变量名
```
class ChannelPK_OnPkFriSwitch_EventArgs(
    var m_type: Int,
    var result: Int,
    var err_desc: String,
    extendInfo: Map<String, String>
)

public static final int GIFT_BANGBANGTANG = 1003; //棒棒糖的id

@PKModuleConfig(mount = {PKModel.MODEL_NOR, PKModel.MODEL_NEW})
public class PKFocusModule extends LayoutModule {

    private static final String TAG = "[11-欢乐斗-PKFocusModule]";
    private LinearLayout guanzhuLayout;
    private TextView guanzhuText;
    private ImageView guanzhuImageView;

    }

```

6. 多处访问修饰词大于实际需要，具体看以下文件
```
GiftPkProtocol
RecycleViewOnScrollListener
BatchingListUpdateCallback
RecycleViewOnScrollListener
```

7. 多处不必要判断
GiftPKMainComponent  341行
```
//设置队长
    private void setDefaultTeamLeader(List<MicTopInfo> micList, boolean isFirst) {
        if (micList.size() == 1) {
            MicTopInfo info = micList.get(0);
            ICoreManagerBase.getCore(IGiftPkCore.class).saveSelectTeamBlue(MicListAdapter.MicTopInfoEx.build(info));
            if (info != null && null != info.name) {
                if (isFirst) {
                    requestUserInfo(info);
                }
                userId1 = info.uid;
                tvTeamBlueName.setText(getString(R.string.gift_pk_team_name, info.name));
            }
        } else if (micList.size() > 1) {
            //此处已判断 size >1
            MicTopInfo info = micList.get(0);
            if (isFirst) {
                requestUserInfo(info);
            }
            ICoreManagerBase.getCore(IGiftPkCore.class).saveSelectTeamBlue(MicListAdapter.MicTopInfoEx.build(info));
            //多余判null
            if (info != null && null != info.name) {
                userId1 = info.uid;
                tvTeamBlueName.setText(getString(R.string.gift_pk_team_name, info.name));
            }

            MicTopInfo info2 = micList.get(1);
            if (isFirst) {
                requestUserInfo(info2);
            }
            ICoreManagerBase.getCore(IGiftPkCore.class).saveSelectTeamYellow(MicListAdapter.MicTopInfoEx.build(info2));
            //多余判null
            if (info2 != null && null != info2.name) {
                userId2 = info2.uid;
                tvTeamYellowName.setText(getString(R.string.gift_pk_team_name, info2.name));
            }
        }
    }
```

8. RxJava interval操作符停止时 直接调用dispose()无法确保立刻终止已启动的计时器， 应设置一个标志位

```kotlin
  /**
     * 开启匹配计时器
     */
     
    // 设置停止标记位 ： private AtomicBoolean mStopper = new AtomicBoolean(true);
    public void startTimer() {
        if (countDownObservable != null && !countDownObservable.isDisposed()) {
            return;
        }
        Observable.interval(1, TimeUnit.SECONDS)
                // .takeWhile(tick -> mStopper.get()) 
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        countDownObservable = d;
                    }
                ...
                });
    }

    /**
     * 关闭计时器 
     */
    public void stopTimer() {
        if (countDownObservable != null && !countDownObservable.isDisposed()) {
            countDownObservable.dispose();
        }
    }
```
9. pkBarComponent 
进行float类型等值比较时， 不应该使用 == ，如果一个是字面量一个是计算量 会导致 == 判断失误
```kotlin
 @BusEvent
    public void onVideoCompnoentRateChange(VideoCompnoentRateChangeAction busEventArgs) {
        float rate = busEventArgs.getRate();
        if (rate > 0.2 && mRatio != rate) {
            if (!isLandScape()) {
                VideoUtils.setRatio(rate);
                updateUI();
            }
        }
    }
```
10. PKModuleDiff

String类型比较应使用.equals()而非 "=="

```java 
public static boolean equals(List<String> lastModel, List<String> currentModel) {
        if (lastModel == currentModel) {
            return true;
        }
        ...
        // 使用了 “==” 比较的是String对象的地址
        for (int i = 0; i < length; i++) {
            if (lastModel.get(i) != currentModel.get(i)) {
                return false;
            }
        }
        return true;
    }

```
11. 在onCreateDialog中尝试获取window，没有进行判空

PkMvpRankPopDialog 

```java
 @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog mDialog = super.onCreateDialog(savedInstanceState);
        mDialog.setCanceledOnTouchOutside(true);
        mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        // 对getWindow进行判空
        mDialog.getWindow().setBackgroundDrawableResource(R.color.midtransparent);
        mDialog.getWindow().setGravity(Gravity.CENTER);
        return mDialog;
    }

```


12. PluginEntryPoint 入口mainEntry方法太多if else，耦合严重，每加个插件都会改动这个类，影响现有逻辑，不利于扩展
建议：用策略模式，或者责任链模式替代
```
@Override
    public void mainEntry(final Intent intent, final Activity activity, ViewGroup parentView) {
         ...
        /**
         * 欢乐斗插件
         */
        if (action.equals(ChannelPkDisPatcher.PLUGINCNETER_PLUGIN_START) && (taskId == ChannelPkDisPatcher.TASK_ID)) {
            // 开启欢乐斗插件
            isPluginActive = true;
            Bundle extendBundle = intent.getBundleExtra("extend");
            // 活动条点击直接开启欢乐斗[需要后台配置]
            if (extendBundle != null && extendBundle.containsKey(TAG_BUSINESS_ID)
                    && extendBundle.getString(TAG_BUSINESS_ID).equals(RANDOM_BUSINESS_ID)) {
                ...
            } else if (extendBundle != null && extendBundle.containsKey("simpleVer")
                    && extendBundle.getInt("simpleVer") == 1) {
                // 开启简版欢乐斗[目前已经下架]
         
            } else {
                // 开启欢乐斗面板[分主动拉取和被动拉取]
              
            }

            EarningSatelliteUtils.postSatelliteEarningOnly("ysfn_hp_pk_start", null);
        } else if (action.equals(ChannelPkDisPatcher.PLUGINCENTER_PLUGIN_CLOSE)
                && (taskId == ChannelPkDisPatcher.TASK_ID)) {
            // 关闭欢乐斗插件
           
        } else if (action.equals(ChannelPkDisPatcher.PLUGINCNETER_PLUGIN_START)
                && (taskId == ChannelPkDisPatcher.LUCKY_ZONE_TASK_ID)) {
            /**
             * 天命圈插件
             */
            // 开启天命圈插件
            
        } else if (action.equals(ChannelPkDisPatcher.PLUGINCENTER_PLUGIN_CLOSE) // 关闭天命圈插件
                && (taskId == ChannelPkDisPatcher.LUCKY_ZONE_TASK_ID)) {
            closePlugin(activity);
        } else if (action.equals(ChannelPkDisPatcher.PLUGINCNETER_PLUGIN_START)
                && (taskId == ChannelPkDisPatcher.HOTPOWER_TASK_ID)) {
            /**
             * 热力时刻插件
             */
            // 开启热力时刻插件
            
        } else if (action.equals(ChannelPkDisPatcher.PLUGINCENTER_PLUGIN_CLOSE) // 关闭热力时刻插件
                && (taskId == ChannelPkDisPatcher.HOTPOWER_TASK_ID)) {
            closePlugin(activity);
        } else if (action.equals("PK_VIEW_LIVE")) { // 更新欢乐斗PK条
            
        } else if (action.equals(ChannelPkDisPatcher.PLUGINCNETER_PLUGIN_START) && (taskId == GiftPkConstants.TASKID)) {
            /**
             * 礼物PK插件
             */
            // 开启礼物PK插件
            
        } else if (action.equals(ChannelPkDisPatcher.PLUGINCENTER_PLUGIN_CLOSE) && (taskId == GiftPkConstants.TASKID)) {
            // 关闭礼物PK插件
     
        } else if (GiftPkConstants.CLOSE_GIFT_PK.equals(action)) {
            // 调用pk关闭协议
            // 退出礼物PK插件
         
        }
    }
```



13. 多处单例模式没有考虑并发线程安全
建议：使用dcl或者静态内部类单例模式
```
     public static ChannelPkDisPatcher init(FragmentActivity activity) {
        if (sInstance == null) {
            sInstance = new ChannelPkDisPatcher(activity);
        }
        return sInstance;
    }
    
      public static ScreenUtil getInstance() {
        if (mInstance == null) {
            mInstance = new ScreenUtil();
        }

        return mInstance;
    }
```

14. 多处命名使用拼音

```
public static final int GIFT_BANGBANGTANG = 1003; //棒棒糖的id
public static final int GIFT_GUZHANG = 1006; //鼓掌的id
```

15. 多处出现statement has empty body