JLChen
2021-12-07 d6a2ca78cc573243a44ff805ac01935fd36bb6d8
2021-12-07 1.调整搜索网关机制
5个文件已添加
7个文件已修改
515 ■■■■■ 已修改文件
HDLSDK/app/src/main/AndroidManifest.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/app/src/main/java/com/hdl/hdlsdk/device/DevicesListActivity.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/app/src/main/java/com/hdl/hdlsdk/device/DevicesListAdapter.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/app/src/main/java/com/hdl/hdlsdk/device/FunctionBean.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/app/src/main/res/layout/activity_devices_list.xml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/app/src/main/res/layout/item_devices_list.xml 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/exception/HDLLinkCode.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/hdl-connect/build.gradle 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java 167 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HdlSocketHelper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDLSDK/app/src/main/AndroidManifest.xml
@@ -12,13 +12,14 @@
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <application
        android:allowBackup="true"
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.HDLSDK">
        <activity android:name=".device.DevicesListActivity"></activity>
        <activity
            android:name=".MainActivity"
            android:exported="true">
HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
@@ -9,6 +9,7 @@
import androidx.recyclerview.widget.RecyclerView;
import android.Manifest;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
@@ -19,6 +20,7 @@
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.google.gson.reflect.TypeToken;
import com.hdl.hdlsdk.device.DevicesListActivity;
import com.hdl.sdk.common.event.EventListener;
import com.hdl.sdk.common.exception.HDLLinkException;
import com.hdl.sdk.common.utils.IdUtils;
@@ -97,6 +99,7 @@
        beans.add(new DemoBean("读取状态"));
        beans.add(new DemoBean("获取场景列表"));
        beans.add(new DemoBean("场景控制"));
        beans.add(new DemoBean("设备功能列表"));
        demoAdapter = new DemoAdapter(beans);
        rv.setAdapter(demoAdapter);
@@ -142,6 +145,10 @@
                    case 7:
                        //获取场景列表
                        controlScene();
                        break;
                    case 8:
                        //功能列表
                        startDevicesListActivity();
                        break;
                }
            }
