## 问卷组件



### 版本历史

| 版本号 | 更新时间  | 更新描述             |
| ------ | --------- | -------------------- |
| 1.0.1  | 2022.6.15 | 问卷组件上线         |
| 1.1.3  | 2023.4.6  | 图片选择组件更换     |
| 1.2.4  | 2023.8.7  | 修复已知问题         |
| 1.2.6  | 2023.12.1 | 升级依赖Glide4.x版本 |
| 1.2.7  | 2024.2.2  | 修复已知问题         |



### 组件引入

注意：所有使用互动组件必须要引入basemodule库，最新版本见 [互动组件对接文档](互动组件/互动组件对接文档)

项目根目录build.gradle引入：

```groovy
 repositories {
     maven { url 'http://nexus-app.bokecc.com/repository/sdk-group/' }
 }
```


module的build.gradle引入：

```java
 dependencies {
     api ('com.bokecc:basemodule:x.x.x')
     api ('com.bokecc.module:questionnairemodule:x.x.x')
 }
```

Application的onCreate方法中，调用`DWLiveEngine.init`初始化dwlivesdk后，添加代码：

```java
QuestionnaireInteractSDK.getInstance().init(app);
```



### 1. 组件描述

问卷组件是基于基础组件库扩展的问卷组件服务，通过IM组件实现问卷活动事件的推送，包括获取问卷列表，获取问卷详情、发送问卷等功能，为业务方提供问卷能力。问卷组件包含管理器和基于管理器实现的UI界面，接入方可基于管理器对外API实现完全自定义UI的问卷，也可直接集成组件SDK提供的UI。



### 2. 组件架构

#### 2.1 组件架构图

![image-20220506100931572](组件架构图.png)

#### 2.2 核心对外API

IQuestionnaireManager内部唯一实现类为QuestionnaireManagerImpl

| 作用             | API                                                          |
| ---------------- | ------------------------------------------------------------ |
| 初始化           | void init(BaseQuestionnaireListener listener, String userId, String roomId, String interactToken) |
| 获取问卷列表     | getQuestionnaireList(IBaseCallBack<QuestionnaireListBean> callBack) |
| 获取问卷详情     | getQuestionnaireDetail(String userCode,String formCode,IBaseCallBack<QuestionnaireListBean.DataDTO> callBack) |
| 提交问卷         | submit(String formCode,String formContent,IBaseCallBack<Object> callBack) |
| 获取问卷填写状况 | getQuestionnaireIsComplete(String formCode, IBaseCallBack<Integer> callBack) |
| 重连             | reConnect()                                                  |
| 释放             | release()                                                    |

API接口代码

```java
public interface IQuestionnaireManager {

    /**
     * @param listener      监听
     * @param userId        viewerId
     * @param roomId        房间id
     * @param interactToken token
     */
    void init(BaseQuestionnaireListener listener, String userId, String roomId, String interactToken);

    /**
     * 获取问卷列表
     */
    void getQuestionnaireList(IBaseCallBack<QuestionnaireListBean> callBack);
    /**
     * 获取问卷详情
     */
    void getQuestionnaireDetail(String userCode,String formCode,IBaseCallBack<QuestionnaireListBean.DataDTO> callBack);
    
    /**
     * 获取问卷是否填写过
     * @param formCode formCode
     * @param callBack 回调
     */
    void getQuestionnaireIsComplete(String formCode, IBaseCallBack<Integer> callBack);

    /**
     * 提交
     */
    void submit(String formCode,String formContent,IBaseCallBack<Object> callBack);


    /**
     * 重连
     */
    void reConnect();

    /**
     * 释放
     */
    void release();

}
```







### 3. 组件接入

#### 3.1 使用组件提供UI

问卷ViewGroup为QuestionnaireMainLayout

1. 登录业务SDK（云直播等）

2. xml中添加QuestionnaireMainLayout

   ```xml
   <?xml version="1.0" encoding="utf-8"?>
   <LinearLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:background="#eeeeee"
       android:orientation="vertical">
   
   
       <com.bokecc.questionnaire.ui.QuestionnaireMainLayout
           android:id="@+id/questionniare_layout"
           android:layout_width="match_parent"
           android:layout_height="match_parent"/>
   
   </LinearLayout>
   ```

