添加了清除缓存,存在BUG
This commit is contained in:
@@ -2,8 +2,10 @@ package com.qxcm.moduleutil.activity;
|
||||
|
||||
import static com.liulishuo.okdownload.OkDownloadProvider.context;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
@@ -22,16 +24,21 @@ import androidx.databinding.DataBindingUtil;
|
||||
import androidx.databinding.ViewDataBinding;
|
||||
|
||||
import com.alibaba.android.arouter.launcher.ARouter;
|
||||
import com.blankj.utilcode.util.ActivityUtils;
|
||||
import com.blankj.utilcode.util.BarUtils;
|
||||
import com.petterp.floatingx.FloatingX;
|
||||
import com.petterp.floatingx.assist.helper.FxAppHelper;
|
||||
import com.qxcm.moduleutil.R;
|
||||
import com.qxcm.moduleutil.base.CommonAppContext;
|
||||
import com.qxcm.moduleutil.event.MqttBean;
|
||||
import com.qxcm.moduleutil.utils.ARouteConstants;
|
||||
import com.qxcm.moduleutil.utils.BackgroundManager;
|
||||
import com.qxcm.moduleutil.utils.ColorManager;
|
||||
import com.qxcm.moduleutil.utils.DisplayUtil;
|
||||
import com.qxcm.moduleutil.utils.LanguageUtil;
|
||||
import com.qxcm.moduleutil.utils.SpUtil;
|
||||
import com.qxcm.moduleutil.widget.PiaoPingManager;
|
||||
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
@@ -54,7 +61,26 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
|
||||
|
||||
|
||||
// private LoadingDialog mLoadingDialog;
|
||||
// 添加广播接收器成员变量
|
||||
private BroadcastReceiver mLogoutReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if ("com.qxcm.moduleutil.ACTION_USER_LOGOUT".equals(intent.getAction())) {
|
||||
// 在这里处理用户登出后的UI更新
|
||||
// 例如:隐藏需要登录才能显示的控件
|
||||
// 或者跳转到登录状态的页面
|
||||
handleUserLogout();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 处理用户登出的方法
|
||||
protected void handleUserLogout() {
|
||||
// 子类可以重写此方法处理具体的登出逻辑
|
||||
// 例如:更新UI状态、清除本地数据等
|
||||
|
||||
ActivityUtils.finishAllActivities();
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -82,6 +108,9 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
|
||||
// 应用当前颜色
|
||||
applyCurrentColors();
|
||||
|
||||
// 注册登出广播接收器
|
||||
IntentFilter filter = new IntentFilter("com.qxcm.moduleutil.ACTION_USER_LOGOUT");
|
||||
registerReceiver(mLogoutReceiver, filter);
|
||||
|
||||
// 动态判断是否包含 @Subscribe 注解的方法
|
||||
boolean hasSubscribeMethods = false;
|
||||
@@ -232,6 +261,13 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
|
||||
if (EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
try {
|
||||
unregisterReceiver(mLogoutReceiver);
|
||||
} catch (Exception e) {
|
||||
// 忽略异常
|
||||
}
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@@ -304,4 +340,10 @@ public abstract class BaseAppCompatActivity<VDB extends ViewDataBinding> extends
|
||||
// FxAppHelper fxAppHelper = FxAppHelper.builder().setContext(this).setLayout(R.layout.item_piaoping).build();
|
||||
// FloatingX.install(fxAppHelper).show();
|
||||
// }
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEvent(ChatInfo event) {
|
||||
String id= event.getId().replace("g", "");
|
||||
ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getH5Url()+"/web/index.html#/pages/union/setGroup?id="+ SpUtil.getToken()+"&guildId="+id).navigation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,21 +108,21 @@ public abstract class BaseMvpActivity<P extends IPresenter, VDB extends ViewData
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
LogUtils.e("@@@","成功");
|
||||
V2TIMUserFullInfo userFullInfo = new V2TIMUserFullInfo();
|
||||
userFullInfo.setNickname(userBean.getNickname());
|
||||
userFullInfo.setFaceUrl(userBean.getAvatar());
|
||||
userFullInfo.setAllowType(userBean.getSex());
|
||||
V2TIMManager.getInstance().setSelfInfo(userFullInfo, new V2TIMCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
LogUtils.e("@@@", "成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String desc) {
|
||||
LogUtils.e("@@@", "描述"+desc);
|
||||
}
|
||||
});
|
||||
// V2TIMUserFullInfo userFullInfo = new V2TIMUserFullInfo();
|
||||
// userFullInfo.setNickname(userBean.getNickname());
|
||||
// userFullInfo.setFaceUrl(userBean.getAvatar());
|
||||
// userFullInfo.setAllowType(userBean.getSex());
|
||||
// V2TIMManager.getInstance().setSelfInfo(userFullInfo, new V2TIMCallback() {
|
||||
// @Override
|
||||
// public void onSuccess() {
|
||||
// LogUtils.e("@@@", "成功");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onError(int code, String desc) {
|
||||
// LogUtils.e("@@@", "描述"+desc);
|
||||
// }
|
||||
// });
|
||||
initLocation();
|
||||
}
|
||||
});
|
||||
@@ -176,21 +176,21 @@ public abstract class BaseMvpActivity<P extends IPresenter, VDB extends ViewData
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void userInfoEvent(UserInfo event) {
|
||||
V2TIMUserFullInfo userFullInfo = new V2TIMUserFullInfo();
|
||||
userFullInfo.setNickname(event.getNickname());
|
||||
userFullInfo.setFaceUrl(event.getAvatar());
|
||||
userFullInfo.setAllowType(event.getSex());
|
||||
V2TIMManager.getInstance().setSelfInfo(userFullInfo, new V2TIMCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
LogUtils.e("@@@", "成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int code, String desc) {
|
||||
LogUtils.e("@@@", "描述"+desc);
|
||||
}
|
||||
});
|
||||
// V2TIMUserFullInfo userFullInfo = new V2TIMUserFullInfo();
|
||||
// userFullInfo.setNickname(event.getNickname());
|
||||
// userFullInfo.setFaceUrl(event.getAvatar());
|
||||
// userFullInfo.setAllowType(event.getSex());
|
||||
// V2TIMManager.getInstance().setSelfInfo(userFullInfo, new V2TIMCallback() {
|
||||
// @Override
|
||||
// public void onSuccess() {
|
||||
// LogUtils.e("@@@", "成功");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onError(int code, String desc) {
|
||||
// LogUtils.e("@@@", "描述"+desc);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
/**
|
||||
* 显示全局飘屏消息(支持任意位置飘过)
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -68,6 +69,8 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
@Override
|
||||
protected void initData() {
|
||||
WebSettings webSettings = mBinding.webView.getSettings();
|
||||
|
||||
// 禁用水平滚动
|
||||
webSettings.setUseWideViewPort(true);
|
||||
webSettings.setLoadWithOverviewMode(true);
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
@@ -75,14 +78,40 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
//增加JSBridge
|
||||
mBinding.webView.addJavascriptInterface(new WebAppInterface(this), "Android");
|
||||
// mBinding.webView.addJavascriptInterface(new WebViewBridgeConfig(title), WebViewBridgeConfig.NAME);
|
||||
webSettings.setBuiltInZoomControls(false);
|
||||
webSettings.setSupportZoom(false);
|
||||
|
||||
if (title!=null && !title.isEmpty()){
|
||||
if (title.contains("协议")) {
|
||||
webSettings.setDisplayZoomControls(false); // 隐藏默认缩放控件
|
||||
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); // 使用正常布局算法
|
||||
webSettings.setBuiltInZoomControls(false);
|
||||
webSettings.setSupportZoom(false);
|
||||
|
||||
// 重要:设置布局算法为适应屏幕
|
||||
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
|
||||
// 设置初始缩放
|
||||
mBinding.webView.setInitialScale(100);
|
||||
mBinding.webView.getSettings().setUseWideViewPort(false);
|
||||
}else {
|
||||
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
|
||||
}
|
||||
}else {
|
||||
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
|
||||
}
|
||||
|
||||
webSettings.setBuiltInZoomControls(true);
|
||||
webSettings.setSupportZoom(true);
|
||||
webSettings.setDomStorageEnabled(true);
|
||||
webSettings.setBlockNetworkImage(false);//解决图片不显示
|
||||
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
|
||||
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
|
||||
// webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
|
||||
|
||||
mBinding.webView.setHorizontalScrollBarEnabled(false);//水平不显示
|
||||
mBinding.webView.setVerticalScrollBarEnabled(false); //垂直不显示
|
||||
mBinding.webView.setScrollbarFadingEnabled(false);
|
||||
mBinding.webView.setScrollContainer(true);
|
||||
|
||||
|
||||
|
||||
mBinding.webView.setWebViewClient(new WebViewClient());
|
||||
mBinding.webView.setBackgroundColor(Color.TRANSPARENT);
|
||||
mBinding.webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
@@ -98,6 +127,7 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
mBinding.webView.setWebChromeClient(new WebChromeClient() {
|
||||
|
||||
//配置权限(同样在WebChromeClient中实现)
|
||||
@@ -109,7 +139,32 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int newProgress) {
|
||||
if (title != null && !title.isEmpty()) {
|
||||
if (title.contains("协议")) {
|
||||
|
||||
if (newProgress >= 100) {
|
||||
// 页面加载完成后调整文本换行
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// 注入CSS确保文字自动换行
|
||||
mBinding.webView.loadUrl("javascript:(function() {" +
|
||||
"var sheets = document.styleSheets;" +
|
||||
"for (var i = 0; i < sheets.length; i++) {" +
|
||||
" try {" +
|
||||
" sheets[i].addRule('*', 'word-wrap: break-word !important; white-space: normal !important; overflow-x: hidden !important;', 0);" +
|
||||
" } catch(e) {" +
|
||||
" try {" +
|
||||
" sheets[i].insertRule('* { word-wrap: break-word !important; white-space: normal !important; overflow-x: hidden !important; }', 0);" +
|
||||
" } catch(e2) {}" +
|
||||
" }" +
|
||||
"}" +
|
||||
"})()");
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For Android < 3.0
|
||||
@@ -142,6 +197,8 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void showFileChooser() {
|
||||
@@ -190,7 +247,7 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
getWindow().getDecorView().setBackgroundResource(com.qxcm.moduleutil.R.color.white);
|
||||
title = getIntent().getStringExtra("title");
|
||||
url = getIntent().getStringExtra("url");
|
||||
if (title!=null) {
|
||||
if (title != null) {
|
||||
if (title.equals("举报") || title.equals("等级") || title.equals("公会") || title.equals("邀请") || title.equals("反馈")) {
|
||||
mBinding.topBar.setVisibility(GONE);
|
||||
// mBinding.webView.setPadding(0,20,0,0);
|
||||
@@ -198,20 +255,19 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
mBinding.topBar.setVisibility(VISIBLE);
|
||||
mBinding.topBar.setTitle(title);
|
||||
}
|
||||
}else {
|
||||
if (url.equals(CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=6")){
|
||||
} else {
|
||||
if (url.equals("file:///android_asset/page_yongh.html")) {
|
||||
mBinding.topBar.setVisibility(VISIBLE);
|
||||
mBinding.topBar.setTitle("用户协议");
|
||||
}else if (url.equals(CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=4")){
|
||||
} else if (url.equals("file:///android_asset/page_show.html")) {
|
||||
mBinding.topBar.setVisibility(VISIBLE);
|
||||
mBinding.topBar.setTitle("隐私协议");
|
||||
}else {
|
||||
} else {
|
||||
mBinding.topBar.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,6 +282,24 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
mContext = c;
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void adjustTextWrap() {
|
||||
// 通过 JavaScript 注入 CSS 样式确保文字自动换行
|
||||
final String javascript = "javascript:(function() {" +
|
||||
"var style = document.createElement('style');" +
|
||||
"style.type = 'text/css';" +
|
||||
"style.innerHTML = '* { word-wrap: break-word; white-space: normal !important; overflow-x: hidden !important; } body { max-width: 100% !important; }';" +
|
||||
"document.getElementsByTagName('head')[0].appendChild(style);" +
|
||||
"})()";
|
||||
|
||||
((Activity) mContext).runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mBinding.webView.loadUrl(javascript);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 被 H5 调用的方法
|
||||
@JavascriptInterface
|
||||
public void showToast(String toast) {
|
||||
@@ -254,6 +328,7 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
public void jumpRoomPage(String room_id) {
|
||||
ARouter.getInstance().build(ARouteConstants.ROOM_DETAILS).withString("form", "首页").withString("roomId", room_id).navigation();
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void jumpWebPage(String objects) {
|
||||
// ARouter.getInstance().build(ARouteConstants.USER_HOME_PAGE).navigation();
|
||||
@@ -261,7 +336,7 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void enterGroupChat(String group_id,String cover,String guild_name) {
|
||||
public void enterGroupChat(String group_id, String cover, String guild_name) {
|
||||
Intent intent = new Intent(mContext, TUIGroupChatActivity.class);
|
||||
intent.putExtra(TUIConstants.TUIChat.CHAT_ID, group_id);
|
||||
intent.putExtra(TUIConstants.TUIChat.CHAT_TYPE, V2TIMConversation.V2TIM_GROUP);
|
||||
@@ -269,14 +344,15 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void chatWithUser(String user_id,String nickname) {
|
||||
public void chatWithUser(String user_id, String nickname) {
|
||||
Intent intent = new Intent(mContext, TUIC2CChatActivity.class);
|
||||
intent.putExtra(TUIConstants.TUIChat.CHAT_ID, user_id);
|
||||
intent.putExtra(TUIConstants.TUIChat.CHAT_TYPE, V2TIMConversation.V2TIM_C2C);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void exchange(){
|
||||
public void exchange() {
|
||||
ARouter.getInstance().build(ARouteConstants.CURRENCY).navigation();
|
||||
|
||||
}
|
||||
@@ -292,7 +368,7 @@ public class WebViewActivity extends BaseAppCompatActivity<ActivityWebViewBindin
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void Recharge(){
|
||||
public void Recharge() {
|
||||
ARouter.getInstance().build(ARouteConstants.RECHARGE_ACTIVITY).navigation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@ public class GiftPackAdapter extends BaseAdapter {
|
||||
viewHolder.item_layout = (ConstraintLayout) convertView.findViewById(R.id.cl_gift);
|
||||
viewHolder.ivDownOn = (ImageView) convertView.findViewById(R.id.iv_down_on);
|
||||
viewHolder.cl_iv_down_on = (ConstraintLayout) convertView.findViewById(R.id.cl_iv_down_on);
|
||||
viewHolder.integral = (TextView) convertView.findViewById(R.id.integral);
|
||||
|
||||
convertView.setTag(viewHolder);
|
||||
} else {
|
||||
@@ -131,10 +132,11 @@ public class GiftPackAdapter extends BaseAdapter {
|
||||
|
||||
viewHolder.item_layout.setOnClickListener(v -> {
|
||||
// RoonGiftModel clickedModel = (RoonGiftModel) v.getTag();
|
||||
EventBus.getDefault().post(new RoomGiftPackToEvent(this, giftModel, 1));
|
||||
EventBus.getDefault().post(new RoomGiftPackToEvent(this, giftModel, 2));
|
||||
|
||||
});
|
||||
|
||||
viewHolder.integral.setVisibility(View.VISIBLE);
|
||||
viewHolder.integral.setText("x"+giftModel.getNum());
|
||||
//设置礼物名字
|
||||
viewHolder.tv_gift_name.setText(giftModel.getGift_name());
|
||||
//设置礼物价格
|
||||
@@ -164,7 +166,7 @@ public class GiftPackAdapter extends BaseAdapter {
|
||||
|
||||
static class ViewHolder {
|
||||
public ConstraintLayout item_layout;
|
||||
public TextView tv_gift_name, tv_gift_price, tv_gift_num;
|
||||
public TextView tv_gift_name, tv_gift_price, integral;
|
||||
public ImageView iv_gift_pic;
|
||||
public TextView tv_gift_change_love_values;
|
||||
public ImageView ivDownOn;
|
||||
|
||||
@@ -40,21 +40,26 @@ import com.blankj.utilcode.util.FileUtils;
|
||||
import com.blankj.utilcode.util.LogUtils;
|
||||
import com.blankj.utilcode.util.ProcessUtils;
|
||||
import com.blankj.utilcode.util.ServiceUtils;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.lahm.library.EasyProtectorLib;
|
||||
import com.lahm.library.EmulatorCheckCallback;
|
||||
import com.qxcm.moduleutil.R;
|
||||
import com.qxcm.moduleutil.bean.UserBean;
|
||||
import com.qxcm.moduleutil.event.AppLifecycleEvent;
|
||||
import com.qxcm.moduleutil.event.RoomGiftRunable;
|
||||
import com.qxcm.moduleutil.interfaces.AppLifecycleUtil;
|
||||
import com.qxcm.moduleutil.listener.MessageListenerSingleton;
|
||||
import com.qxcm.moduleutil.rtc.AgoraManager;
|
||||
import com.qxcm.moduleutil.service.MyMqttService;
|
||||
import com.qxcm.moduleutil.utils.ARouteConstants;
|
||||
import com.qxcm.moduleutil.utils.FloatWindowHelper;
|
||||
import com.qxcm.moduleutil.utils.ImageUtils;
|
||||
import com.qxcm.moduleutil.utils.MemoryOptimizationUtils;
|
||||
import com.qxcm.moduleutil.utils.SpUtil;
|
||||
import com.qxcm.moduleutil.utils.UtilConfig;
|
||||
import com.qxcm.moduleutil.utils.config.EnvironmentEnum;
|
||||
import com.qxcm.moduleutil.utils.config.EnvironmentPrefs;
|
||||
import com.qxcm.moduleutil.utils.location.SystemLocationProvider;
|
||||
import com.qxcm.moduleutil.widget.CommonAppConfig;
|
||||
import com.qxcm.moduleutil.widget.CustomRefreshHeader;
|
||||
import com.qxcm.moduleutil.widget.PiaoPingManager;
|
||||
@@ -69,6 +74,7 @@ import com.scwang.smartrefresh.layout.header.ClassicsHeader;
|
||||
import com.tencent.bugly.crashreport.CrashReport;
|
||||
import com.tencent.qcloud.tuicore.TUILogin;
|
||||
import com.tencent.qcloud.tuicore.interfaces.TUICallback;
|
||||
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
@@ -116,26 +122,92 @@ public class CommonAppContext extends MultiDexApplication {
|
||||
EnvironmentPrefs prefs = new EnvironmentPrefs(this);
|
||||
currentEnvironment = prefs.getSelectedEnvironment();
|
||||
initialization();
|
||||
piaoPingManager = PiaoPingManager.getInstance(this);
|
||||
// 在独立进程中运行 LeakCanary 分析
|
||||
|
||||
// leakcanary.LeakCanary.setConfig(new leakcanary.LeakCanary.Config());
|
||||
// 禁用自动堆分析
|
||||
}
|
||||
|
||||
public void initialization(){
|
||||
UtilConfig.init(this);
|
||||
registerActivityLifecycleCallbacks();
|
||||
initWebView();
|
||||
private void handleMemoryTrim(int level) {
|
||||
LogUtils.w("MemoryTrim", "Memory trim level: " + level);
|
||||
|
||||
switch (level) {
|
||||
case TRIM_MEMORY_RUNNING_MODERATE:
|
||||
LogUtils.w("MemoryTrim", "Memory trim: moderate");
|
||||
break;
|
||||
case TRIM_MEMORY_RUNNING_LOW:
|
||||
LogUtils.w("MemoryTrim", "Memory trim: low");
|
||||
clearCaches();
|
||||
break;
|
||||
case TRIM_MEMORY_RUNNING_CRITICAL:
|
||||
LogUtils.w("MemoryTrim", "Memory trim: critical");
|
||||
clearCaches();
|
||||
MemoryOptimizationUtils.forceGC();
|
||||
break;
|
||||
case TRIM_MEMORY_UI_HIDDEN:
|
||||
LogUtils.w("MemoryTrim", "Memory trim: UI hidden");
|
||||
clearCaches();
|
||||
break;
|
||||
case TRIM_MEMORY_BACKGROUND:
|
||||
LogUtils.w("MemoryTrim", "Memory trim: background");
|
||||
clearCaches();
|
||||
break;
|
||||
case TRIM_MEMORY_MODERATE:
|
||||
LogUtils.w("MemoryTrim", "Memory trim: moderate background");
|
||||
clearCaches();
|
||||
break;
|
||||
case TRIM_MEMORY_COMPLETE:
|
||||
LogUtils.w("MemoryTrim", "Memory trim: complete");
|
||||
clearCaches();
|
||||
MemoryOptimizationUtils.forceGC();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearCaches() {
|
||||
try {
|
||||
// 清理图片缓存
|
||||
MemoryOptimizationUtils.clearImageCache(this);
|
||||
|
||||
// 清理 Glide 内存缓存
|
||||
Glide.get(this).clearMemory();
|
||||
|
||||
// 清理SVGA缓存
|
||||
MemoryOptimizationUtils.clearSVGACache();
|
||||
|
||||
// 清理其他缓存
|
||||
if (piaoPingManager != null) {
|
||||
piaoPingManager.unsubscribe();
|
||||
}
|
||||
|
||||
// 清理消息缓存
|
||||
RoomGiftRunable.clearMqttCache();
|
||||
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("ClearCaches", "Error clearing caches: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void initialization() {
|
||||
|
||||
if (ProcessUtils.isMainProcess()) {
|
||||
initARouter();
|
||||
if (SpUtil.isAgreePolicy()) {
|
||||
UtilConfig.init(this);
|
||||
registerActivityLifecycleCallbacks();
|
||||
initWebView();
|
||||
checkInEmulator();
|
||||
UtilConfig.checkInEmulator();
|
||||
AgoraManager.getInstance(this).init(currentEnvironment.getSwSdkAppId());
|
||||
MessageListenerSingleton.getInstance();
|
||||
CrashReport.initCrashReport(this, "865cfe9555", true);/*bugly初始化*/
|
||||
ServiceUtils.startService(MyMqttService.class);/*Mqtt初始化*/
|
||||
// 每次启动应用时重置状态
|
||||
SpUtil.getInstance().setBooleanValue("youth_model_shown", false);
|
||||
}
|
||||
}
|
||||
|
||||
piaoPingManager = PiaoPingManager.getInstance(this);
|
||||
piaoPingManager.subscribe();
|
||||
AgoraManager.getInstance(this).init(currentEnvironment.getSwSdkAppId());
|
||||
MessageListenerSingleton.getInstance();
|
||||
CrashReport.initCrashReport(this, "865cfe9555", true);/*bugly初始化*/
|
||||
ServiceUtils.startService(MyMqttService.class);/*Mqtt初始化*/
|
||||
}
|
||||
|
||||
private PiaoPingManager piaoPingManager;
|
||||
@@ -234,7 +306,14 @@ public class CommonAppContext extends MultiDexApplication {
|
||||
CommonAppConfig.getInstance().setFrontGround(true);
|
||||
// FloatWindowHelper.setFloatWindowVisible(true);
|
||||
AppLifecycleUtil.onAppFrontGround();
|
||||
|
||||
// 确保在主线程中订阅
|
||||
if (activity != null && !activity.isFinishing()) {
|
||||
activity.runOnUiThread(() -> {
|
||||
if (piaoPingManager != null) {
|
||||
piaoPingManager.subscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,6 +337,14 @@ public class CommonAppContext extends MultiDexApplication {
|
||||
CommonAppConfig.getInstance().setFrontGround(false);
|
||||
// FloatWindowHelper.setFloatWindowVisible(false);
|
||||
AppLifecycleUtil.onAppBackGround();
|
||||
// 确保在主线程中取消订阅
|
||||
if (activity != null && !activity.isFinishing()) {
|
||||
activity.runOnUiThread(() -> {
|
||||
if (piaoPingManager != null) {
|
||||
piaoPingManager.unsubscribe();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +357,7 @@ public class CommonAppContext extends MultiDexApplication {
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -369,6 +457,8 @@ public class CommonAppContext extends MultiDexApplication {
|
||||
// SpUtil.getInstance().removeValue(
|
||||
// SPConstants.USER_ID, SPConstants.TOKEN, SPConstants.USER_INFO
|
||||
// );
|
||||
isShow = false;
|
||||
isPlaying = false;
|
||||
mUserBean = null;
|
||||
SpUtil.saveUserId(-1);
|
||||
SpUtil.saveUserBean(new UserBean());
|
||||
@@ -376,11 +466,16 @@ public class CommonAppContext extends MultiDexApplication {
|
||||
Intent intent = new Intent("com.example.action.LAUNCH_PAGE");
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
getApplicationContext().startActivity(intent);
|
||||
piaoPingManager.unsubscribe();
|
||||
// piaoPingManager.unsubscribe();
|
||||
FileUtils.deleteAllInDir(getCacheDir());
|
||||
FileUtils.deleteAllInDir(getExternalCacheDir());
|
||||
AgoraManager.getInstance(getApplicationContext()).destroy();
|
||||
// 每次启动应用时重置状态
|
||||
SpUtil.setBooleanValue("youth_model_shown", false);
|
||||
|
||||
// 发送广播通知所有Activity刷新状态
|
||||
Intent refreshIntent = new Intent("com.qxcm.moduleutil.ACTION_USER_LOGOUT");
|
||||
sendBroadcast(refreshIntent);
|
||||
}
|
||||
|
||||
public static boolean isAlipayInstalled(Context context) {
|
||||
@@ -417,4 +512,5 @@ public class CommonAppContext extends MultiDexApplication {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class UserInfo implements Serializable {
|
||||
private String dress;//头像框
|
||||
private String charm;//魅力值
|
||||
private String room_id;
|
||||
private String guile;//公会名称
|
||||
private String guild;//公会名称
|
||||
private String is_mute;//禁言状态 0否 1是
|
||||
private String is_mute_pit;//禁麦状态 0否 1是
|
||||
private String is_manager;//是否是管理员 0否 1是
|
||||
|
||||
@@ -42,7 +42,9 @@ public class PolicyDialog extends Dialog {
|
||||
ClickableSpan clickSpan = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=6" ).withString("title", "用户协议").navigation();
|
||||
// ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=6" ).withString("title", "用户协议").navigation();
|
||||
ARouter.getInstance().build(ARouteConstants.H5).withString("url", "file:///android_asset/page_yongh.html").withString("title", "用户协议").navigation();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,7 +56,9 @@ public class PolicyDialog extends Dialog {
|
||||
ClickableSpan ysClickSpan = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=4").withString("title", "隐私协议").navigation();
|
||||
// ARouter.getInstance().build(ARouteConstants.H5).withString("url", CommonAppContext.getInstance().getCurrentEnvironment().getServerUrl()+"/api/Page/page_show?id=4").withString("title", "隐私协议").navigation();
|
||||
ARouter.getInstance().build(ARouteConstants.H5).withString("url", "file:///android_asset/page_show.html").withString("title", "隐私协议").navigation();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
package com.qxcm.moduleutil.event;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.provider.Settings;
|
||||
|
||||
import com.blankj.utilcode.util.GsonUtils;
|
||||
import com.blankj.utilcode.util.ServiceUtils;
|
||||
import com.google.gson.Gson;
|
||||
import com.qxcm.moduleutil.base.CommonAppContext;
|
||||
import com.qxcm.moduleutil.service.FloatingWindow;
|
||||
import com.qxcm.moduleutil.widget.PiaoPingManager;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
@@ -27,6 +19,39 @@ public class RoomGiftRunable implements Runnable {
|
||||
private static final List<MqttBean> mqttCache = new ArrayList<>();
|
||||
private static final int MAX_CACHE_SIZE = 6;
|
||||
private static final Object lock = new Object();
|
||||
|
||||
public static synchronized void addMqttCache(MqttBean mqttBean) {
|
||||
if (mqttBean == null) return;
|
||||
|
||||
// 检查内存状态
|
||||
if (isMemoryLow()) {
|
||||
// 内存不足时清理缓存
|
||||
clearMqttCache();
|
||||
return;
|
||||
}
|
||||
|
||||
// 限制缓存大小
|
||||
if (mqttCache.size() >= MAX_CACHE_SIZE) {
|
||||
mqttCache.remove(0); // 移除最旧的项
|
||||
}
|
||||
|
||||
mqttCache.add(mqttBean);
|
||||
}
|
||||
|
||||
public static synchronized void clearMqttCache() {
|
||||
mqttCache.clear();
|
||||
// 建议进行垃圾回收
|
||||
// System.gc();
|
||||
}
|
||||
|
||||
private static boolean isMemoryLow() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
long usedMemory = runtime.totalMemory() - runtime.freeMemory();
|
||||
long maxMemory = runtime.maxMemory();
|
||||
double memoryUsage = (double) usedMemory / maxMemory;
|
||||
|
||||
return memoryUsage > 0.8; // 内存使用超过80%认为是低内存
|
||||
}
|
||||
public RoomGiftRunable(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
@@ -36,10 +61,26 @@ public class RoomGiftRunable implements Runnable {
|
||||
MqttBean mqttBean= GsonUtils.fromJson(data, MqttBean.class);
|
||||
// 线程安全地添加到缓存
|
||||
synchronized (lock) {
|
||||
if (mqttCache.size() >= MAX_CACHE_SIZE) {
|
||||
mqttCache.remove(0); // 移除第一条数据
|
||||
|
||||
if (mqttBean == null) return;
|
||||
|
||||
// 检查内存状态
|
||||
if (isMemoryLow()) {
|
||||
// 内存不足时清理缓存
|
||||
clearMqttCache();
|
||||
return;
|
||||
}
|
||||
mqttCache.add(mqttBean); // 添加新数据
|
||||
|
||||
// 限制缓存大小
|
||||
if (mqttCache.size() >= MAX_CACHE_SIZE) {
|
||||
mqttCache.remove(0); // 移除最旧的项
|
||||
}
|
||||
|
||||
mqttCache.add(mqttBean);
|
||||
// if (mqttCache.size() >= MAX_CACHE_SIZE) {
|
||||
// mqttCache.remove(0); // 移除第一条数据
|
||||
// }
|
||||
// mqttCache.add(mqttBean); // 添加新数据
|
||||
}
|
||||
EventBus.getDefault().post(mqttBean);
|
||||
// new FloatingWindow(CommonAppContext.getInstance(),mqttBean);
|
||||
|
||||
@@ -84,6 +84,14 @@ public interface ApiServer {
|
||||
@POST(Constants.SEND_CODE)
|
||||
Observable<BaseModel<Object>> sendCode(@Field("mobile") String mobile, @Field("event") String event);
|
||||
|
||||
|
||||
@FormUrlEncoded //手机换绑
|
||||
@POST(Constants.MODIFY_MOBILE)
|
||||
Call<BaseModel<String>> mobileView(@Field("mobile") String mobile, @Field("new_mobile") String new_mobile,@Field("sms_code") String sms_code);
|
||||
@FormUrlEncoded //手机绑定
|
||||
@POST(Constants.BIND_MOBILE)
|
||||
Call<BaseModel<String>> mobileView2( @Field("new_mobile") String new_mobile,@Field("sms_code") String sms_code);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(Constants.LOGIN)
|
||||
Observable<BaseModel<List<UserBean>>> login(@Field("user_login") String user_login, @Field("sms_code") String sms_code);
|
||||
@@ -254,7 +262,7 @@ public interface ApiServer {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(Constants.GET_EXPAND_COLUMN)
|
||||
Observable<BaseModel<List<ExpandColumnBean>>> getExpandColumn(@Field("type") String type);
|
||||
Observable<BaseModel<List<ExpandColumnBean>>> getExpandColumn(@Field("type") String type,@Field("page") String page, @Field("page_limit") String page_limit);
|
||||
|
||||
@GET(Constants.GET_OFFICIAL_NOTICE)
|
||||
Observable<BaseModel<NewsDataBean>> getOfficialNotice();
|
||||
@@ -644,7 +652,7 @@ public interface ApiServer {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(Constants.POST_CHARM_LIST)
|
||||
Observable<BaseModel<RoomDetails>> getCharmList(@Field("room_id") String room_id, @Field("start_time") String start_time, @Field("end_time") String end_time);
|
||||
Observable<BaseModel<RoomDetails>> getCharmList(@Field("room_id") String room_id, @Field("start_time") String start_time, @Field("end_time") String end_time,@Field("page") String page);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(Constants.POST_SET_UPLOAD_BG_IMG)
|
||||
|
||||
@@ -144,7 +144,7 @@ public class RetrofitClient {
|
||||
private OkHttpClient provideOkHttpClient() {
|
||||
Map<String, String> headers = Collections.emptyMap();
|
||||
if (SpUtil.isAgreePolicy()) {
|
||||
headers = SystemUtils.getSystemParams();
|
||||
headers = SystemUtils.getSystemParams();
|
||||
}
|
||||
SetCookieCache cookieCache = new SetCookieCache();
|
||||
ClearableCookieJar cookieJar =
|
||||
@@ -248,6 +248,41 @@ public class RetrofitClient {
|
||||
sApiServer.sendCode(mobile, event).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
}
|
||||
|
||||
public void mobileView(String mobile, String new_mobile, String sms_code, BaseObserver<String> observer) {
|
||||
sApiServer.mobileView(mobile, new_mobile, sms_code).enqueue(new Callback<BaseModel<String>>() {
|
||||
@Override
|
||||
public void onResponse(Call<BaseModel<String>> call, Response<BaseModel<String>> response) {
|
||||
if (response.code() == 200) {
|
||||
BaseModel<String> body = response.body();
|
||||
observer.onNext(body.getMsg());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<BaseModel<String>> call, Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void mobileView2(String new_mobile, String sms_code, BaseObserver<String> observer) {
|
||||
sApiServer.mobileView2(new_mobile, sms_code).enqueue(new Callback<BaseModel<String>>() {
|
||||
@Override
|
||||
public void onResponse(Call<BaseModel<String>> call, Response<BaseModel<String>> response) {
|
||||
if (response.code() == 200) {
|
||||
BaseModel<String> body = response.body();
|
||||
observer.onNext(body.getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<BaseModel<String>> call, Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void login(String mobile, String password, BaseObserver<List<UserBean>> observer) {
|
||||
sApiServer.login(mobile, password).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
}
|
||||
@@ -453,24 +488,24 @@ public class RetrofitClient {
|
||||
sApiServer.dailyTasksOpenBox(gift_box_id).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
}
|
||||
|
||||
public void dailyTasksReceive(String task_id,BaseObserver<String> observer){
|
||||
public void dailyTasksReceive(String task_id, BaseObserver<String> observer) {
|
||||
sApiServer.dailyTasksReceive(task_id).enqueue(new Callback<ResponseBody>() {
|
||||
|
||||
@Override
|
||||
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
|
||||
if (response.code() == 200){
|
||||
if (response.code() == 200) {
|
||||
observer.onNext("任务完成");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||
t.printStackTrace();
|
||||
t.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void dailyTasksComplete(String task_id,BaseObserver<RoomSingleton> observer) {
|
||||
public void dailyTasksComplete(String task_id, BaseObserver<RoomSingleton> observer) {
|
||||
sApiServer.dailyTasksComplete(task_id).enqueue(new Callback<ResponseBody>() {
|
||||
@Override
|
||||
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
|
||||
@@ -494,6 +529,7 @@ public class RetrofitClient {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void sendHeadine(String content, String money, String roomId, BaseObserver<String> observer) {
|
||||
sApiServer.sendHeadine(content, money, roomId).enqueue(new Callback<BaseModel<String>>() {
|
||||
@Override
|
||||
@@ -543,7 +579,7 @@ public class RetrofitClient {
|
||||
if (baseModel != null) {
|
||||
if (baseModel.getData() != null && baseModel.getData().size() > 0) {
|
||||
observer.onNext(baseModel.getData());
|
||||
}else {
|
||||
} else {
|
||||
observer.onNext(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
@@ -718,16 +754,16 @@ public class RetrofitClient {
|
||||
});
|
||||
}
|
||||
|
||||
public void getThemeData(BaseObserver<ThemeBean> observer){
|
||||
public void getThemeData(BaseObserver<ThemeBean> observer) {
|
||||
sApiServer.getThemeData().enqueue(new Callback<BaseModel<ThemeBean>>() {
|
||||
|
||||
@Override
|
||||
public void onResponse(Call<BaseModel<ThemeBean>> call, Response<BaseModel<ThemeBean>> response) {
|
||||
if (response.code() == 200){
|
||||
if (response.code() == 200) {
|
||||
BaseModel<ThemeBean> baseModel = response.body();
|
||||
if (baseModel.getData()!=null){
|
||||
if (baseModel.getData() != null) {
|
||||
observer.onNext(baseModel.getData());
|
||||
}else {
|
||||
} else {
|
||||
observer.onNext(null);
|
||||
}
|
||||
}
|
||||
@@ -760,7 +796,7 @@ public class RetrofitClient {
|
||||
sApiServer.getBlacklist(page, page_limit).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
}
|
||||
|
||||
public void getLockMiniList(String page, String page_limit, BaseObserver<List<BlackUserBean>> observer){
|
||||
public void getLockMiniList(String page, String page_limit, BaseObserver<List<BlackUserBean>> observer) {
|
||||
sApiServer.getLockMiniList(page, page_limit).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
}
|
||||
|
||||
@@ -770,7 +806,7 @@ public class RetrofitClient {
|
||||
|
||||
//获取扩列数据
|
||||
public void getExpandColumn(String type, String page, String page_limit, BaseObserver<List<ExpandColumnBean>> observer) {
|
||||
sApiServer.getExpandColumn(type).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
sApiServer.getExpandColumn(type,page, page_limit).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
}
|
||||
|
||||
//获取官方公告数据或者系统消息,
|
||||
@@ -1074,7 +1110,7 @@ public class RetrofitClient {
|
||||
}
|
||||
|
||||
public void getCharmList(String roomId, String stime, String etime, String p, BaseObserver<RoomDetails> observer) {
|
||||
sApiServer.getCharmList(roomId, stime, etime).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
sApiServer.getCharmList(roomId, stime, etime, p).compose(new DefaultTransformer<>()).subscribe(observer);
|
||||
}
|
||||
|
||||
// TODO: 2025/6/28 房间竞拍开始
|
||||
@@ -1644,9 +1680,9 @@ public class RetrofitClient {
|
||||
sApiServer.cancelUserDecorate(type).enqueue(new Callback<BaseModel<String>>() {
|
||||
@Override
|
||||
public void onResponse(Call<BaseModel<String>> call, Response<BaseModel<String>> response) {
|
||||
if (response.code() == 200){
|
||||
if (response.code() == 200) {
|
||||
observer.onNext("取消成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1913,12 +1949,12 @@ public class RetrofitClient {
|
||||
});
|
||||
}
|
||||
|
||||
public void postRoomSwToken(String roomId, BaseObserver<PkSwTokenBean> observer){
|
||||
public void postRoomSwToken(String roomId, BaseObserver<PkSwTokenBean> observer) {
|
||||
sApiServer.postRoomSwToken(roomId).enqueue(new Callback<BaseModel<PkSwTokenBean>>() {
|
||||
|
||||
@Override
|
||||
public void onResponse(Call<BaseModel<PkSwTokenBean>> call, Response<BaseModel<PkSwTokenBean>> response) {
|
||||
if (response.code() == 200){
|
||||
if (response.code() == 200) {
|
||||
BaseModel<PkSwTokenBean> baseModel = response.body();
|
||||
observer.onNext(baseModel.getData());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.qxcm.moduleutil.listener;
|
||||
|
||||
import static com.liulishuo.okdownload.OkDownloadProvider.context;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.blankj.utilcode.util.GsonUtils;
|
||||
@@ -27,6 +31,8 @@ import org.greenrobot.eventbus.EventBus;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
*@author qx
|
||||
|
||||
@@ -103,8 +103,8 @@ public class AgoraManager {
|
||||
private static List<Music> musicList;
|
||||
private static boolean isBjMusic = false;
|
||||
private static List<SoundLevelUpdateListener> soundLevelUpdateListeners = new CopyOnWriteArrayList<>();
|
||||
private static ChannelMediaOptions options;
|
||||
private static RtcConnection connection;
|
||||
private static ChannelMediaOptions options;
|
||||
private static RtcConnection connection;
|
||||
private String pkRoomId = "";
|
||||
|
||||
private AgoraManager() {
|
||||
@@ -148,7 +148,8 @@ public class AgoraManager {
|
||||
* 初始化 Agora 引擎
|
||||
*/
|
||||
public static void init(String appId) {
|
||||
if (rtcEngine != null) throw new IllegalStateException("RtcEngine已经初始化过");;
|
||||
if (rtcEngine != null) throw new IllegalStateException("RtcEngine已经初始化过");
|
||||
;
|
||||
|
||||
try {
|
||||
RtcEngineConfig config = new RtcEngineConfig();
|
||||
@@ -212,7 +213,7 @@ public class AgoraManager {
|
||||
public void joinRoom(String token, String roomId, int uid, boolean isMicrophoneEnabled, boolean isCamerJs) {
|
||||
if (rtcEngine == null) {
|
||||
Log.e("AgoraManager", "RtcEngine not initialized");
|
||||
return;
|
||||
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
|
||||
}
|
||||
if (!mRoomId.isEmpty()) {
|
||||
leaveRoom();
|
||||
@@ -256,6 +257,9 @@ public class AgoraManager {
|
||||
}
|
||||
|
||||
public void joinChannelEx(String token, String channelId, int uid) {
|
||||
if (rtcEngine == null) {
|
||||
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
|
||||
}
|
||||
if (rtcEngine != null) {
|
||||
options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
|
||||
options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
|
||||
@@ -346,21 +350,69 @@ public class AgoraManager {
|
||||
* 销毁引擎
|
||||
*/
|
||||
public void destroy() {
|
||||
// if (rtcEngine != null) {
|
||||
//// rtcEngine.registerEventHandler(getDefaultEventHandler());
|
||||
// rtcEngine.leaveChannel();
|
||||
// rtcEngine.stopScreenCapture();
|
||||
// rtcEngine.stopPreview();
|
||||
// if (musicPlayer != null) {
|
||||
// musicPlayer.destroy();
|
||||
// }
|
||||
// if (musicContentCenter != null) {
|
||||
// musicContentCenter.destroy();
|
||||
// }
|
||||
//// rtcEngine.destroy();
|
||||
//// rtcEngine = null;
|
||||
// }
|
||||
// eventHandlers.clear();
|
||||
|
||||
|
||||
if (rtcEngine != null) {
|
||||
// rtcEngine.registerEventHandler(getDefaultEventHandler());
|
||||
rtcEngine.leaveChannel();
|
||||
// 停止屏幕捕获
|
||||
rtcEngine.stopScreenCapture();
|
||||
|
||||
// 停止预览
|
||||
rtcEngine.stopPreview();
|
||||
|
||||
// 离开频道
|
||||
rtcEngine.leaveChannel();
|
||||
|
||||
// 销毁音乐播放器
|
||||
if (musicPlayer != null) {
|
||||
musicPlayer.stop();
|
||||
musicPlayer.destroy();
|
||||
musicPlayer = null;
|
||||
}
|
||||
|
||||
// 销毁音乐内容中心
|
||||
if (musicContentCenter != null) {
|
||||
musicContentCenter.destroy();
|
||||
musicContentCenter = null;
|
||||
}
|
||||
// rtcEngine.destroy();
|
||||
|
||||
// 移除所有事件监听器
|
||||
for (IRtcEngineEventHandler handler : eventHandlers) {
|
||||
rtcEngine.removeHandler(handler);
|
||||
}
|
||||
eventHandlers.clear();
|
||||
|
||||
// // 销毁RtcEngine
|
||||
// RtcEngine.destroy();
|
||||
// rtcEngine = null;
|
||||
}
|
||||
eventHandlers.clear();
|
||||
|
||||
// 清理静态变量
|
||||
musicList = null;
|
||||
soundLevelUpdateListeners.clear();
|
||||
mRoomId = "";
|
||||
mSongCode = 0;
|
||||
options = null;
|
||||
connection = null;
|
||||
pkRoomId = "";
|
||||
isBjMusic = false;
|
||||
|
||||
// 清理实例
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public void desMusic() {
|
||||
@@ -374,6 +426,9 @@ public class AgoraManager {
|
||||
*/
|
||||
@SuppressLint("SuspiciousIndentation")
|
||||
public void setLocalAudioEnabled(boolean enabled, String userId) {
|
||||
if (rtcEngine == null) {
|
||||
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
|
||||
}
|
||||
if (rtcEngine != null) {
|
||||
rtcEngine.enableLocalAudio(enabled); // 启用/禁用音频采集
|
||||
this.isLocalAudioEnabled = enabled;
|
||||
@@ -425,6 +480,9 @@ public class AgoraManager {
|
||||
// RtcConnection connection = new RtcConnection();
|
||||
// connection.channelId = mRoomId;
|
||||
// connection.localUid = uid;
|
||||
if (rtcEngine == null) {
|
||||
init(CommonAppContext.getInstance().getCurrentEnvironment().getSwSdkAppId());
|
||||
}
|
||||
rtcEngine.muteLocalAudioStreamEx(enabled, connection);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.qxcm.moduleutil.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.blankj.utilcode.util.LogUtils;
|
||||
import com.bumptech.glide.Glide;
|
||||
|
||||
public class MemoryOptimizationUtils {
|
||||
private static final String TAG = "MemoryOptimization";
|
||||
|
||||
/**
|
||||
* 检查内存状态
|
||||
*/
|
||||
public static boolean isMemoryLow() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
long usedMemory = runtime.totalMemory() - runtime.freeMemory();
|
||||
long maxMemory = runtime.maxMemory();
|
||||
double memoryUsage = (double) usedMemory / maxMemory;
|
||||
|
||||
LogUtils.d(TAG, "Memory usage: " + (memoryUsage * 100) + "%");
|
||||
|
||||
// 内存使用超过85%认为是低内存
|
||||
return memoryUsage > 0.85;
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制进行垃圾回收
|
||||
*/
|
||||
public static void forceGC() {
|
||||
try {
|
||||
LogUtils.d(TAG, "Forcing garbage collection");
|
||||
Runtime.getRuntime().gc();
|
||||
Thread.sleep(100); // 给GC一些时间
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理图片缓存
|
||||
*/
|
||||
public static void clearImageCache(Context context) {
|
||||
try {
|
||||
// 清理Glide缓存
|
||||
Glide.get(context).clearMemory();
|
||||
|
||||
// 在后台线程清理磁盘缓存
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Glide.get(context).clearDiskCache();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error clearing Glide disk cache: " + e.getMessage());
|
||||
}
|
||||
}).start();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error clearing image cache: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取当前内存使用情况
|
||||
*/
|
||||
public static String getMemoryInfo() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
long maxMemory = runtime.maxMemory();
|
||||
long totalMemory = runtime.totalMemory();
|
||||
long freeMemory = runtime.freeMemory();
|
||||
long usedMemory = totalMemory - freeMemory;
|
||||
|
||||
return String.format("Max: %d MB, Total: %d MB, Used: %d MB, Free: %d MB",
|
||||
maxMemory / (1024 * 1024),
|
||||
totalMemory / (1024 * 1024),
|
||||
usedMemory / (1024 * 1024),
|
||||
freeMemory / (1024 * 1024));
|
||||
}
|
||||
/**
|
||||
* 清理SVGA缓存
|
||||
*/
|
||||
public static void clearSVGACache() {
|
||||
try {
|
||||
// 如果SVGA库提供了清理缓存的方法,调用它
|
||||
// SVGAParser.clearCache(); // 假设有这样的方法
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error clearing SVGA cache: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.qxcm.moduleutil.utils.config;
|
||||
|
||||
public enum EnvironmentEnum {
|
||||
PRODUCTION(//生产环境
|
||||
"http://chat.qxmier.com/",
|
||||
"https://chat.qxmier.com/",
|
||||
"6rdWuz058oq5OahdbFiGEybUcdahd12J83L34Uc7MrPIrxtFG+rXiwDvRcqNvjwbClbbmvMrmxKVkIysFByBsl0Qe9kqd2w8T/nhK5G6eXXlk2V9AjYCieIU+jRnjZBB+Cfechr6rCGJ2aeBARIsXcRPW7wm9WFK9euh5T+v6Pyte68yNaNdcYCll3+U4/uCEog7HygCnMIbAU+kqoPdmn2H+51YOHW+VsnsHd4w1+I3f8Tt0xLIXGM4GWnQueZ5GR46GTWiSYMy8dCIh9SPIMRyC91GosVcfGPMJSdcXqc=",
|
||||
"https://oss-cn-hangzhou.aliyuncs.com/",
|
||||
"LTAI5tJ2UYfFNF7K3F4e1siv",
|
||||
@@ -15,7 +15,7 @@ public enum EnvironmentEnum {
|
||||
"tcp://81.70.45.221",
|
||||
"https://vespa.qxmier.com"),
|
||||
TEST(//测试环境
|
||||
"http://vschat.qxmier.com/",
|
||||
"https://vschat.qxmier.com/",
|
||||
"6rdWuz058oq5OahdbFiGEybUcdahd12J83L34Uc7MrPIrxtFG+rXiwDvRcqNvjwbClbbmvMrmxKVkIysFByBsl0Qe9kqd2w8T/nhK5G6eXXlk2V9AjYCieIU+jRnjZBB+Cfechr6rCGJ2aeBARIsXcRPW7wm9WFK9euh5T+v6Pyte68yNaNdcYCll3+U4/uCEog7HygCnMIbAU+kqoPdmn2H+51YOHW+VsnsHd4w1+I3f8Tt0xLIXGM4GWnQueZ5GR46GTWiSYMy8dCIh9SPIMRyC91GosVcfGPMJSdcXqc=",
|
||||
"https://oss-cn-hangzhou.aliyuncs.com/",
|
||||
"LTAI5tJ2UYfFNF7K3F4e1siv",
|
||||
|
||||
@@ -16,14 +16,100 @@ import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import com.blankj.utilcode.util.ToastUtils;
|
||||
import com.qxcm.moduleutil.base.CommonAppContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class SystemLocationProvider implements LocationProvider {
|
||||
|
||||
private LocationManager locationManager;
|
||||
private LocationListener gpsLocationListener;
|
||||
private LocationListener networkLocationListener;
|
||||
private Handler timeoutHandler;
|
||||
private Runnable timeoutRunnable;
|
||||
|
||||
// 使用静态内部类避免内存泄漏
|
||||
private static class LocationListenerImpl implements LocationListener {
|
||||
private final WeakReference<LocationCallback> callbackRef;
|
||||
private final WeakReference<Context> contextRef;
|
||||
private final boolean isGpsListener; // 标识是否是GPS监听器
|
||||
|
||||
LocationListenerImpl(LocationCallback callback, Context context, boolean isGpsListener) {
|
||||
this.callbackRef = new WeakReference<>(callback);
|
||||
this.contextRef = new WeakReference<>(context);
|
||||
this.isGpsListener = isGpsListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(@NonNull Location location) {
|
||||
LocationCallback callback = callbackRef.get();
|
||||
Context context = contextRef.get();
|
||||
if (callback != null && context != null) {
|
||||
String city = getCityName(context, location.getLatitude(), location.getLongitude());
|
||||
callback.onLocationReceived(location.getLatitude(), location.getLongitude(), city);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
// 可以添加日志或其他处理
|
||||
Log.d("LocationDebug", "onStatusChanged: " + provider + ", status: " + status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(@NonNull String provider) {
|
||||
Log.d("LocationDebug", "onProviderEnabled: " + provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(@NonNull String provider) {
|
||||
LocationCallback callback = callbackRef.get();
|
||||
Context context = contextRef.get();
|
||||
if (callback != null && context != null) {
|
||||
if (isGpsListener) {
|
||||
// GPS被禁用时回退到网络定位
|
||||
fallbackToNetwork(callback, context);
|
||||
} else {
|
||||
callback.onFailed("网络定位不可用");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getCityName(Context context, double latitude, double longitude) {
|
||||
android.location.Geocoder geocoder = new android.location.Geocoder(context, Locale.getDefault());
|
||||
try {
|
||||
List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
|
||||
if (addresses != null && !addresses.isEmpty()) {
|
||||
return addresses.get(0).getAdminArea() + "," + addresses.get(0).getLocality() + "," + addresses.get(0).getSubLocality();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "未知城市";
|
||||
}
|
||||
|
||||
private void fallbackToNetwork(LocationCallback callback, Context context) {
|
||||
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
if (locationManager != null && locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|
||||
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
callback.onFailed("缺少定位权限");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建网络定位监听器
|
||||
LocationListenerImpl networkListener = new LocationListenerImpl(callback, context, false);
|
||||
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, networkListener, Looper.getMainLooper());
|
||||
} else {
|
||||
callback.onFailed("GPS 不可用且网络定位也未启用");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getLastKnownLocation(@NonNull Context context, @NonNull LocationCallback callback) {
|
||||
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
if (locationManager == null) {
|
||||
@@ -40,153 +126,40 @@ public class SystemLocationProvider implements LocationProvider {
|
||||
Log.d("LocationDebug", "GPS Enabled: " + isGpsEnabled);
|
||||
Log.d("LocationDebug", "Network Enabled: " + isNetworkEnabled);
|
||||
|
||||
if (!isGpsEnabled && !isNetworkEnabled) {
|
||||
callback.onFailed("GPS 和 网络定位均未启用");
|
||||
return;
|
||||
}
|
||||
// 清理之前的监听器
|
||||
cleanupListeners();
|
||||
|
||||
final Handler handler = new Handler(Looper.getMainLooper());
|
||||
Runnable timeout = () -> callback.onFailed("定位请求超时");
|
||||
handler.postDelayed(timeout, 15000); // 15秒超时
|
||||
|
||||
LocationListener listener = new LocationListener() {
|
||||
@Override
|
||||
public void onLocationChanged(@NonNull Location location) {
|
||||
handler.removeCallbacks(timeout);
|
||||
String city = getCityName(context, location.getLatitude(), location.getLongitude());
|
||||
callback.onLocationReceived(location.getLatitude(), location.getLongitude(), city);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
Log.d("LocationDebug", "onStatusChanged: " + provider + ", status: " + status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(@NonNull String provider) {
|
||||
Log.d("LocationDebug", "onProviderEnabled: " + provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(@NonNull String provider) {
|
||||
Log.d("LocationDebug", "onProviderDisabled: " + provider);
|
||||
fallbackToNetwork(callback, context);
|
||||
}
|
||||
// 设置超时处理
|
||||
timeoutHandler = new Handler(Looper.getMainLooper());
|
||||
timeoutRunnable = () -> {
|
||||
cleanupListeners();
|
||||
callback.onFailed("定位请求超时");
|
||||
};
|
||||
if (isNetworkEnabled) {
|
||||
Log.d("LocationDebug", "尝试使用 NETWORK 定位");
|
||||
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, listener, Looper.getMainLooper());
|
||||
}
|
||||
else if (isGpsEnabled) {
|
||||
timeoutHandler.postDelayed(timeoutRunnable, 15000); // 15秒超时
|
||||
|
||||
if (isGpsEnabled) {
|
||||
Log.d("LocationDebug", "尝试使用 GPS 定位");
|
||||
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, listener, Looper.getMainLooper());
|
||||
gpsLocationListener = new LocationListenerImpl(callback, context, true);
|
||||
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, gpsLocationListener, Looper.getMainLooper());
|
||||
} else if (isNetworkEnabled) {
|
||||
Log.d("LocationDebug", "尝试使用 NETWORK 定位");
|
||||
networkLocationListener = new LocationListenerImpl(callback, context, false);
|
||||
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, networkLocationListener, Looper.getMainLooper());
|
||||
} else {
|
||||
// 清理超时处理
|
||||
if (timeoutHandler != null && timeoutRunnable != null) {
|
||||
timeoutHandler.removeCallbacks(timeoutRunnable);
|
||||
}
|
||||
callback.onFailed("GPS 和 网络定位均未启用");
|
||||
}
|
||||
|
||||
} catch (SecurityException e) {
|
||||
Log.e("LocationDebug", "缺少定位权限", e);
|
||||
callback.onFailed("缺少定位权限:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void getLastKnownLocation(@NonNull Context context, @NonNull LocationCallback callback) {
|
||||
// locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
// if (locationManager == null) {
|
||||
// callback.onFailed("无法获取定位服务");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// try {
|
||||
// if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
// locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, new LocationListener() {
|
||||
// @Override
|
||||
// public void onLocationChanged(@NonNull Location location) {
|
||||
// String city = getCityName(context, location.getLatitude(), location.getLongitude());
|
||||
// callback.onLocationReceived(location.getLatitude(), location.getLongitude(), city);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
// ToastUtils.showShort(provider);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onProviderEnabled(@NonNull String provider) {
|
||||
// ToastUtils.showShort(provider);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onProviderDisabled(@NonNull String provider) {
|
||||
// fallbackToNetwork(callback, context);
|
||||
// }
|
||||
// }, Looper.getMainLooper());
|
||||
// } else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
||||
// locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, new LocationListener() {
|
||||
// @Override
|
||||
// public void onLocationChanged(@NonNull Location location) {
|
||||
// String city = getCityName(context, location.getLatitude(), location.getLongitude());
|
||||
// callback.onLocationReceived(location.getLatitude(), location.getLongitude(), city);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
// ToastUtils.showShort(provider);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onProviderEnabled(@NonNull String provider) {
|
||||
// ToastUtils.showShort(provider);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onProviderDisabled(@NonNull String provider) {
|
||||
// callback.onFailed("网络定位不可用");
|
||||
// }
|
||||
// }, Looper.getMainLooper());
|
||||
// } else {
|
||||
// callback.onFailed("GPS 和 网络定位均未启用");
|
||||
// }
|
||||
// } catch (SecurityException e) {
|
||||
// callback.onFailed("缺少定位权限:" + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
|
||||
private void fallbackToNetwork(LocationCallback callback, Context context) {
|
||||
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
// TODO: Consider calling
|
||||
// ActivityCompat#requestPermissions
|
||||
// here to request the missing permissions, and then overriding
|
||||
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
|
||||
// int[] grantResults)
|
||||
// to handle the case where the user grants the permission. See the documentation
|
||||
// for ActivityCompat#requestPermissions for more details.
|
||||
return;
|
||||
// 清理超时处理
|
||||
if (timeoutHandler != null && timeoutRunnable != null) {
|
||||
timeoutHandler.removeCallbacks(timeoutRunnable);
|
||||
}
|
||||
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, new LocationListener() {
|
||||
@Override
|
||||
public void onLocationChanged(@NonNull Location location) {
|
||||
String city = getCityName(context, location.getLatitude(), location.getLongitude());
|
||||
callback.onLocationReceived(location.getLatitude(), location.getLongitude(), city);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
ToastUtils.showShort(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(@NonNull String provider) {
|
||||
ToastUtils.showShort(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(@NonNull String provider) {
|
||||
callback.onFailed("网络定位不可用");
|
||||
}
|
||||
}, Looper.getMainLooper());
|
||||
} else {
|
||||
callback.onFailed("GPS 不可用且网络定位也未启用");
|
||||
callback.onFailed("缺少定位权限:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,15 +170,47 @@ public class SystemLocationProvider implements LocationProvider {
|
||||
|
||||
@Override
|
||||
public void stopLocationUpdates() {
|
||||
// 可扩展为停止监听
|
||||
cleanupListeners();
|
||||
}
|
||||
|
||||
private void cleanupListeners() {
|
||||
try {
|
||||
if (locationManager != null) {
|
||||
if (gpsLocationListener != null) {
|
||||
if (ActivityCompat.checkSelfPermission(CommonAppContext.getInstance(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
|| ActivityCompat.checkSelfPermission(CommonAppContext.getInstance(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
locationManager.removeUpdates(gpsLocationListener);
|
||||
}
|
||||
gpsLocationListener = null;
|
||||
}
|
||||
|
||||
if (networkLocationListener != null) {
|
||||
if (ActivityCompat.checkSelfPermission(CommonAppContext.getInstance(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
|| ActivityCompat.checkSelfPermission(CommonAppContext.getInstance(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
|
||||
locationManager.removeUpdates(networkLocationListener);
|
||||
}
|
||||
networkLocationListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 清理超时处理
|
||||
if (timeoutHandler != null && timeoutRunnable != null) {
|
||||
timeoutHandler.removeCallbacks(timeoutRunnable);
|
||||
timeoutHandler = null;
|
||||
timeoutRunnable = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("LocationDebug", "清理监听器时出错", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 保持原有的工具方法
|
||||
private String getCityName(Context context, double latitude, double longitude) {
|
||||
android.location.Geocoder geocoder = new android.location.Geocoder(context, Locale.getDefault());
|
||||
try {
|
||||
List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
|
||||
if (addresses != null && !addresses.isEmpty()) {
|
||||
return addresses.get(0).getAdminArea() + "," + addresses.get(0).getLocality()+ "," + addresses.get(0).getSubLocality();
|
||||
return addresses.get(0).getAdminArea() + "," + addresses.get(0).getLocality() + "," + addresses.get(0).getSubLocality();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@@ -213,7 +218,6 @@ public class SystemLocationProvider implements LocationProvider {
|
||||
return "未知城市";
|
||||
}
|
||||
|
||||
|
||||
public void useNetworkLocation(Context context, LocationCallback callback) {
|
||||
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
if (locationManager == null) {
|
||||
@@ -228,31 +232,15 @@ public class SystemLocationProvider implements LocationProvider {
|
||||
}
|
||||
|
||||
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
||||
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, new LocationListener() {
|
||||
@Override
|
||||
public void onLocationChanged(@NonNull Location location) {
|
||||
String city = getCityName(context, location.getLatitude(), location.getLongitude());
|
||||
callback.onLocationReceived(location.getLatitude(), location.getLongitude(), city);
|
||||
}
|
||||
// 清理之前的网络监听器
|
||||
if (networkLocationListener != null) {
|
||||
locationManager.removeUpdates(networkLocationListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
ToastUtils.showShort(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(@NonNull String provider) {
|
||||
ToastUtils.showShort(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(@NonNull String provider) {
|
||||
callback.onFailed("网络定位不可用");
|
||||
}
|
||||
}, Looper.getMainLooper());
|
||||
networkLocationListener = new LocationListenerImpl(callback, context, false);
|
||||
locationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, networkLocationListener, Looper.getMainLooper());
|
||||
} else {
|
||||
callback.onFailed("网络定位未启用");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
@@ -19,6 +20,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import com.blankj.utilcode.util.LogUtils;
|
||||
import com.blankj.utilcode.util.PathUtils;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
@@ -39,6 +41,7 @@ import com.qxcm.moduleutil.R;
|
||||
import com.qxcm.moduleutil.databinding.RoomViewSvgaAnimBinding;
|
||||
import com.qxcm.moduleutil.utils.DownloadUtil;
|
||||
import com.qxcm.moduleutil.utils.Md5Utils;
|
||||
import com.qxcm.moduleutil.utils.MemoryOptimizationUtils;
|
||||
import com.qxcm.moduleutil.utils.SpUtil;
|
||||
import com.qxcm.moduleutil.utils.logger.Logger;
|
||||
import com.tencent.qgame.animplayer.AnimConfig;
|
||||
@@ -46,13 +49,15 @@ import com.tencent.qgame.animplayer.inter.IAnimListener;
|
||||
import com.tencent.qgame.animplayer.inter.IFetchResource;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
|
||||
public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
|
||||
@Override
|
||||
public void onFailed(int i, @Nullable String s) {
|
||||
|
||||
@@ -75,15 +80,37 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
|
||||
@Override
|
||||
public void onVideoComplete() {
|
||||
// if (mType == 1) {
|
||||
// mBinding.playView.startPlay(mFile); // 循环播放
|
||||
// } else {
|
||||
// isPlaying = false;
|
||||
// playNextFromQueue(); // 播放下一项
|
||||
// }
|
||||
if (isDestroyed) return;
|
||||
|
||||
// 确保在主线程中执行
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
handleVideoComplete();
|
||||
} else {
|
||||
mainHandler.post(() -> {
|
||||
if (!isDestroyed) {
|
||||
handleVideoComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
private void handleVideoComplete() {
|
||||
if (isDestroyed) return;
|
||||
|
||||
if (mType == 1) {
|
||||
mBinding.playView.startPlay(mFile); // 循环播放
|
||||
if (mBinding != null && mFile != null) {
|
||||
mBinding.playView.startPlay(mFile); // 循环播放
|
||||
}
|
||||
} else {
|
||||
isPlaying = false;
|
||||
playNextFromQueue(); // 播放下一项
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoDestroy() {
|
||||
|
||||
@@ -101,11 +128,19 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
private int mType;//1:循环播放 2:播放一次停止播放
|
||||
private File mFile;
|
||||
private final Queue<PlayItem> playQueue = new LinkedList<>();
|
||||
|
||||
private boolean isPlaying = false;
|
||||
|
||||
|
||||
// 添加销毁标记
|
||||
private boolean isDestroyed = false;
|
||||
private static final String TAG = "AvatarFrameView";
|
||||
private RoomViewSvgaAnimBinding mBinding;
|
||||
|
||||
// 内存监控
|
||||
private static final long MAX_MEMORY_THRESHOLD = 300 * 1024 * 1024; // 300MB
|
||||
private static final int MAX_SVGA_CACHE_SIZE = 3;
|
||||
private final Map<String, WeakReference<SVGAVideoEntity>> svgaCache = new LruCache<>(MAX_SVGA_CACHE_SIZE);
|
||||
|
||||
|
||||
public AvatarFrameView(@NonNull Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -121,6 +156,7 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
if (isDestroyed) return;
|
||||
// 初始化 ExoPlayer View
|
||||
playerView = new PlayerView(getContext());
|
||||
playerView.setUseController(false);
|
||||
@@ -142,10 +178,18 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
// addView(glSurfaceView);
|
||||
|
||||
// 初始化 ExoPlayer
|
||||
exoPlayer = new ExoPlayer.Builder(getContext()).build();
|
||||
playerView.setPlayer(exoPlayer);
|
||||
if (!isDestroyed) {
|
||||
try {
|
||||
exoPlayer = new ExoPlayer.Builder(getContext()).build();
|
||||
playerView.setPlayer(exoPlayer);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e("AvatarFrameView", "Failed to initialize ExoPlayer: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
mBinding.playView.setAnimListener(this);
|
||||
if (mBinding != null) {
|
||||
mBinding.playView.setAnimListener(this);
|
||||
}
|
||||
}
|
||||
private String getFileExtension(String url) {
|
||||
if (url == null || url.isEmpty()) return "";
|
||||
@@ -156,7 +200,18 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
return "";
|
||||
}
|
||||
private void playNextFromQueue() {
|
||||
|
||||
if (isDestroyed) return;
|
||||
// 确保在主线程中执行
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(this::playNextFromQueue);
|
||||
return;
|
||||
}
|
||||
// 再次检查内存状态
|
||||
if (isMemoryLow()) {
|
||||
LogUtils.w(TAG, "Low memory, clearing queue");
|
||||
clearQueue();
|
||||
return;
|
||||
}
|
||||
// 检查特效是否开启
|
||||
if (SpUtil.getOpenEffect() != 1) {
|
||||
clearQueue();
|
||||
@@ -202,6 +257,18 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
}
|
||||
}
|
||||
public void setSource(String url, int type2) {
|
||||
if (isDestroyed) return;
|
||||
// 确保在主线程中执行
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(() -> setSource(url, type2));
|
||||
return;
|
||||
}
|
||||
// 检查内存状态
|
||||
if (isMemoryLow()) {
|
||||
LogUtils.w(TAG, "Low memory, skipping animation");
|
||||
clearQueue();
|
||||
return;
|
||||
}
|
||||
// 检查特效是否开启
|
||||
if (SpUtil.getOpenEffect() != 1) {
|
||||
// 特效关闭时清空队列并停止播放
|
||||
@@ -219,7 +286,15 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
playNextFromQueue();
|
||||
}
|
||||
}
|
||||
private boolean isMemoryLow() {
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
long usedMemory = runtime.totalMemory() - runtime.freeMemory();
|
||||
long maxMemory = runtime.maxMemory();
|
||||
double memoryUsage = (double) usedMemory / maxMemory;
|
||||
|
||||
// 内存使用超过80%或绝对使用量超过阈值
|
||||
return memoryUsage > 0.8 || usedMemory > MAX_MEMORY_THRESHOLD;
|
||||
}
|
||||
|
||||
// public void setSource(String url, int type2) {
|
||||
// if (SpUtil.getOpenEffect()==1) {
|
||||
@@ -323,7 +398,157 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSVGAComplete(SVGAVideoEntity videoItem, String url) {
|
||||
if (isDestroyed || svgaSurface == null) return;
|
||||
|
||||
try {
|
||||
// 缓存实体(使用弱引用)
|
||||
svgaCache.put(url, new WeakReference<>(videoItem));
|
||||
|
||||
SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity());
|
||||
svgaSurface.setImageDrawable(drawable);
|
||||
svgaSurface.setCallback(new SVGACallback() {
|
||||
@Override
|
||||
public void onStep(int i, double v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeat() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished() {
|
||||
if (isDestroyed) return;
|
||||
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(() -> {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
});
|
||||
} else {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
}
|
||||
});
|
||||
svgaSurface.startAnimation();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error handling SVGA completion: " + e.getMessage());
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
}
|
||||
|
||||
private void playCachedSVGA(SVGAVideoEntity videoItem) {
|
||||
if (isDestroyed || svgaSurface == null) return;
|
||||
|
||||
try {
|
||||
SVGADrawable drawable = new SVGADrawable(videoItem, new SVGADynamicEntity());
|
||||
svgaSurface.setImageDrawable(drawable);
|
||||
svgaSurface.setCallback(new SVGACallback() {
|
||||
@Override
|
||||
public void onStep(int i, double v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRepeat() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished() {
|
||||
if (isDestroyed) return;
|
||||
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(() -> {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
});
|
||||
} else {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
}
|
||||
});
|
||||
svgaSurface.startAnimation();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error playing cached SVGA: " + e.getMessage());
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
}
|
||||
private void loadNewSVGA(String url) {
|
||||
if (isDestroyed) return;
|
||||
|
||||
try {
|
||||
new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
|
||||
@Override
|
||||
public void onComplete(SVGAVideoEntity videoItem) {
|
||||
if (isDestroyed) return;
|
||||
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(() -> handleSVGAComplete(videoItem, url));
|
||||
} else {
|
||||
handleSVGAComplete(videoItem, url);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError() {
|
||||
if (isDestroyed) return;
|
||||
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(() -> {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
});
|
||||
} else {
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error parsing SVGA: " + e.getMessage());
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
}
|
||||
private void loadSVGA(String url) {
|
||||
if (isDestroyed || svgaSurface == null) return;
|
||||
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(() -> loadSVGA(url));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
svgaSurface.setVisibility(View.VISIBLE);
|
||||
|
||||
// 检查缓存
|
||||
WeakReference<SVGAVideoEntity> cachedRef = svgaCache.get(url);
|
||||
SVGAVideoEntity cachedEntity = cachedRef != null ? cachedRef.get() : null;
|
||||
|
||||
if (cachedEntity != null) {
|
||||
// 使用缓存的实体
|
||||
playCachedSVGA(cachedEntity);
|
||||
} else {
|
||||
// 加载新的SVGA
|
||||
loadNewSVGA(url);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error loading SVGA: " + e.getMessage());
|
||||
isPlaying = false;
|
||||
playNextFromQueue();
|
||||
}
|
||||
|
||||
svgaSurface.setVisibility(View.VISIBLE);
|
||||
try {
|
||||
new SVGAParser(getContext()).parse(new URL(url), new SVGAParser.ParseCompletion() {
|
||||
@@ -406,38 +631,201 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
}
|
||||
|
||||
private void clearPrevious() {
|
||||
// if (exoPlayer != null) {
|
||||
// exoPlayer.stop();
|
||||
// exoPlayer.clearVideoSurface();
|
||||
// }
|
||||
|
||||
if (svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||||
((SVGADrawable) svgaSurface.getDrawable()).stop();
|
||||
if (isDestroyed) return;
|
||||
// 确保在主线程中执行
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(() -> {
|
||||
if (!isDestroyed) {
|
||||
clearPrevious();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 停止并清理 ExoPlayer
|
||||
if (exoPlayer != null) {
|
||||
try {
|
||||
exoPlayer.stop(); // 这里可能会在错误线程中调用
|
||||
exoPlayer.clearVideoSurface();
|
||||
} catch (Exception e) {
|
||||
Logger.e("Error stopping ExoPlayer: " + e.getMessage());
|
||||
// 如果在错误线程中,切换到主线程重试
|
||||
mainHandler.post(() -> {
|
||||
try {
|
||||
if (exoPlayer != null) {
|
||||
exoPlayer.stop();
|
||||
exoPlayer.clearVideoSurface();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.e("Error stopping ExoPlayer on main thread: " + ex.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// 停止并清理 SVGA 动画
|
||||
if (svgaSurface != null && svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||||
SVGADrawable drawable = (SVGADrawable) svgaSurface.getDrawable();
|
||||
if (drawable != null) {
|
||||
drawable.stop();
|
||||
// 清理 SVGADrawable 中的资源
|
||||
svgaSurface.clearAnimation();
|
||||
svgaSurface.setImageDrawable(null);
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏所有视图
|
||||
if (playerView != null) playerView.setVisibility(View.GONE);
|
||||
if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
|
||||
mBinding.playView.setVisibility(View.GONE);
|
||||
|
||||
// 停止播放器
|
||||
if (mBinding.playView != null) {
|
||||
mBinding.playView.stopPlay();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error in clearPrevious: " + e.getMessage());
|
||||
}
|
||||
|
||||
// if (svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||||
// ((SVGADrawable) svgaSurface.getDrawable()).stop();
|
||||
// }
|
||||
|
||||
// if (playerView != null) playerView.setVisibility(View.GONE);
|
||||
// if (svgaSurface != null) svgaSurface.setVisibility(View.GONE);
|
||||
// if (glSurfaceView != null) glSurfaceView.setVisibility(View.GONE);
|
||||
// mBinding.playView.setVisibility(View.GONE);
|
||||
}
|
||||
// 简单的 LRU Cache 实现
|
||||
private static class LruCache<K, V> extends LinkedHashMap<K, V> {
|
||||
private final int maxSize;
|
||||
|
||||
public void release() {
|
||||
// if (exoPlayer != null) {
|
||||
// exoPlayer.release();
|
||||
// }
|
||||
|
||||
if (svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||||
((SVGADrawable) svgaSurface.getDrawable()).stop();
|
||||
public LruCache(int maxSize) {
|
||||
super(16, 0.75f, true);
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
if (glSurfaceView != null) {
|
||||
glSurfaceView.onPause(); // 必须调用生命周期方法
|
||||
// glSurfaceView.requestRender();
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
|
||||
return size() > maxSize;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 释放所有资源
|
||||
*/
|
||||
private void releaseResources() {
|
||||
LogUtils.d(TAG, "Releasing all resources");
|
||||
|
||||
if (isDestroyed) return;
|
||||
|
||||
try {
|
||||
// 清理 SVGA 资源
|
||||
if (svgaSurface != null && svgaSurface.getDrawable() instanceof SVGADrawable) {
|
||||
SVGADrawable drawable = (SVGADrawable) svgaSurface.getDrawable();
|
||||
if (drawable != null) {
|
||||
try {
|
||||
drawable.stop();
|
||||
svgaSurface.clearAnimation();
|
||||
svgaSurface.setImageDrawable(null);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error releasing SVGA resources: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 停止并清理播放器
|
||||
if (mBinding != null && mBinding.playView != null) {
|
||||
mBinding.playView.stopPlay();
|
||||
}
|
||||
|
||||
// 清理 ExoPlayer 资源
|
||||
if (exoPlayer != null) {
|
||||
try {
|
||||
exoPlayer.stop();
|
||||
exoPlayer.clearVideoSurface();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error releasing ExoPlayer resources: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error in releaseResources: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 公共释放方法,用于外部主动释放资源
|
||||
*/
|
||||
public void release() {
|
||||
Logger.d("AvatarFrameView", "Public release called");
|
||||
if (isDestroyed) return;
|
||||
// 确保在主线程中执行
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
mainHandler.post(this::release);
|
||||
return;
|
||||
}
|
||||
isDestroyed = true;
|
||||
|
||||
try {
|
||||
// 清空播放队列
|
||||
clearQueue();
|
||||
|
||||
// 释放所有资源
|
||||
releaseResources();
|
||||
|
||||
// 释放 ExoPlayer
|
||||
if (exoPlayer != null) {
|
||||
try {
|
||||
exoPlayer.stop();
|
||||
exoPlayer.release();
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error releasing ExoPlayer: " + e.getMessage());
|
||||
}
|
||||
exoPlayer = null;
|
||||
}
|
||||
|
||||
// 清理 PlayerView
|
||||
if (playerView != null) {
|
||||
try {
|
||||
playerView.setPlayer(null);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error releasing PlayerView: " + e.getMessage());
|
||||
}
|
||||
playerView = null;
|
||||
}
|
||||
|
||||
// 清理 SVGAImageView
|
||||
if (svgaSurface != null) {
|
||||
try {
|
||||
svgaSurface.pauseAnimation();
|
||||
svgaSurface.clearAnimation();
|
||||
svgaSurface.setImageDrawable(null);
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error releasing SVGAImageView: " + e.getMessage());
|
||||
}
|
||||
svgaSurface = null;
|
||||
}
|
||||
|
||||
// 清理 binding
|
||||
if (mBinding != null) {
|
||||
mBinding = null;
|
||||
}
|
||||
|
||||
// 清理队列
|
||||
playQueue.clear();
|
||||
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "Error in AvatarFrameView release: " + e.getMessage());
|
||||
} finally {
|
||||
// 建议进行垃圾回收
|
||||
MemoryOptimizationUtils.forceGC();
|
||||
}
|
||||
}
|
||||
public void clearQueue() {
|
||||
if (isDestroyed) return;
|
||||
playQueue.clear();
|
||||
isPlaying = false;
|
||||
// 清理当前正在播放的内容
|
||||
clearPrevious();
|
||||
}
|
||||
|
||||
|
||||
@@ -454,8 +842,13 @@ public class AvatarFrameView extends FrameLayout implements IAnimListener {
|
||||
* 关闭特效
|
||||
*/
|
||||
public void closeEffect() {
|
||||
|
||||
// 清空队列
|
||||
clearQueue();
|
||||
// 释放资源
|
||||
releaseResources();
|
||||
//清空队列
|
||||
playQueue.clear();
|
||||
// playQueue.clear();
|
||||
//关闭动画
|
||||
// if (mBinding.image != null && isPlaying && mBinding.image.isAnimating()) {
|
||||
// mBinding.image.setAnimation(null);
|
||||
|
||||
@@ -285,6 +285,8 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
if (pitBean != null && pitBean.getUser_id() != null && !pitBean.getUser_id().equals("0")) {
|
||||
if (pitBean.getUser_id().equals(userId + "")) {
|
||||
iv_on_line.setVisibility(GONE);
|
||||
mIvRipple.stopAnimation();
|
||||
mIvRipple.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,12 +299,16 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
}
|
||||
}else if (pitBean.getUser_id()==null || pitBean.getUser_id().equals("0") || pitBean.getUser_id().equals("")){
|
||||
iv_on_line.setVisibility(GONE);
|
||||
mIvRipple.stopAnimation();
|
||||
mIvRipple.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
if (pitBean.getUser_id()==null || pitBean.getUser_id().equals("0") || pitBean.getUser_id().equals("") ){
|
||||
iv_on_line.setVisibility(GONE);
|
||||
mIvRipple.stopAnimation();
|
||||
mIvRipple.setVisibility(GONE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -361,6 +367,8 @@ public abstract class BaseWheatView extends ConstraintLayout implements IBaseWhe
|
||||
if (pitBean.getUser_id().equals(isOnline.getUser_id())) {
|
||||
if (isOnline.getIs_online() == 1) {
|
||||
iv_on_line.setVisibility(GONE);
|
||||
mIvRipple.stopAnimation();
|
||||
mIvRipple.setVisibility(GONE);
|
||||
} else {
|
||||
iv_on_line.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
package com.qxcm.moduleutil.widget
|
||||
|
||||
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.opengl.GLES20
|
||||
import android.opengl.Matrix
|
||||
|
||||
class ChannelSplitRenderer {
|
||||
|
||||
private val vertexShaderCode = """
|
||||
attribute vec4 aPosition;
|
||||
attribute vec2 aTexCoord;
|
||||
varying vec2 vTexCoord;
|
||||
void main() {
|
||||
gl_Position = aPosition;
|
||||
vTexCoord = aTexCoord;
|
||||
}
|
||||
"""
|
||||
|
||||
private val fragmentShaderCode = """
|
||||
precision mediump float;
|
||||
uniform sampler2D uTexture;
|
||||
varying vec2 vTexCoord;
|
||||
void main() {
|
||||
// 只使用左半部分作为最终颜色
|
||||
vec2 leftCoord = vec2(vTexCoord.x * 0.5, vTexCoord.y);
|
||||
vec4 color = texture2D(uTexture, leftCoord);
|
||||
|
||||
// 设置 alpha 为 1.0 表示完全不透明,或根据需求设为 0.0 表示全透明
|
||||
gl_FragColor = vec4(color.rgb, 0.0); // 左通道颜色 + 不透明
|
||||
}"""
|
||||
|
||||
private var program = 0
|
||||
private var positionHandle = 0
|
||||
private var texCoordHandle = 0
|
||||
private var textureHandle = 0
|
||||
private val projectionMatrix = FloatArray(16)
|
||||
private val modelMatrix = FloatArray(16)
|
||||
|
||||
fun onSurfaceCreated(surface: SurfaceTexture, width: Int, height: Int) {
|
||||
// 初始化着色器
|
||||
val vertexShader = ShaderUtils.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
|
||||
val fragmentShader = ShaderUtils.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
|
||||
|
||||
program = GLES20.glCreateProgram().also {
|
||||
GLES20.glAttachShader(it, vertexShader)
|
||||
GLES20.glAttachShader(it, fragmentShader)
|
||||
GLES20.glLinkProgram(it)
|
||||
}
|
||||
|
||||
positionHandle = GLES20.glGetAttribLocation(program, "aPosition")
|
||||
texCoordHandle = GLES20.glGetAttribLocation(program, "aTexCoord")
|
||||
textureHandle = GLES20.glGetUniformLocation(program, "uTexture")
|
||||
|
||||
// 初始化矩阵
|
||||
Matrix.setIdentityM(projectionMatrix, 0)
|
||||
Matrix.setIdentityM(modelMatrix, 0)
|
||||
|
||||
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
GLES20.glEnable(GLES20.GL_BLEND)
|
||||
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
}
|
||||
|
||||
fun onSurfaceChanged(width: Int, height: Int) {
|
||||
GLES20.glViewport(0, 0, width, height)
|
||||
}
|
||||
|
||||
fun onDrawFrame(textureId: Int) {
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
|
||||
GLES20.glUseProgram(program)
|
||||
|
||||
// 定义顶点坐标(全屏)
|
||||
val vertices = floatArrayOf(
|
||||
-1.0f, -1.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f
|
||||
)
|
||||
|
||||
// 修改纹理坐标,只映射左半部分视频内容到左侧屏幕
|
||||
val texCoords = floatArrayOf(
|
||||
0.0f, 1.0f, // 左下角
|
||||
0.5f, 1.0f, // 右下角(对应视频中间)
|
||||
0.0f, 0.0f, // 左上角
|
||||
0.5f, 0.0f // 右上角
|
||||
)
|
||||
|
||||
val vertexBuffer = ShaderUtils.createFloatBuffer(vertices)
|
||||
val texBuffer = ShaderUtils.createFloatBuffer(texCoords)
|
||||
|
||||
GLES20.glEnableVertexAttribArray(positionHandle)
|
||||
GLES20.glVertexAttribPointer(
|
||||
positionHandle, 3,
|
||||
GLES20.GL_FLOAT, false,
|
||||
0, vertexBuffer
|
||||
)
|
||||
|
||||
GLES20.glEnableVertexAttribArray(texCoordHandle)
|
||||
GLES20.glVertexAttribPointer(
|
||||
texCoordHandle, 2,
|
||||
GLES20.GL_FLOAT, false,
|
||||
0, texBuffer
|
||||
)
|
||||
|
||||
// 绑定纹理
|
||||
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
|
||||
GLES20.glUniform1i(textureHandle, 0)
|
||||
|
||||
// 绘制
|
||||
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
|
||||
|
||||
// 清理
|
||||
GLES20.glDisableVertexAttribArray(positionHandle)
|
||||
GLES20.glDisableVertexAttribArray(texCoordHandle)
|
||||
}
|
||||
|
||||
|
||||
fun release() {
|
||||
GLES20.glDeleteProgram(program)
|
||||
}
|
||||
}
|
||||
@@ -370,6 +370,8 @@ public class Constants {
|
||||
public static final String dailyTasksComplete = "/api/Dailytasks/dailyTasksComplete";//领取每日任务奖励
|
||||
public static final String POST_CANCEL_USER_DECORATE = "/api/Decorate/cancel_user_decorate";//取消装扮
|
||||
public static final String GET_THEME_DATA = "/api/Theme/get_theme_data";//主题接口
|
||||
public static final String MODIFY_MOBILE = "/api/UserData/modify_mobile";//手机换绑
|
||||
public static final String BIND_MOBILE = "/api/UserData/bind_mobile";//手机绑定
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@ import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.blankj.utilcode.util.LogUtils;
|
||||
import com.petterp.floatingx.FloatingX;
|
||||
import com.petterp.floatingx.assist.FxGravity;
|
||||
import com.petterp.floatingx.assist.helper.FxAppHelper;
|
||||
@@ -23,6 +25,9 @@ import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* @Author
|
||||
* @Time 2025/7/18 21:52
|
||||
@@ -33,6 +38,8 @@ public class PiaoPingManager {
|
||||
private WindowManager windowManager;
|
||||
private View piaoPingView;
|
||||
private boolean isPiaoPingShown = false;
|
||||
private Queue<MqttBean> messageQueue = new ConcurrentLinkedQueue<>(); // 消息队列
|
||||
private boolean isAnimating = false; // 动画状态标记
|
||||
|
||||
private PiaoPingManager(Context context) {
|
||||
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
@@ -52,11 +59,64 @@ public class PiaoPingManager {
|
||||
|
||||
public void showPiaoPingMessage(MqttBean mqttBean) {
|
||||
// 创建 FloatingX 配置
|
||||
// 添加到队列
|
||||
messageQueue.offer(mqttBean);
|
||||
// 如果当前没有动画正在进行,则开始处理
|
||||
if (!isAnimating) {
|
||||
processNextMessage();
|
||||
}
|
||||
|
||||
// // 获取悬浮窗视图并设置内容
|
||||
//// 替换第72行及后续对 layoutView 的直接访问
|
||||
// View floatingView = LayoutInflater.from(context).inflate(R.layout.item_piaoping, new FrameLayout(context), false);
|
||||
// TextView textView = floatingView.findViewById(R.id.tv_name);
|
||||
// TextView textView2 = floatingView.findViewById(R.id.tv_to_name);
|
||||
// textView2.setText("送给" + mqttBean.getList().getToUserName());
|
||||
// textView.setText(mqttBean.getList().getFromUserName());
|
||||
// ImageUtils.loadHeadCC(mqttBean.getList().getGift_picture(), floatingView.findViewById(R.id.iv_piaoping));
|
||||
// TextView tv_time = floatingView.findViewById(R.id.tv_num);
|
||||
// tv_time.setText("x" + mqttBean.getList().getNumber());
|
||||
//
|
||||
// // 3秒后执行左侧滑动关闭动画
|
||||
// floatingView.postDelayed(() -> {
|
||||
// // 实现左侧滑出动画
|
||||
// ObjectAnimator animator = ObjectAnimator.ofFloat(floatingView, "translationX", 0f, -floatingView.getWidth());
|
||||
// animator.setDuration(300); // 300ms 动画时间
|
||||
// animator.addListener(new AnimatorListenerAdapter() {
|
||||
// @Override
|
||||
// public void onAnimationEnd(Animator animation) {
|
||||
// // 动画结束后移除悬浮窗
|
||||
// FloatingX.uninstallAll();
|
||||
// }
|
||||
// });
|
||||
// animator.start();
|
||||
// }, 3000);
|
||||
//
|
||||
// assert floatingView != null;
|
||||
// FxAppHelper fxAppHelper = FxAppHelper.builder()
|
||||
// .setContext(context)
|
||||
// .setLayoutView(floatingView)
|
||||
// .setGravity(FxGravity.LEFT_OR_TOP)
|
||||
// .setY(100)
|
||||
// .build();
|
||||
//
|
||||
// FloatingX.install(fxAppHelper).show();
|
||||
}
|
||||
|
||||
private void processNextMessage() {
|
||||
if (messageQueue.isEmpty()) {
|
||||
isAnimating = false;
|
||||
return;
|
||||
}
|
||||
|
||||
isAnimating = true;
|
||||
MqttBean mqttBean = messageQueue.poll();
|
||||
displayMessage(mqttBean);
|
||||
}
|
||||
|
||||
private void displayMessage(MqttBean mqttBean) {
|
||||
// 获取悬浮窗视图并设置内容
|
||||
// 替换第72行及后续对 layoutView 的直接访问
|
||||
View floatingView = LayoutInflater.from(context).inflate(R.layout.item_piaoping, new FrameLayout(context), false);
|
||||
View floatingView = LayoutInflater.from(context).inflate(R.layout.item_piaoping, new FrameLayout(context), false);
|
||||
TextView textView = floatingView.findViewById(R.id.tv_name);
|
||||
TextView textView2 = floatingView.findViewById(R.id.tv_to_name);
|
||||
textView2.setText("送给" + mqttBean.getList().getToUserName());
|
||||
@@ -65,38 +125,74 @@ public class PiaoPingManager {
|
||||
TextView tv_time = floatingView.findViewById(R.id.tv_num);
|
||||
tv_time.setText("x" + mqttBean.getList().getNumber());
|
||||
|
||||
// 3秒后执行左侧滑动关闭动画
|
||||
floatingView.postDelayed(() -> {
|
||||
// 实现左侧滑出动画
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(floatingView, "translationX", 0f, -floatingView.getWidth());
|
||||
animator.setDuration(300); // 300ms 动画时间
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// 动画结束后移除悬浮窗
|
||||
FloatingX.uninstallAll();
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
}, 3000);
|
||||
// 先将视图放置在屏幕右侧外部,避免闪现问题
|
||||
floatingView.setTranslationX(10000); // 先放到屏幕外
|
||||
|
||||
assert floatingView != null;
|
||||
FxAppHelper fxAppHelper = FxAppHelper.builder()
|
||||
.setContext(context)
|
||||
.setLayoutView(floatingView)
|
||||
.setGravity(FxGravity.LEFT_OR_TOP)
|
||||
.setGravity(FxGravity.RIGHT_OR_TOP)
|
||||
.setX(0)
|
||||
.setY(100)
|
||||
.build();
|
||||
|
||||
FloatingX.install(fxAppHelper).show();
|
||||
|
||||
// 首先从右侧滑入到屏幕中央
|
||||
floatingView.post(() -> {
|
||||
// 确保初始位置在屏幕右侧外部
|
||||
floatingView.setTranslationX(floatingView.getWidth());
|
||||
|
||||
// 第一阶段:从右到屏幕右侧边缘(缓慢进入)
|
||||
ObjectAnimator animator1 = ObjectAnimator.ofFloat(floatingView, "translationX",
|
||||
floatingView.getWidth(), 0f);
|
||||
animator1.setDuration(1500); // 延长动画时间到1.5秒
|
||||
animator1.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果
|
||||
animator1.start();
|
||||
|
||||
// 第二阶段:延迟1秒后从当前位置向左滑出
|
||||
floatingView.postDelayed(() -> {
|
||||
ObjectAnimator animator2 = ObjectAnimator.ofFloat(floatingView, "translationX",
|
||||
0f, -floatingView.getWidth());
|
||||
animator2.setDuration(1500); // 延长动画时间到1.5秒
|
||||
animator2.setInterpolator(new DecelerateInterpolator(2.0f)); // 更平缓的减速效果
|
||||
animator2.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
// 动画结束后移除悬浮窗
|
||||
FloatingX.uninstallAll();
|
||||
// 处理下一个消息
|
||||
processNextMessage();
|
||||
}
|
||||
});
|
||||
animator2.start();
|
||||
}, 1000); // 停留1秒
|
||||
});
|
||||
}
|
||||
|
||||
public void subscribe() {
|
||||
EventBus.getDefault().register(this);
|
||||
try {
|
||||
if (!EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 处理重复注册或其他异常
|
||||
LogUtils.e("PiaoPingManager subscribe error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void unsubscribe() {
|
||||
EventBus.getDefault().unregister(this);
|
||||
try {
|
||||
if (EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 处理取消注册异常
|
||||
LogUtils.e("PiaoPingManager unsubscribe error: " + e.getMessage());
|
||||
}
|
||||
messageQueue.clear();
|
||||
isAnimating = false; // 重置动画状态
|
||||
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
||||
Reference in New Issue
Block a user