环信UI开源Demo情景分析三、启动界面

在分析启动界面SplashActivity前,先来看看清单文件中对这个界面的设置:

<!-- 开屏页 -->
        <activity
            android:name=".activity.SplashActivity"
            android:screenOrientation="portrait"
            android:theme="@style/horizontal_slide" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
其中有一点需要注意:android:theme="@style/horizontal_slide",咱们点进去看看。

11以前是这个

    <style name="horizontal_slide" parent="android:Theme.NoTitleBar">
        <item name="android:windowAnimationStyle">@style/AnimFade2</item>
    </style>

11以后

<style name="horizontal_slide" parent="android:style/Theme.Holo.Light.NoActionBar">
        <item name="android:windowAnimationStyle">@style/AnimFade2</item>
    </style>
只要是说明没有标题栏。
AnimFade2:

<style name="AnimFade2" parent="@android:style/Animation.Activity">
        <item name="android:activityOpenEnterAnimation">@anim/slide_in_from_right</item>
        <item name="android:activityOpenExitAnimation">@anim/slide_out_to_left</item>
        <item name="android:activityCloseExitAnimation">@anim/slide_out_to_right</item>
        <item name="android:activityCloseEnterAnimation">@anim/slide_in_from_left</item>
    </style>
可以清晰发现所设置的动画,都是Activity的切换动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="100%p"
        android:toXDelta="0" />

</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />

</set>
配置了解完了,咱们接下来看界面。

xml文件就不详细说明了,因为这个界面继承自BaseActivity所以先来看看BaseActivity里面有什么东西。

public class BaseActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
    }
    @Override
    protected void onResume() {
        super.onResume();
        // onresume时,取消notification显示
        HXSDKHelper.getInstance().getNotifier().reset();
        
        // umeng
        MobclickAgent.onResume(this);
    }
    @Override
    protected void onStart() {
        super.onStart();
        // umeng
        MobclickAgent.onPause(this);
    }
    /**
     * 返回
     * 
     * @param view
     */
    public void back(View view) {
        finish();
    }
}
很简单,因为是聊天软件,所以设置当界面可见时取消notification显示,以及umeng的一些设置,最后写了一个返回的公共方法。

接下来看主要代码:

public class SplashActivity extends BaseActivity {
	private LinearLayout rootLayout;
	private TextView versionText;
	// 停留时间
	private static final int sleepTime = 2000;

	@Override
	protected void onCreate(Bundle arg0) {
		setContentView(R.layout.activity_splash);
		super.onCreate(arg0);
		rootLayout = (LinearLayout) findViewById(R.id.splash_root);
		// 显示版本信息的文字
		versionText = (TextView) findViewById(R.id.tv_version);
		versionText.setText(getVersion());
		// 设置渐变动画
		AlphaAnimation animation = new AlphaAnimation(0.3f, 1.0f);
		animation.setDuration(1500);
		rootLayout.startAnimation(animation);
	}