3. 设置QuestionnaireMainLayout的Listener

   ```java
   questionnaireMainLayout.setQuestionnaireMainListener(new IQuestionnaireMainListener() {
               @Override
               public void onQuestionnairePush() {
                   Toast.makeText(QuestionnaireTestActivity.this, "onQuestionnairePush", Toast.LENGTH_SHORT).show();
               }
   
               @Override
               public void onCloseClick() {
                   Toast.makeText(QuestionnaireTestActivity.this, "onCloseClick", Toast.LENGTH_SHORT).show();
               }
           });
   ```
   
4. 初始化组件

   1. 获取token-初始组件需要传递参数token，可以通过业务SDK（云直播等）提供的对外API获取token

   2. 使用业务SDK提供的配置信息初始化组件SDK

      代码示例（以云直播为例）：


   ```java
   private void initQuestionnaireModel() {
           if (DWLiveCoreHandler.getInstance().getInteractionConfigure()!=null){
               InteractionConfigure interactionConfigure = DWLiveCoreHandler.getInstance().getInteractionConfigure();
               if (interactionConfigure.getQuestionnaire()!=null){
                   InteractionConfigure.Questionnaire questionnaire = interactionConfigure.getQuestionnaire();
                   if (questionnaire.getSwitch()>0){
                       //推送方式：0:手动推送 1:进入直播时 2：结束直播时
                       final int sendMode = questionnaire.getSendMode();
                       if (questionnaireSendMode!=null){
                           questionnaireSendMode.set(questionnaire.getSendMode());
                       }
                       //活动编码
                       final String activityCode = questionnaire.getActivityCode();
                       //表单编码
                       final String formCode = questionnaire.getFormCode();
   
                       String viewerId = "";
                       try {
                           viewerId = DWLiveCoreHandler.getInstance().getViewer().getId();
                       } catch (Exception e) {
                           e.printStackTrace();
                       }
                       String roomId = "";
                       try {
                           roomId = DWLiveCoreHandler.getInstance().getRoomInfo().getId();
                       } catch (Exception e) {
                           e.printStackTrace();
                       }
                       final String finalViewerId = viewerId;
                       final String finalRoomId = roomId;
                       DWLive.getInstance().getInteractiveToken(new BaseCallback<String>() {
                           @Override
                           public void onError(String s) {
                               Toast.makeText(mContext, "获取组件token失败:" + s, Toast.LENGTH_SHORT).show();
                           }
   
                           @Override
                           public void onSuccess(final String token) {
                               questionniareLayout.setQuestionnaireMainListener(new IQuestionnaireMainListener() {
                                   @Override
                                   public void onQuestionnairePush() {
                                       //收到问卷推送 显示问卷布局
                                       showQuestionnaire(true);
                                   }
   
                                   @Override
                                   public void onCloseClick() {
                                       questionniareLayout.setVisibility(View.GONE);
                                   }
                               });
   
                               questionniareLayout.initialize(
                                       new QuestionnaireBaseLayout.QuestionnaireConfig()
                                               .setInteractToken(token)
                                               .setUserId(finalViewerId)
                                               .setRoomId(finalRoomId)
                                               .setFormCode(formCode)
                                               .setActivityId(activityCode)
                                               .setSendMode(sendMode)
                               );
   //                            if (sendMode==1){
   //                                showQuestionnaire();
   //                            }else if (sendMode==2){
   //                                //设置直播结束后展示问卷列表
   //                            }
                           }
                       });
                   }
   
               }
           }
       }
   
   ```

5. 销毁组件

   ```java
   @Override
       protected void onDestroy() {
           super.onDestroy();
            if (questionniareLayout!=null){
               questionniareLayout.release();
           }
       }
   ```



#### 3.2 使用组件管理器+自定义UI

问卷管理器实现类为QuestionnaireManagerImpl，对外方法参照IQuestionnaireManager，UI可以参考QuestionnaireBaseLayout以及其子类QuestionnaireMainLayout实现



### 4. 混淆配置

混淆配置

```
-keep class com.bokecc.**{*;}
-keep interface com.bokecc.**{*;}
```



### 5. 组件库依赖

```groovy
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.bokecc.gson:gson:2.9.0'
implementation 'com.bokecc.widget:pickerview:0.0.2'
implementation 'it.sephiroth.android.library.imagezoom:library:1.0.4'
implementation 'com.aliyun.dpa:oss-android-sdk:2.9.11'
//图片选择框架
implementation 'com.zhihu.android:matisse:0.5.3-beta3'
```