@@ -313,6 +320,7 @@
            @Override
            public void onError(HDLLinkException e) {
                tv.setText("网关不在线");
                responseTv.setText(e.getMsg());
            }
            @Override
            public void onSuccess(GatewaySearchBean gatewaySearchBean) {
@@ -464,4 +472,8 @@
    }
    void startDevicesListActivity(){
        Intent intent = new Intent(this, DevicesListActivity.class);
        startActivity(intent);
    }
}
HDLSDK/app/src/main/java/com/hdl/hdlsdk/device/DevicesListActivity.java
New file
@@ -0,0 +1,89 @@
package com.hdl.hdlsdk.device;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.OrientationHelper;
import androidx.recyclerview.widget.RecyclerView;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.util.Log;
import com.google.gson.reflect.TypeToken;
import com.hdl.hdlsdk.DemoAdapter;
import com.hdl.hdlsdk.R;
import com.hdl.sdk.common.exception.HDLLinkException;
import com.hdl.sdk.common.utils.LogUtils;
import com.hdl.sdk.common.utils.gson.GsonConvert;
import com.hdl.sdk.connect.HDLLink;
import com.hdl.sdk.connect.bean.LinkResponse;
import com.hdl.sdk.connect.bean.response.BaseLocalResponse;
import com.hdl.sdk.connect.bean.response.GatewaySearchBean;
import com.hdl.sdk.connect.callback.HDLLinkCallBack;
import java.util.ArrayList;
import java.util.List;
public class DevicesListActivity extends AppCompatActivity {
    private static final String TAG = "DevicesListActivity";
    private List<FunctionBean> devicesList = new ArrayList<>();
    private DevicesListAdapter mDevicesListAdapter;
    private RecyclerView mRecyclerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_devices_list);
        initView();
        initData();
    }
    @SuppressLint("WrongConstant")
    private void initView() {
        mRecyclerView = findViewById(R.id.device_list_rv);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mDevicesListAdapter = new DevicesListAdapter(this, devicesList);
        mRecyclerView.setAdapter(mDevicesListAdapter);
    }
    private void initData() {
        getFunctionList();
    }
    /**
     * 获取功能列表
     */
    void getFunctionList(){
        HDLLink.getInstance().getFunctionList(new HDLLinkCallBack() {
            @Override
            public void onError(HDLLinkException error) {
                Log.e(TAG,error.getMsg());
            }
            @Override
            public void onSuccess(String data) {
                Log.i(TAG, "获取设备列表成功");
                handelFunList(data);
            }
        });
    }
    void handelFunList(String data){
      try {
          final LinkResponse linkResponse = GsonConvert.getGson().fromJson(data, new TypeToken<LinkResponse>() {
          }.getType());
          final BaseLocalResponse<List<FunctionBean>> bean = GsonConvert.getGson().fromJson(linkResponse.getData(), new TypeToken<BaseLocalResponse<List<FunctionBean>>>() {
          }.getType());
          devicesList.clear();
          devicesList.addAll(bean.getObjects());
          mDevicesListAdapter.notifyDataSetChanged();
      }catch (Exception e){
          Log.e(TAG, "handelFunList: " + e.getMessage());
      }
    }
}
HDLSDK/app/src/main/java/com/hdl/hdlsdk/device/DevicesListAdapter.java
New file
@@ -0,0 +1,69 @@
package com.hdl.hdlsdk.device;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.adapter.base.BaseMultiItemQuickAdapter;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.hdl.hdlsdk.DemoBean;
import com.hdl.hdlsdk.R;
import java.util.List;
public class DevicesListAdapter extends RecyclerView.Adapter<DevicesListAdapter.ViewHolder> {
    private LayoutInflater mInflater;
    private List<FunctionBean> mList = null;
    public DevicesListAdapter(Context context, List<FunctionBean> devicesList) {
        this.mInflater = LayoutInflater.from(context);
        this.mList = devicesList;
    }
    /**
     * item显示类型
     *
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.item_devices_list, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }
    /**
     * 数据的绑定显示
     *
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.item_tv.setText(mList.get(position).getName());
    }
    @Override
    public int getItemCount() {
        return mList.size();
    }
    //自定义的ViewHolder,持有每个Item的的所有界面元素
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView item_tv;
        public ViewHolder(View view) {
            super(view);
            item_tv = (TextView) view.findViewById(R.id.device_title_tv);
        }
    }
}
HDLSDK/app/src/main/java/com/hdl/hdlsdk/device/FunctionBean.java
New file
@@ -0,0 +1,106 @@
package com.hdl.hdlsdk.device;
import com.chad.library.adapter.base.entity.MultiItemEntity;
import java.io.Serializable;
import java.util.List;
/**
 * Created by jlchen on 12/7/21.
 */
public class FunctionBean implements Serializable {
    private String sid;
    private String oid;
    private String name;
    private String spk;
    private String omodel;
    private String src;
    private String online;
    private List<FunctionStatus> status;
    public String getSid() {
        return sid;
    }
    public void setSid(String sid) {
        this.sid = sid;
    }
    public String getOid() {
        return oid;
    }
    public void setOid(String oid) {
        this.oid = oid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSpk() {
        return spk;
    }
    public void setSpk(String spk) {
        this.spk = spk;
    }
    public String getOmodel() {
        return omodel;
    }
    public void setOmodel(String omodel) {
        this.omodel = omodel;
    }
    public String getSrc() {
        return src;
    }
    public void setSrc(String src) {
        this.src = src;
    }
    public String getOnline() {
        return online;
    }
    public void setOnline(String online) {
        this.online = online;
    }
    public List<FunctionStatus> getStatus() {
        return status;
    }
    public void setStatus(List<FunctionStatus> status) {
        this.status = status;
    }
    public class FunctionStatus implements Serializable {
        private String key;
        private String value;
        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
    }
}
HDLSDK/app/src/main/res/layout/activity_devices_list.xml
New file
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".device.DevicesListActivity">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/device_list_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
HDLSDK/app/src/main/res/layout/item_devices_list.xml
New file
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/device_title_tv"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="@dimen/dp_10"
            android:gravity="center|left"
            android:text="设备"
            android:textColor="@color/black"
            android:layout_weight="1"/>
        <Switch
            android:id="@+id/device_on_off_switch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="@dimen/dp_10"
            />
    </LinearLayout>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        android:background="#f5f5f5"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</LinearLayout>
HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/exception/HDLLinkCode.java
@@ -14,6 +14,7 @@
    HDL_TIMEOUT_ERROR(-2004,"超时"),
    HDL_UNAUTHORIZED_ERROR(-2005,"未认证,请先认证"),
    HDL_AUTH_ERROR_GATEWAY_NOT_REGISTERED(-2006,"认证失败,网关未注册到云端"),
    HDL_SEARCH_GATEWAY_TIMEOUT_ERROR(-2007,"搜索网关失败,超时"),
    HDL_GET_DEVICE_LIST_ERROR(-2100,"获取设备列表失败"),
    HDL_GET_FUNCTION_LIST_ERROR(-2101,"获取功能列表失败"),
    HDL_GET_FUNCTION_PROPERTIES_ERROR(-2102,"获取功能属性失败"),
HDLSDK/hdl-connect/build.gradle
@@ -9,7 +9,7 @@
        minSdkVersion rootProject.minSdkVersion
        targetSdkVersion rootProject.targetSdkVersion
        versionCode 1
        versionName "1.0"
        versionName "1.0.1"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java
@@ -1,5 +1,6 @@
package com.hdl.sdk.connect.socket;
import android.net.ipsec.ike.TunnelModeChildSessionParams;
import android.text.TextUtils;
import com.google.gson.Gson;
@@ -10,6 +11,7 @@
import com.hdl.sdk.common.exception.HDLLinkCode;
import com.hdl.sdk.common.exception.HDLLinkException;
import com.hdl.sdk.common.utils.LogUtils;
import com.hdl.sdk.common.utils.ThreadToolUtils;
import com.hdl.sdk.connect.bean.response.AuthenticateResponse;
import com.hdl.sdk.connect.bean.response.NetworkAccessBroadcastResponse;
import com.hdl.sdk.connect.callback.BaseCallBack;
@@ -36,6 +38,9 @@
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static com.hdl.sdk.common.config.TopicConstant.DEIVCE_AUTH_REQUEST;
@@ -52,6 +57,8 @@
    private static final int UDP_PORT = 8585;
    private static SocketBoot updBoot;
//    private EventListener authEvent;
    //搜索网关
    private EventListener searchGatewayEvent;
    /**
     * udp默认组播ip
     */
@@ -61,6 +68,10 @@
     * instance
     */
    private volatile static HDLAuthSocket instance;
    private HDLAuthSocket() {
        initSearchGatewayEvent();
    }
//    public interface CallBack extends BaseCallBack {
//        void onSuccess(String msg);
@@ -256,6 +267,7 @@
    /**
     * 组播搜索指定网关是否在线,搜索到则返回指定的网关对象
     *
     * @param callBack  回调
     */
    public void searchGatewayMulticast(SearchGatewayCallBack callBack) {
@@ -264,6 +276,7 @@
    /**
     * 组播搜索指定网关是否在线,搜索到则返回指定的网关对象
     *
     * @param callBack  回调
     */
    public void searchGatewayBroadcast(SearchGatewayCallBack callBack) {
@@ -271,42 +284,6 @@
        searchGateway(HDLLinkConfig.getInstance().getGatewayId(), ip, callBack);
    }
    /**
     * 搜索指定网关是否在线,搜索到则返回指定的网关对象
     *
     * @param gatewayId 网关id
     * @param ip 接收目标的ip地址
     * @param callBack  回调
     */
    public void searchGateway(String gatewayId, String ip, SearchGatewayCallBack callBack) {
        String time = String.valueOf(System.currentTimeMillis());
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("id", IdUtils.getUUId());
        jsonObject.addProperty("time_stamp", time);
        LinkRequest message = new LinkRequest(TopicConstant.GATEWAY_SEARCH,
                jsonObject.toString());
        HdlSocketHelper.send(getUdpBoot(ip), message, new HdlSocketHelper.HdlSocketListener() {
            @Override
            public void onSucceed(Object msg) {
                GatewaySearchBean searchBean = getGatewaySearchBean(msg);
                if (searchBean != null && searchBean.getGatewayId().contains(gatewayId)) {
                    LogUtils.i(TAG, "onSuccess: ");
                    HDLLinkConfig.getInstance().setCurrentGateway(searchBean);
                    HDLLinkConfig.getInstance().setLocalEncrypt(searchBean.isLocalEncrypt());
                    callBack.onSuccess(searchBean);
                }else {
                }
            }
            @Override
            public void onFailure() {
                LogUtils.i(TAG, "onFailure: ");
                callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_TIMEOUT_ERROR));
            }
        });
    }
@@ -343,6 +320,7 @@
    /**
     * 通用发送指令
     * 1秒没响应就让他重新发送,重试3次
     *
     * @param topic 发送数据
     * @param bodyStr 回复的主题
     * @param callBack 回调
@@ -418,4 +396,121 @@
        return mBean;
    }
    /**
     * 网关搜索相关
     */
    private static final int MAX_SEARCH_COUNT  = 10;//总共搜索测试
    private final AtomicInteger searchGatewayCount = new AtomicInteger(0);;
    private final AtomicBoolean isSearchGatewaySuccess = new AtomicBoolean(true);
    private String searchGatewayId = "";
    private SearchGatewayCallBack mSearchGatewayCallBack;
    private void initSearchGatewayEvent(){
        LogUtils.i("搜索网关--","initSearchGatewayEvent");
        searchGatewayEvent = new EventListener() {
            @Override
            public void onMessage(Object msg) {
                try {
                    if (msg instanceof LinkResponse) {
                        LinkResponse linkResponse = (LinkResponse) msg;
                        String data = linkResponse.getData();
                        if (!TextUtils.isEmpty(data)) {
                            final BaseLocalResponse<GatewaySearchBean> response = GsonConvert.getGson().fromJson(data, new TypeToken<BaseLocalResponse<GatewaySearchBean>>() {
                            }.getType());
                            GatewaySearchBean searchBean = response.getObjects();
                            if (searchBean != null && !TextUtils.isEmpty(searchBean.getGatewayId())) {
                                if (searchBean.getGatewayId().contains(searchGatewayId)) {
                                    removeSearchGatewayEvent();//移除搜索网关监听
                                    isSearchGatewaySuccess.set(true);//搜索成功标记
                                    searchGatewayCount.set(11);//次数标记
                                    if(mSearchGatewayCallBack != null){
                                        mSearchGatewayCallBack.onSuccess(searchBean);
                                    }
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                }
            }
        };
    }
    /**
     * 搜索指定网关是否在线,搜索到则返回指定的网关对象
     *
     * @param gatewayId 网关id
     * @param ip        接收目标的ip地址
     * @param callBack  回调
     */
    public void searchGateway(String gatewayId, String ip, SearchGatewayCallBack callBack) {
        this.searchGatewayId = gatewayId;
        this.mSearchGatewayCallBack = callBack;
        //重置参数
        searchGatewayCount.set(0);
        isSearchGatewaySuccess.set(false);
        String time = String.valueOf(System.currentTimeMillis());
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("id", IdUtils.getUUId());
        jsonObject.addProperty("time_stamp", time);
        LinkRequest message = new LinkRequest(TopicConstant.GATEWAY_SEARCH,
                jsonObject.toString());
        //注册搜索网关监听
        registerSearchGatewayEvent();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (searchGatewayCount.get() < 10 && (!isSearchGatewaySuccess.get()) ) {
                    try {
                        //搜索网关
                        searchGatewayCount.set(searchGatewayCount.get() + 1);
                        LogUtils.i("搜索网关--","搜索网关第"+searchGatewayCount.get()+"次");
                        getUdpBoot(ip).sendMsg(message.getSendBytes());
                        Thread.sleep(1000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(!isSearchGatewaySuccess.get()){
                    //搜索10次,指定网关都没回复,回调超时
                    callBackSearchGatewayTimeout();
                    LogUtils.e("搜索网关--","搜索10次,指定网关都没回复,回调超时");
                }
            }
        }).start();
    }
    /**
     * 注册搜索网关监听
     */
    private void registerSearchGatewayEvent(){
        LogUtils.i("搜索网关--","注册搜索网关监听");
        EventDispatcher.getInstance().registerIo(TopicConstant.GATEWAY_SEARCH_REPLY, searchGatewayEvent);
    }
    /**
     * 移除搜索网关监听
     */
    private void removeSearchGatewayEvent(){
        LogUtils.i("搜索网关--","移除搜索网关监听");
        EventDispatcher.getInstance().remove(TopicConstant.GATEWAY_SEARCH_REPLY, searchGatewayEvent);
    }
    /**
     * 回调搜索网关超时
     */
    private void callBackSearchGatewayTimeout(){
        removeSearchGatewayEvent();
        ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if(mSearchGatewayCallBack != null){
                    mSearchGatewayCallBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_SEARCH_GATEWAY_TIMEOUT_ERROR));
                }
            }
        });
    }
}
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java
@@ -11,6 +11,7 @@
import com.hdl.sdk.common.exception.HDLLinkException;
import com.hdl.sdk.common.utils.IdUtils;
import com.hdl.sdk.common.utils.IpUtils;
import com.hdl.sdk.common.utils.LogUtils;
import com.hdl.sdk.common.utils.SPUtils;
import com.hdl.sdk.common.utils.ThreadToolUtils;
import com.hdl.sdk.common.utils.gson.GsonConvert;
@@ -696,12 +697,14 @@
                @Override
                public void onMessage(Object msg) {
                    if (msg instanceof LinkResponse) {
                        LogUtils.e("sendMsg onSuccess");
                        if (callBack != null) {
                            callBack.onSuccess(msg.toString());
                        }
                        threadPool.shutdownNow();
                    }
                    LogUtils.e("sendMsg eventListener remove");
                    EventDispatcher.getInstance().remove(eventTag, this);
                }
            };
@@ -713,6 +716,7 @@
                        getTcp().sendMsg(data);
                    } else {
                        threadPool.shutdownNow();
                        LogUtils.e("sendMsg eventListener remove");
                        EventDispatcher.getInstance().remove(eventTag, eventListener);
                        ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
                            @Override
HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HdlSocketHelper.java
@@ -129,5 +129,7 @@
        if (listener != null) {
            listener.onFailure();
        }
        EventDispatcher.getInstance().remove(eventListener);
    }
}