	@Override
	protected void onStart() {
		super.onStart();
		// 判断是否有登录 已经登录直接进入主界面 否则进入登录界面
		new Thread(new Runnable() {
			public void run() {
				if (DemoHXSDKHelper.getInstance().isLogined()) {
					// ** 免登陆情况 加载所有本地群和会话
					// 不是必须的,不加sdk也会自动异步去加载(不会重复加载);
					// 加上的话保证进了主页面会话和群组都已经load完毕
					long start = System.currentTimeMillis();
					EMGroupManager.getInstance().loadAllGroups();
					EMChatManager.getInstance().loadAllConversations();
					long costTime = System.currentTimeMillis() - start;
					// 等待sleeptime时长
					if (sleepTime - costTime > 0) {
						try {
							Thread.sleep(sleepTime - costTime);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					// 进入主页面
					startActivity(new Intent(SplashActivity.this, MainActivity.class));
					finish();
				} else {
					try {
						Thread.sleep(sleepTime);
					} catch (InterruptedException e) {
					}
					// 进入登录界面
					startActivity(new Intent(SplashActivity.this, LoginActivity.class));
					finish();
				}
			}
		}).start();
	}

	/**
	 * 获取当前应用程序的版本号
	 */
	private String getVersion() {
		String st = getResources().getString(R.string.Version_number_is_wrong);
		PackageManager pm = getPackageManager();
		try {
			PackageInfo packinfo = pm.getPackageInfo(getPackageName(), 0);
			String version = packinfo.versionName;
			return version;
		} catch (NameNotFoundException e) {
			e.printStackTrace();
			return st;
		}
	}
}
其中设置了一个1500毫秒的渐变动画,并且根据应用版本修改界面上的TextView。
在onStart方法里面开启一条线程用来检测账号是否已经登录,如果已经登录的话直接进入主界面,否则的话进入等登录界面。并且确保停留时间不能比设定的时间(sleepTime = 2000)小。

在这里使用了一个类:DemoHXSDKHelper,进去看下到底是怎么来检测账号是否登录的。

继承自抽象类HXSDKHelper,可以看到这个类:

/**
 * The developer can derive from this class to talk with HuanXin SDK
 * All the Huan Xin related initialization and global listener are implemented in this class which will 
 * help developer to speed up the SDK integration。
 * this is a global instance class which can be obtained in any codes through getInstance()
 * 
 * 开发人员可以选择继承这个环信SDK帮助类去加快初始化集成速度。此类会初始化环信SDK,并设置初始化参数和初始化相应的监听器
 * 不过继承类需要根据要求求提供相应的函数,尤其是提供一个{@link HXSDKModel}. 所以请实现abstract protected HXSDKModel createModel();
 * 全局仅有一个此类的实例存在,所以可以在任意地方通过getInstance()函数获取此全局实例
 * 
 * @author easemob
 *
 */
既然是初始化,那肯定是在一个全局的APP类里面了,到清单文件里面看一下是DemoApplication类,

public static DemoHXSDKHelper hxSDKHelper = new DemoHXSDKHelper();
@Override
    public void onCreate() {
        super.onCreate();
        // 获取一个全局的Context
        applicationContext = this;
        // 获取一个全局的APP实例
        instance = this;

        /**
         * this function will initialize the HuanXin SDK
         * 
         * @return boolean true if caller can continue to call HuanXin related
         *         APIs after calling onInit, otherwise false.
         * 
         *         环信初始化SDK帮助函数
         *         返回true如果正确初始化,否则false,如果返回为false,请在后续的调用中不要调用任何和环信相关的代码
         * 
         *         for example: 例子:
         * 
         *         public class DemoHXSDKHelper extends HXSDKHelper
         * 
         *         HXHelper = new DemoHXSDKHelper();
         *         if(HXHelper.onInit(context)){ // do HuanXin related work }
         */
        hxSDKHelper.onInit(applicationContext);
    }
接下来看下初始化里面的内容:onInit

    
    /**
     * application context
     */
    protected Context appContext = null;
    /**
     * init flag: test if the sdk has been inited before, we don't need to init again
     */
    private boolean sdkInited = false;

    /**
     * this function will initialize the HuanXin SDK
     * 
     * @return boolean true if caller can continue to call HuanXin related APIs after calling onInit, otherwise false.
     * 
     * 环信初始化SDK帮助函数
     * 返回true如果正确初始化,否则false,如果返回为false,请在后续的调用中不要调用任何和环信相关的代码
     * 
     * for example:
     * 例子:
     * 
     * public class DemoHXSDKHelper extends HXSDKHelper
     * 
     * HXHelper = new DemoHXSDKHelper();
     * if(HXHelper.onInit(context)){
     *     // do HuanXin related work
     * }
     */
    public synchronized boolean onInit(Context context){
        if(sdkInited){
            return true;
        }

        appContext = context;
        
        // create HX SDK model
        hxModel = createModel();
        
        // create a default HX SDK model in case subclass did not provide the model
        if(hxModel == null){
            hxModel = new DefaultHXSDKModel(appContext);
        }
        
        int pid = android.os.Process.myPid();
        String processAppName = getAppName(pid);
        
        Log.d(TAG, "process app name : " + processAppName);
        
        // 如果app启用了远程的service,此application:onCreate会被调用2次
        // 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
        // 默认的app会在以包名为默认的process name下运行,如果查到的process name不是app的process name就立即返回
        if (processAppName == null || !processAppName.equalsIgnoreCase(hxModel.getAppProcessName())) {
            Log.e(TAG, "enter the service process!");
            
            // 则此application::onCreate 是被service 调用的,直接返回
            return false;
        }

        // 初始化环信SDK,一定要先调用init()
        EMChat.getInstance().init(context);
        
        // 设置sandbox测试环境
        // 建议开发者开发时设置此模式
        if(hxModel.isSandboxMode()){
            EMChat.getInstance().setEnv(EMEnvMode.EMSandboxMode);
        }
        
        if(hxModel.isDebugMode()){
            // set debug mode in development process
            EMChat.getInstance().setDebugMode(true);    
        }

        Log.d(TAG, "initialize EMChat SDK");
                
        initHXOptions();
        initListener();
        sdkInited = true;
        return true;
    }
初始化之后可以通过SDK来判断是否已经在服务端登录:

    /**
     * 检查是否已经登录过
     * @return
     */
    public boolean isLogined(){
       return EMChat.getInstance().isLoggedIn();
    }
这里只显示部分代码,由于初始化的内容比较多,且都是SDK方面的东西,此处不再详讲。

到此启动界面就已经讲完了,接下来会按照没有登录的逻辑进入登录界面。




### RT-DETRv3 网络结构分析 RT-DETRv3 是一种基于 Transformer 的实时端到端目标检测算法,其核心在于通过引入分层密集正监督方法以及一系列创新性的训练策略,解决了传统 DETR 模型收敛慢和解码器训练不足的问题。以下是 RT-DETRv3 的主要网络结构特点: #### 1. **基于 CNN 的辅助分支** 为了增强编码器的特征表示能力,RT-DETRv3 引入了一个基于卷积神经网络 (CNN) 的辅助分支[^3]。这一分支提供了密集的监督信号,能够与原始解码器协同工作,从而提升整体性能。 ```python class AuxiliaryBranch(nn.Module): def __init__(self, in_channels, out_channels): super(AuxiliaryBranch, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn = nn.BatchNorm2d(out_channels) def forward(self, x): return F.relu(self.bn(self.conv(x))) ``` 此部分的设计灵感来源于传统的 CNN 架构,例如 YOLO 系列中的 CSPNet 和 PAN 结构[^2],这些技术被用来优化特征提取效率并减少计算开销。 --- #### 2. **自注意力扰动学习策略** 为解决解码器训练不足的问题,RT-DETRv3 提出了一种名为 *self-att 扰动* 的新学习策略。这种策略通过对多个查询组中阳性样本的标签分配进行多样化处理,有效增加了阳例的数量,进而提高了模型的学习能力和泛化性能。 具体实现方式是在训练过程中动态调整注意力权重分布,确保更多的高质量查询可以与真实标注 (Ground Truth) 进行匹配。 --- #### 3. **共享权重解编码器分支** 除了上述改进外,RT-DETRv3 还引入了一个共享权重的解编码器分支,专门用于提供密集的正向监督信号。这一设计不仅简化了模型架构,还显著降低了参数量和推理时间,使其更适合实时应用需求。 ```python class SharedDecoderEncoder(nn.Module): def __init__(self, d_model, nhead, num_layers): super(SharedDecoderEncoder, self).__init__() decoder_layer = nn.TransformerDecoderLayer(d_model=d_model, nhead=nhead) self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_layers) def forward(self, tgt, memory): return self.decoder(tgt=tgt, memory=memory) ``` 通过这种方式,RT-DETRv3 实现了高效的目标检测流程,在保持高精度的同时大幅缩短了推理延迟。 --- #### 4. **与其他模型的关系** 值得一提的是,RT-DETRv3 并未完全抛弃经典的 CNN 技术,而是将其与 Transformer 结合起来形成混合架构[^4]。例如,它采用了 YOLO 系列中的 RepNCSP 模块替代冗余的多尺度自注意力层,从而减少了不必要的计算负担。 此外,RT-DETRv3 还借鉴了 DETR 的一对一匹配策略,并在此基础上进行了优化,进一步提升了小目标检测的能力。 --- ### 总结 综上所述,RT-DETRv3 的网络结构主要包括以下几个关键组件:基于 CNN 的辅助分支、自注意力扰动学习策略、共享权重解编码器分支以及混合编码器设计。这些技术创新共同推动了实时目标检测领域的发展,使其在复杂场景下的表现更加出色。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值