使用ViewBinding时遇到 java.lang.ClassCastException: android.widget.RelativeLayout cannot be

本文介绍了一个关于Android开发中使用ViewBinding时遇到的ID名称冲突问题。通过一个具体的例子展示了当主界面使用include标签引入布局文件时,相同ID名称如何导致ClassCastException异常,并给出了修改建议。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

使用ViewBinding时遇到 java.lang.ClassCastException: android.widget.RelativeLayout cannot be cast to cast to android.widget.TextView

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <Button
        android:id="@+id/back"
        android:layout_margin="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:text="Back" />

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Title"
        android:textSize="20sp" />

    <Button
        android:id="@+id/done"
        android:layout_margin="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:text="Done" />

</RelativeLayout>

在标题的Xml中textVIew的ID是title

<include
        android:id="@+id/title"
        layout="@layout/titlebar" />
        

在主界面使用Include<>来引入布局时,设置的布局id也是title,
在使用ViewBinding时会发生混淆,故要将id名设置成不同的。

FATAL EXCEPTION: main Process: person.tools.treasurebox, PID: 8622 android.view.InflateException: Binary XML file line #38: person.tools.treasurebox.customview.widget.CustomizeTextView cannot be cast to android.view.ViewGroup Caused by: java.lang.ClassCastException: person.tools.treasurebox.customview.widget.CustomizeTextView cannot be cast to android.view.ViewGroup at android.view.LayoutInflater.rInflate(LayoutInflater.java:885) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:845) at android.view.LayoutInflater.rInflate(LayoutInflater.java:887) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:845) at android.view.LayoutInflater.rInflate(LayoutInflater.java:887) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:845) at android.view.LayoutInflater.inflate(LayoutInflater.java:519) at android.view.LayoutInflater.inflate(LayoutInflater.java:427) at person.tools.treasurebox.customview.adapter.StockAdapter.onCreateViewHolder(StockAdapter.java:49) at person.tools.treasurebox.customview.adapter.StockAdapter.onCreateViewHolder(StockAdapter.java:25) at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7295) at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6416) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6300) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6296) at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1631) at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4309) at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3686) at android.view.View.measure(View.java:23386) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535) at android.widget.LinearLayout.measureVertical(LinearLayout.java:825) at android.widget.LinearLayout.onMeasure(LinearLayout.java:704) at android.view.View.measure(View.java:23386) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828) at android.widget.FrameLayout.onMeasure(FrameLayout.java:185) at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:145) at android.view.View.measure(View.java:23386) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535) at android.widget.LinearLayout.measureVertical(LinearLayout.java:825) at android.widget.LinearLayout.onMeasure(LinearLayout.java:704) at android.view.View.measure(View.java:23386) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828) at android.widget.FrameLayout.onMeasure(FrameLayout.java:185) at android.view.View.measure(View.java:23386) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1535) at android.widget.LinearLayout.measureVertical(LinearLayout.java:825) at android.widget.LinearLayout.onMeasure(LinearLayout.java:704) at android.view.View.measure(View.java:23386) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6828) at android.widget.FrameLayout.onMeasure(FrameLayout.java:185) at com.android.internal.policy.DecorView.onMeasure(DecorView.java:721) at android.view.View.measure(View.java:23386) at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2914) at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1706) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2001) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1594) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7661) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1047) at android.view.Choreographer.doCallbacks(Choreographer.java:843) at android.view.Choreographer.doFrame(Choreographer.java:771) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1033) at android.os.Handler.handleCallback(Handler.java:873) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:201) at android.app.ActivityThread.main(ActivityThread.java:6820) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922) Sending signal. PID: 8622 SIG: 9 ---------------------------- PROCESS ENDED (8622) for package person.tools.treasurebox ---------------------------- ---------------------------- PROCESS STARTED (8704) for package person.tools.treasurebox ---------------------------- 错误分析
10-30
package com.example.layoutdome; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.MediaController; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import android.widget.VideoView; import com.example.mylibrary.Usages; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MainActivity extends AppCompatActivity implements DataUploader.OnDataReceivedListener { private List<DataList> dataLists = new ArrayList<>(); private int type; private DataList.DataDTO.ComponentsDTO.SetStyleDTO setStyle; private TextView tvDate, tvWeather, tvList; private FullScreenVideoView tvVideo; private VerticalMarqueeTextView tvMarquee; private String fileUrl; private List<DataList.DataDTO.ComponentsDTO.SetStyleDTO.VideoListDTO> videoList; private int currentIndex = 0; // 用于追踪当前播放的视频索引 private MediaController mMediaController; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView = (TextView) findViewById(R.id.text); tvMarquee = (VerticalMarqueeTextView) findViewById(R.id.tv_marquee); tvVideo = (FullScreenVideoView) findViewById(R.id.tv_video); tvDate = (TextView) findViewById(R.id.tv_date); tvWeather = (TextView) findViewById(R.id.tv_weather); tvList = (TextView) findViewById(R.id.tv_list); textView.setText("版本号:" + APKVersionCodeUtils.getVersionCode(MainActivity.this)); Usages usages = new Usages(); usages.getTimes(MainActivity.this); new DataUploader("ES0001", this).execute(); } @Override public void onDataReceived(DataList dataList) { // 当数据接收到更新 dataLists dataLists.clear(); dataLists.add(dataList); // 输出数据 for (int i = 0; i < dataLists.size(); i++) { DataList.DataDTO data = dataLists.get(i).getData(); List<DataList.DataDTO.ComponentsDTO> components = data.getComponents(); for (int j = 0; j < components.size(); j++) { type = components.get(j).getType(); Log.i("components:", "" + type); setStyle = components.get(j).getSetStyle(); //1文本组件 2图片组件 3视频组件 4天气 5日期 6线路 if (type == 1) { int height = setStyle.getHeight(); int width = setStyle.getWidth(); int left = setStyle.getLeft(); int top = setStyle.getTop(); String noticeText = setStyle.getNoticeText(); tvMarquee.setTextList(Arrays.asList( noticeText )); tvMarquee.startMarquee(); Log.i("aaaaaaa", "文本组件marqueeTop:" + top); Utils.updateLayoutParams(MainActivity.this,tvMarquee,width,height,left,top); Log.i("aaaaaaa", "文本组件:" + type); } else if (type == 2) { // int height = setStyle.getHeight(); // int width = setStyle.getWidth(); // int left = setStyle.getLeft(); // int top = setStyle.getTop(); // int videoWidth = Integer.parseInt(String.valueOf(width)); // int videoHeight = Integer.parseInt(String.valueOf(height)); // int videoTop = Integer.parseInt(String.valueOf(top)); // FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(videoWidth, videoHeight); params.width = dip2px(MainActivity.this, videoWidth); // params.height = dip2px(MainActivity.this, videoHeight); // params.leftMargin = dip2px(MainActivity.this, left); // params.topMargin = dip2px(MainActivity.this, videoTop); // tvVideo.setLayoutParams(params); // 重新设置 LayoutParams } else if (type == 3) { int height = setStyle.getHeight(); int width = setStyle.getWidth(); int left = setStyle.getLeft(); int top = setStyle.getTop(); Utils.updateLayoutParams(MainActivity.this,tvVideo,width,height,left,top); videoList = setStyle.getVideoList(); // 开始播放第一个视频 playNextVideo(); Log.i("aaaaaaa", "视频组件:" + type); } else if (type == 4) { int height = setStyle.getHeight(); int width = setStyle.getWidth(); int left = setStyle.getLeft(); int top = setStyle.getTop(); Utils.updateLayoutParams(MainActivity.this,tvWeather,width,height,left,top); Log.i("aaaaaaa", "天气组件:" + type); // Log.i("aaaaaaa", "天气组件左边距:" + params.leftMargin); // Log.i("aaaaaaa", "天气组件高:" + params.height); // Log.i("aaaaaaa", "天气组件宽:" + params.width ); // Log.i("aaaaaaa", "天气组件距上边距:" + params.topMargin); } else if (type == 5) { int height = setStyle.getHeight(); int width = setStyle.getWidth(); int left = setStyle.getLeft(); int top = setStyle.getTop(); Utils.updateLayoutParams(MainActivity.this,tvDate,width,height,left,top); Log.i("aaaaaaa", "日期组件:" + type); } else if (type == 6) { int height = setStyle.getHeight(); int width = setStyle.getWidth(); int left = setStyle.getLeft(); int top = setStyle.getTop(); Utils.updateLayoutParams(MainActivity.this,tvList,width,height,left,top); Log.i("aaaaaaa", "线路组件:" + type); } } } } private void playNextVideo() { mMediaController = new MediaController(this); if (currentIndex < videoList.size()) { String fileUrl = videoList.get(currentIndex).getStaticFileName(); Log.i("aaaaaaa", "视频地址:" + fileUrl); Uri parse = Uri.parse("http://117.71.111.12:8087/eb/static/"+fileUrl); tvVideo.setVideoURI(parse); mMediaController.setVisibility(View.GONE); mMediaController.setMediaPlayer(tvVideo); tvVideo.setMediaController(mMediaController); tvVideo.start(); // 设置视频准备好之后的监听 tvVideo.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { try { tvVideo.start(); } catch (Exception e) { Log.e("VideoPlayError", "播放视频出错: " + e.getMessage()); } } }); // 设置视频播放完成后的监听 tvVideo.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if (currentIndex < videoList.size() - 1) { currentIndex++; // Move to the next video playNextVideo(); // Play next video } else { Log.i("VideoPlayer", "所有视频均已播放"); } } }); } else { Log.i("aaaaaaa", "所有视频已播放完毕"); } // 检查文件格式和编码是否受支持 tvVideo.setOnErrorListener(new MediaPlayer.OnErrorListener() { @Override public boolean onError(MediaPlayer mp, int what, int extra) { if (what == MediaPlayer.MEDIA_ERROR_UNSUPPORTED) { // 处理不支持的文件格式或编码 Log.e("VideoPlayer", "播放视频发生错误. what: " + what + ", extra: " + extra); } return false; } }); } } package com.example.layoutdome; import android.content.Context; import android.view.View; import android.widget.FrameLayout; import android.widget.RelativeLayout; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; public class Utils { /** * 设置布局参数,改变控件位置 * @param view * @param width * @param height * @param left * @param top */ static void updateLayoutParams(Context context,View view, int width, int height, int left, int top) { FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height); params.width = dip2px(context, width); params.height = dip2px(context, height); params.leftMargin = dip2px(context, left); params.topMargin = dip2px(context, top); view.setLayoutParams(params); // 重新设置 LayoutParams } /** * dp转为px * @param context 上下文 * @param dpValue dp值 * @return */ public static int dip2px(Context context, int dpValue) { float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } } 报错 java.lang.ClassCastException: android.widget.FrameLayout$LayoutParams cannot be cast to android.widget.RelativeLayout$LayoutParams
07-16
logcat:2025-06-23 15:10:40.037 1491-3220 ActivityTrigger system_server E activityStartTrigger: not whiteListedcom.hik.netsdk.SimpleDemo/com.hik.netsdk.SimpleDemo.View.MainActivity/11 2025-06-23 15:10:40.038 1491-3220 ActivityTrigger system_server E activityResumeTrigger: not whiteListedcom.hik.netsdk.SimpleDemo/com.hik.netsdk.SimpleDemo.View.MainActivity/11 2025-06-23 15:10:40.044 1491-3220 ActivityTrigger system_server E activityResumeTrigger: not whiteListedcom.hik.netsdk.SimpleDemo/com.hik.netsdk.SimpleDemo.View.MainActivity/11 ---------------------------- PROCESS STARTED (15498) for package com.hik.netsdk.SimpleDemo ---------------------------- 2025-06-23 15:10:40.330 15498-15498 ResourceType com.hik.netsdk.SimpleDemo W No package identifier when getting name for resource number 0x00000000 2025-06-23 15:10:40.366 15498-15498 ResourceType com.hik.netsdk.SimpleDemo W No package identifier when getting name for resource number 0x00000000 2025-06-23 15:10:40.399 15498-15498 NetworkSecurityConfig com.hik.netsdk.SimpleDemo D No Network Security Config specified, using platform default 2025-06-23 15:10:40.406 15498-15498 ResourceType com.hik.netsdk.SimpleDemo W No package identifier when getting name for resource number 0x00000000 2025-06-23 15:10:40.412 15498-15498 ResourceType com.hik.netsdk.SimpleDemo W No package identifier when getting name for resource number 0x00000000 2025-06-23 15:10:40.446 15498-15533 ResourceType com.hik.netsdk.SimpleDemo W No package identifier when getting name for resource number 0x00000000 2025-06-23 15:10:40.450 15498-15498 AccessibilityManager com.hik.netsdk.SimpleDemo D AccessibilityManager status: mPackageName = com.hik.netsdk.SimpleDemo, mOptimizeEnabled = true, mIsEnabled = false, mIsUiAutomationEnabled = false, mIsInterestedPackage =false 2025-06-23 15:10:40.461 15498-15533 ViewContentFactory com.hik.netsdk.SimpleDemo D initViewContentFetcherClass 2025-06-23 15:10:40.461 15498-15533 ViewContentFactory com.hik.netsdk.SimpleDemo D getInterceptorPackageInfo 2025-06-23 15:10:40.462 15498-15533 ViewContentFactory com.hik.netsdk.SimpleDemo D getInitialApplication took 1ms 2025-06-23 15:10:40.462 15498-15533 ViewContentFactory com.hik.netsdk.SimpleDemo D packageInfo.packageName: com.miui.catcherpatch 2025-06-23 15:10:40.464 15498-15533 ResourceType com.hik.netsdk.SimpleDemo W No package identifier when getting name for resource number 0x00000000 2025-06-23 15:10:40.471 15498-15503 zygote64 com.hik.netsdk.SimpleDemo I Do partial code cache collection, code=30KB, data=19KB 2025-06-23 15:10:40.471 15498-15503 zygote64 com.hik.netsdk.SimpleDemo I After code cache collection, code=30KB, data=19KB 2025-06-23 15:10:40.471 15498-15503 zygote64 com.hik.netsdk.SimpleDemo I Increasing code cache capacity to 128KB 2025-06-23 15:10:40.477 15498-15533 ViewContentFactory com.hik.netsdk.SimpleDemo D initViewContentFetcherClass took 16ms 2025-06-23 15:10:40.477 15498-15533 ContentCatcher com.hik.netsdk.SimpleDemo I ViewContentFetcher : ViewContentFetcher 2025-06-23 15:10:40.478 15498-15533 ViewContentFactory com.hik.netsdk.SimpleDemo D createInterceptor took 16ms 2025-06-23 15:10:40.670 15498-15503 zygote64 com.hik.netsdk.SimpleDemo I Do partial code cache collection, code=39KB, data=37KB 2025-06-23 15:10:40.670 15498-15503 zygote64 com.hik.netsdk.SimpleDemo I After code cache collection, code=39KB, data=37KB 2025-06-23 15:10:40.670 15498-15503 zygote64 com.hik.netsdk.SimpleDemo I Increasing code cache capacity to 256KB 2025-06-23 15:10:40.670 15498-15503 zygote64 com.hik.netsdk.SimpleDemo I Compiler allocated 4MB to compile void android.view.View.<init>(android.content.Context, android.util.AttributeSet, int, int) 2025-06-23 15:10:40.772 15498-15498 AndroidRuntime com.hik.netsdk.SimpleDemo D Shutting down VM 2025-06-23 15:10:40.774 15498-15498 AndroidRuntime com.hik.netsdk.SimpleDemo E FATAL EXCEPTION: main Process: com.hik.netsdk.SimpleDemo, PID: 15498 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.hik.netsdk.SimpleDemo/com.hik.netsdk.SimpleDemo.View.MainActivity}: java.lang.ClassCastException: androidx.appcompat.widget.AppCompatTextView cannot be cast to androidx.appcompat.widget.Toolbar at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2856) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2931) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1620) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:173) at android.app.ActivityThread.main(ActivityThread.java:6698) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782) Caused by: java.lang.ClassCastException: androidx.appcompat.widget.AppCompatTextView cannot be cast to androidx.appcompat.widget.Toolbar at com.hik.netsdk.SimpleDemo.View.MainActivity.initUIComponents(MainActivity.java:137) at com.hik.netsdk.SimpleDemo.View.MainActivity.onCreate(MainActivity.java:117) at android.app.Activity.performCreate(Activity.java:7040) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2809) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2931)  at android.app.ActivityThread.-wrap11(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1620)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:173)  at android.app.ActivityThread.main(ActivityThread.java:6698)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)  2025-06-23 15:10:40.804 15498-15498 Process com.hik.netsdk.SimpleDemo I Sending signal. PID: 15498 SIG: 9 依据上述logcat日志解决在VideoListActivity中实现通过用户在设备列表选择Videolist播放通道后传递参数跨应用ysy1.apk中实现已经云接入萤石开放平台的75台摄像头实现实预览(即摄像头实监控,现在只需要实现最基础的实预览)的功能 VideoListActivity:package com.jd.projects.wlw.video; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.AssetManager; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.support.v4.content.FileProvider; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import com.jd.projects.wlw.DeviceMapActivity; import com.jd.projects.wlw.R; import com.jd.projects.wlw.adapter.VideoDevAdapter; import com.jd.projects.wlw.dialog.CreateLoadingDialog; import com.jd.projects.wlw.hkdemo.HkMainActivity; import com.jd.projects.wlw.units.FileUtils; import com.jd.projects.wlw.units.NetHelper; import com.jd.projects.wlw.xmvideo.DahuaVideoActicity; import org.json.JSONObject; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class VideoListActivity extends Activity { private ArrayList<Map<String, String>> mvideolist; private Context context; public static Map<String, String> map; public Button curve3; private String aliasname = "";//站点别名 public static final String package_name = "com.hik.netsdk.SimpleDemo"; public static final String package_name2 = "com.example.funsdkdemo"; public static final String APK_NAME = "ysy1.apk"; public static final String APK_NAME2 = "zxcv.apk"; private int curersioncode = 11;//萤石云插件apk最新版本号。 private int curersioncode2 = 5;//雄迈插件apk最新版本号。 //private String Appkey = "05381ff665c843c398a0a3b6d6e341ac"; private String Appkey = ""; private String devserial = ""; private String VerifyCode = ""; private int channelName = 1; private String accessToken = ""; Map<String, String> mmap; private String response = ""; private CreateLoadingDialog loadingDialg = new CreateLoadingDialog(); private String user_control_power, site_control_power; private String netmode = ""; private String xmip = ""; private String xmport = ""; private String xmusername = ""; private String xmpassword = ""; private String devSn = ""; private String xmmark = ""; private double intentLat = 0.0; private double intentLng = 0.0; @SuppressLint("HandlerLeak") Handler mHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: loadingDialg.dismissLoadingDialog(); System.out.println("--访问令牌接口返回--" + response); try { JSONObject object = new JSONObject(response); String code = object.get("code").toString(); String mmsg = object.get("msg").toString(); if (code.equals("200")) { JSONObject object2 = (JSONObject) object.get("data"); accessToken = object2.get("accessToken").toString(); System.out.println("--访问令牌为:--" + accessToken); openAPK(); } else { Toast.makeText(context, mmsg, Toast.LENGTH_SHORT).show(); } } catch (Exception e) { // TODO: handle exception } break; default: break; } } ; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.avtivity_videolist); intentLat = getIntent().getDoubleExtra("intentLat", 0.0); intentLng = getIntent().getDoubleExtra("intentLng", 0.0); context = this; initData(); initView(); } private void initView() { ListView listView = (ListView) findViewById(R.id.Videolist); curve3 = (Button) findViewById(R.id.curve3); VideoDevAdapter adapter = new VideoDevAdapter(mvideolist, context); listView.setAdapter(adapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { map = mvideolist.get(position); String mark = map.get("mark"); if (mark.equals("yiwei")) { SerializableMap myMap = new SerializableMap(); myMap.setMap(map); Bundle bundle = new Bundle(); bundle.putSerializable("map", myMap); bundle.putString("user_control_power", user_control_power); bundle.putString("site_control_power", site_control_power); bundle.putString("netmode", netmode); Intent intent = new Intent(); intent.putExtras(bundle); intent.setClass(getApplicationContext(), YwVideoPlayerActivity.class); startActivity(intent); } else if (mark.equals("haikang")) { // 跳转海康页面 String strIP = map.get("serverUrl").trim(); String nPort = map.get("serverPort").trim(); String strUser = map.get("userName").trim(); String strPsd = map.get("userPwd").trim(); Bundle bundle = new Bundle(); bundle.putString("ip", strIP); bundle.putString("port", nPort); bundle.putString("username", strUser); bundle.putString("password", strPsd); bundle.putString("user_control_power", user_control_power); bundle.putString("site_control_power", site_control_power); bundle.putString("netmode", netmode); Intent intent2 = new Intent(); intent2.putExtras(bundle); intent2.setClass(getApplicationContext(), HkMainActivity.class); startActivity(intent2); } else if (mark.equals("dahua")) { // 跳转大华页面 String strIP = map.get("serverUrl").trim(); String nPort = map.get("serverPort").trim(); String strUser = map.get("userName").trim(); String strPsd = map.get("userPwd").trim(); Bundle bundle = new Bundle(); bundle.putString("ip", strIP); bundle.putString("port", nPort); bundle.putString("username", strUser); bundle.putString("password", strPsd); bundle.putString("user_control_power", user_control_power); bundle.putString("site_control_power", site_control_power); bundle.putString("netmode", netmode); Intent intent2 = new Intent(); intent2.putExtras(bundle); intent2.setClass(getApplicationContext(), DahuaVideoActicity.class); startActivity(intent2); } else if (mark.equals("xiongmai") || mark.equals("4Gxiongmai")) { xmip = map.get("serverUrl").trim(); xmport = map.get("serverPort").trim(); xmusername = map.get("userName").trim(); xmpassword = map.get("userPwd").trim(); devSn = map.get("devSn").trim();//雄迈4G球机序列号 xmmark = mark; openAPK2(); } else if (mark.equals("HK4GIPC01")) { // 海康4G摄像机---公司现在暂无使用 String strIP = map.get("serverUrl");//设备序列号 String strUser = map.get("userName");//设备验证名 String strPsd = map.get("userPwd"); Bundle bundle = new Bundle(); bundle.putString("ip", strIP.trim()); bundle.putString("username", strUser.trim()); bundle.putString("password", strPsd.trim()); Intent intent2 = new Intent(); intent2.putExtras(bundle); intent2.setClass(getApplicationContext(), Hk4GVideoMain.class); startActivity(intent2); } else if (mark.equals("HK4GIPC02")) { // 萤石云平台摄像机 devserial = map.get("serverUrl").trim();// 设备序列号 VerifyCode = map.get("serverPort").trim();// 设备验证码 Appkey = map.get("userName").trim();// AppKey channelName = Integer.parseInt(map.get("channelNum").trim());// channelName String secret = map.get("userPwd").trim();// Secret //System.out.println("---测试参数--"+appkey+"---"+secret); if (accessToken.equals("")) { loadingDialg.createLoadingDialog(context, "访问令牌获取中...").show(); // 获取访问令牌 mmap = new HashMap<>(); mmap.put("appKey", Appkey); mmap.put("appSecret", secret); new Thread(new Runnable() { @Override public void run() { response = NetHelper.submitPostData("https://open.ys7.com/api/lapp/token/get", mmap, "utf-8");//encode mHandler.sendEmptyMessage(0); } }).start(); } else { openAPK(); } } } }); findViewById(R.id.back).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO 自动生成的方法存根 VideoListActivity.this.finish(); } }); curve3.setOnClickListener(view -> { Intent intent = new Intent(VideoListActivity.this, DeviceMapActivity.class); intent.putExtra("intentLat",intentLat); intent.putExtra("intentLng",intentLng); intent.putExtra("isShowTitle",true); startActivity(intent); }); } private void initData() { //mvideolist = VideoActivity.videolist; Bundle bundle = getIntent().getExtras(); mvideolist = (ArrayList<Map<String, String>>) bundle.get("list"); aliasname = bundle.getString("aliasname"); user_control_power = bundle.getString("user_control_power"); site_control_power = bundle.getString("site_control_power"); netmode = bundle.getString("netmode"); } protected void openAPK() { // 首先判断SD卡是否可用 if (!FileUtils.getSDcard()) { Toast.makeText(this, "外部存储不可用,此功能禁用", Toast.LENGTH_SHORT).show(); } // 判断SD卡是否已安装 else if (!FileUtils.checkInstall(getApplicationContext(), package_name)) { AlertDialog.Builder builder = new AlertDialog.Builder(VideoListActivity.this); builder.setTitle("提示").setMessage("未安装视频插件,是否安装?") .setPositiveButton("安装", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // 读取APK readApk(); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }); AlertDialog dialog = builder.create(); dialog.show(); } else { //已安装应用,直接打开应用 //判断是否需要更新 PackageManager pm = context.getPackageManager(); try { //通过包名获取已安装应用的信息,然后获取版本号。在与最新版本号对比是否需要进行更新。 PackageInfo info = pm.getPackageInfo(package_name, 1); int code = info.versionCode; if (curersioncode > code) { //有新版本需要跟新 AlertDialog.Builder builder = new AlertDialog.Builder(VideoListActivity.this); builder.setTitle("提示").setMessage("视频插件需要更新,请点击安装!") .setPositiveButton("安装", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // 读取APK readApk(); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }); AlertDialog dialog = builder.create(); dialog.show(); } else { //不需要更新,直接打开APK startApk2(); } } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } protected void openAPK2() { // 首先判断SD卡是否可用 if (!FileUtils.getSDcard()) { Toast.makeText(this, "外部存储不可用,此功能禁用", Toast.LENGTH_SHORT).show(); } // 判断SD卡是否已安装 else if (!FileUtils.checkInstall(getApplicationContext(), package_name2)) { AlertDialog.Builder builder = new AlertDialog.Builder(VideoListActivity.this); builder.setTitle("提示").setMessage("未安装视频插件,是否安装?") .setPositiveButton("安装", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // 读取APK readApk2(); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }); AlertDialog dialog = builder.create(); dialog.show(); } else { //已安装应用,直接打开应用 //判断是否需要更新 PackageManager pm = context.getPackageManager(); try { //通过包名获取已安装应用的信息,然后获取版本号。在与最新版本号对比是否需要进行更新。 PackageInfo info = pm.getPackageInfo(package_name2, 1); int code = info.versionCode; if (curersioncode2 > code) { //有新版本需要跟新 AlertDialog.Builder builder = new AlertDialog.Builder(VideoListActivity.this); builder.setTitle("提示").setMessage("视频插件需要更新,请点击安装!") .setPositiveButton("安装", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // 读取APK readApk2(); } }).setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }); AlertDialog dialog = builder.create(); dialog.show(); } else { //不需要更新,直接打开APK startApk3(); } } catch (NameNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } protected void readApk() { InputStream in1 = null; OutputStream out; FileUtils fileUtils = new FileUtils(); AssetManager am = getAssets(); byte[] buffer = new byte[1024]; int read; try { in1 = am.open(APK_NAME); File file = new File(fileUtils.getSDPATH() + APK_NAME); file.createNewFile(); out = new FileOutputStream(file); while ((read = in1.read(buffer)) != -1) { out.write(buffer, 0, read); } out.flush(); in1.close(); out.close(); } catch (IOException e) { } finally { try { in1.close(); } catch (IOException e) { } } installApk(APK_NAME); } protected void readApk2() { InputStream in1 = null; InputStream in2 = null; InputStream in3 = null; InputStream in4 = null; InputStream in5 = null; OutputStream out = null; FileUtils fileUtils = new FileUtils(); AssetManager am = getAssets(); byte[] buffer = new byte[1024]; int read = 0; try { in1 = am.open("zxcv1.apk"); in2 = am.open("zxcv2.apk"); in3 = am.open("zxcv3.apk"); in4 = am.open("zxcv4.apk"); in5 = am.open("zxcv5.apk"); if (!fileUtils.isFileExist(APK_NAME2) && new File(fileUtils.getSDPATH() + APK_NAME2).length() < 1) { File file = new File(fileUtils.getSDPATH() + APK_NAME2); file.createNewFile(); out = new FileOutputStream(file); while ((read = in1.read(buffer)) != -1) { out.write(buffer, 0, read); } while ((read = in2.read(buffer)) != -1) { out.write(buffer, 0, read); } while ((read = in3.read(buffer)) != -1) { out.write(buffer, 0, read); } while ((read = in4.read(buffer)) != -1) { out.write(buffer, 0, read); } while ((read = in5.read(buffer)) != -1) { out.write(buffer, 0, read); } out.flush(); in1.close(); in2.close(); in3.close(); in4.close(); in5.close(); out.close(); } } catch (IOException e) { } finally { try { in1.close(); in2.close(); in3.close(); in4.close(); in5.close(); } catch (IOException e) { } } installApk(APK_NAME2); } protected void installApk(String apkName) { //得到了Android外部存储目录 String fileName = Environment.getExternalStorageDirectory() + "/" + apkName; Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", new File(fileName)); intent.setDataAndType(uri, "application/vnd.android.package-archive"); this.startActivity(intent); } protected void startApk2() { ComponentName componentName = new ComponentName("com.hik.netsdk.SimpleDemo", "com.hik.netsdk.SimpleDemo.View.MainActivity"); Intent intent = new Intent(); // Intent intent = new Intent("chroya.foo"); Bundle bundle = new Bundle(); /* bundle.putString("serial", "811729242");//摄像机序列号 bundle.putString("VerifyCode", "CFEJRH");//摄像机验证码 bundle.putString("accessToken", "at.13zoz9dj48txpxtmbtdbxyp86yppa0kv-8377rzprmz-1ga3ixh-2csonzo9x");//访问令牌,7天过期。 */ bundle.putString("appkey", Appkey);//Appkey bundle.putString("serial", devserial);//摄像机序列号 bundle.putString("VerifyCode", VerifyCode);//摄像机验证码 bundle.putString("accessToken", accessToken);//访问令牌 bundle.putInt("cameraNo", channelName);//通道号 intent.putExtras(bundle); intent.setComponent(componentName); startActivity(intent); } protected void startApk3() { ComponentName componentName = new ComponentName("com.example.funsdkdemo", "com.example.funsdkdemo.Xm4GSDKActivity"); Intent intent = new Intent(); // Intent intent = new Intent("chroya.foo"); Bundle bundle = new Bundle(); /* bundle.putString("serial", "811729242");//摄像机序列号 bundle.putString("VerifyCode", "CFEJRH");//摄像机验证码 bundle.putString("accessToken", "at.13zoz9dj48txpxtmbtdbxyp86yppa0kv-8377rzprmz-1ga3ixh-2csonzo9x");//访问令牌,7天过期。 */ bundle.putString("xmip", xmip); bundle.putString("xmport", xmport); bundle.putString("xmusername", xmusername); bundle.putString("xmpassword", xmpassword); bundle.putString("devSn", devSn); bundle.putString("xmmark", xmmark); //System.out.println("---aaa---"+xmip+"--"+xmport+"--"+xmusername+"--"+xmpassword+"--"+devSn+"--"+xmmark); intent.putExtras(bundle); intent.setComponent(componentName); startActivity(intent); } } 跨应用ysy1.apk的MainActivity:package com.hik.netsdk.SimpleDemo.View; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.content.Intent; import android.graphics.PixelFormat; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.ImageButton; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; // 添加 UnstableApi 注解支持 import androidx.media3.common.util.UnstableApi; import androidx.media3.common.MediaItem; import androidx.media3.common.Player; import androidx.media3.common.PlaybackException; import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DefaultHttpDataSource; import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.hls.HlsMediaSource; import androidx.media3.exoplayer.source.MediaSource; import com.hik.netsdk.SimpleDemo.R; import com.videogo.openapi.EZConstants; import com.videogo.openapi.EZOpenSDK; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; // 在类级别添加 @UnstableApi 注解 @UnstableApi public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback { // 核心参数 private String mDeviceSerial; private String mVerifyCode; private int mCameraNo = 1; private boolean isEzDevice = false; // 萤石云相关参数 private String mAppKey = "a794d58c13154caeb7d2fbb5c3420c65"; private String mAccessToken = ""; // UI组件 private SurfaceView mPreviewSurface; private SurfaceHolder mSurfaceHolder; private Toolbar m_toolbar; private ProgressBar mProgressBar; private RelativeLayout mControlLayout; private ImageButton mRotateButton; // 播放器相关 private ExoPlayer mExoPlayer; private String mPlaybackUrl; private final OkHttpClient mHttpClient = new OkHttpClient.Builder() .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .build(); // 播放器状态监听器 private final Player.Listener mPlayerListener = new Player.Listener() { @Override public void onPlaybackStateChanged(int state) { switch (state) { case Player.STATE_READY: mProgressBar.setVisibility(View.GONE); Log.d("ExoPlayer", "播放准备就绪"); break; case Player.STATE_BUFFERING: mProgressBar.setVisibility(View.VISIBLE); Log.d("ExoPlayer", "缓冲中..."); break; case Player.STATE_ENDED: Log.d("ExoPlayer", "播放结束"); break; case Player.STATE_IDLE: Log.d("ExoPlayer", "空闲状态"); break; } } @Override public void onPlayerError(PlaybackException error) { Log.e("ExoPlayer", "播放错误: " + error.getMessage()); handleError("播放错误: " + error.getMessage(), -1); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activitymain); // 初始化UI组件 initUIComponents(); // 获取启动参数 parseIntentParams(); // 初始化SDK initSDK(); // 参数校验 if (mDeviceSerial == null || mDeviceSerial.isEmpty()) { showErrorAndFinish("设备序列号不能为空"); return; } Log.d("MainActivity", "onCreate完成: isEzDevice=" + isEzDevice); } @SuppressLint("WrongViewCast") private void initUIComponents() { // 基础UI m_toolbar = findViewById(R.id.titlename); setSupportActionBar(m_toolbar); // 预览相关UI mPreviewSurface = findViewById(R.id.realplay_sv); mSurfaceHolder = mPreviewSurface.getHolder(); mSurfaceHolder.addCallback(this); mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT); mProgressBar = findViewById(R.id.liveProgressBar); mControlLayout = findViewById(R.id.rl_control); mRotateButton = findViewById(R.id.ib_rotate2); // 设置旋转按钮点击事件 mRotateButton.setOnClickListener(v -> changeScreen()); if (m_toolbar != null) { m_toolbar.setVisibility(View.GONE); } // 初始化控制按钮 initControlButtons(); Log.d("UI", "UI组件初始化完成"); } private void parseIntentParams() { // 获取Intent参数 Intent intent = getIntent(); isEzDevice = true; // 只支持萤石设备 mAccessToken = intent.getStringExtra("accessToken"); // 优先使用bundle Bundle bundle = intent.getExtras(); if (bundle != null) { mDeviceSerial = bundle.getString("devSn"); mVerifyCode = bundle.getString("verifyCode"); mCameraNo = bundle.getInt("cameraNo", 1); } // 兼容直接Extra方式 if (mDeviceSerial == null) mDeviceSerial = intent.getStringExtra("devSn"); if (mVerifyCode == null) mVerifyCode = intent.getStringExtra("verifyCode"); if (mCameraNo == 0) mCameraNo = intent.getIntExtra("cameraNo", 1); Log.d("Params", "设备序列号: " + mDeviceSerial + ", 通道号: " + mCameraNo); } private void initSDK() { try { // 使用反射检查初始化状态 boolean isInitialized = false; try { EZOpenSDK instance = EZOpenSDK.getInstance(); if (instance != null) { isInitialized = true; } } catch (Exception e) { isInitialized = false; } // 未初始化进行初始化 if (!isInitialized) { EZOpenSDK.initLib(getApplication(), mAppKey); Log.d("EZSDK", "萤石SDK初始化完成"); } // 设置AccessToken if (mAccessToken != null && !mAccessToken.isEmpty()) { EZOpenSDK.getInstance().setAccessToken(mAccessToken); Log.d("EZToken", "AccessToken设置成功"); } else { Log.w("EZToken", "AccessToken缺失!"); } } catch (Exception e) { Log.e("EZSDK", "萤石SDK初始化失败", e); handleError("萤石SDK初始化失败: " + e.getMessage(), -1); } } private void initControlButtons() { // 云台控制按钮 findViewById(R.id.ptz_top_btn).setOnClickListener(v -> controlPTZ("UP")); findViewById(R.id.ptz_bottom_btn).setOnClickListener(v -> controlPTZ("DOWN")); findViewById(R.id.ptz_left_btn).setOnClickListener(v -> controlPTZ("LEFT")); findViewById(R.id.ptz_right_btn).setOnClickListener(v -> controlPTZ("RIGHT")); // 变焦控制 findViewById(R.id.focus_add).setOnClickListener(v -> controlZoom("ZOOM_IN")); findViewById(R.id.foucus_reduce).setOnClickListener(v -> controlZoom("ZOOM_OUT")); // 水平布局控制按钮 findViewById(R.id.ptz_top_btn2).setOnClickListener(v -> controlPTZ("UP")); findViewById(R.id.ptz_bottom_btn2).setOnClickListener(v -> controlPTZ("DOWN")); findViewById(R.id.ptz_left_btn2).setOnClickListener(v -> controlPTZ("LEFT")); findViewById(R.id.ptz_right_btn2).setOnClickListener(v -> controlPTZ("RIGHT")); Log.d("Controls", "控制按钮初始化完成"); } @Override public void surfaceCreated(SurfaceHolder holder) { Log.d("Surface", "Surface created"); // 获取播放地址并开始播放 new Thread(this::fetchPlaybackUrl).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.d("Surface", "Surface changed: " + width + "x" + height); if (mExoPlayer != null) { mExoPlayer.setVideoSurfaceHolder(holder); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.d("Surface", "Surface destroyed"); stopPreview(); } // ======================== 播放地址获取与播放 ======================== private void fetchPlaybackUrl() { try { // 构建请求参数 JSONObject params = new JSONObject(); params.put("accessToken", mAccessToken); params.put("deviceSerial", mDeviceSerial); params.put("channelNo", mCameraNo); params.put("protocol", 2); // 使用HLS协议 if (mVerifyCode != null && !mVerifyCode.isEmpty()) { params.put("code", mVerifyCode); } params.put("expireTime", 7200); // 2小有效期 // 创建请求体 RequestBody body = RequestBody.create( MediaType.parse("application/json"), params.toString() ); // 创建请求 Request request = new Request.Builder() .url("https://open.ys7.com/api/lapp/v2/live/address/get") .post(body) .build(); // 执行请求 try (Response response = mHttpClient.newCall(request).execute()) { if (!response.isSuccessful()) { handleError("获取播放地址失败: " + response.code(), response.code()); return; } // 解析响应 String responseBody = response.body().string(); JSONObject json = new JSONObject(responseBody); if ("200".equals(json.getString("code"))) { JSONObject data = json.getJSONObject("data"); mPlaybackUrl = data.getString("url"); Log.d("PlaybackURL", "获取到播放地址: " + mPlaybackUrl); // 在主线程初始化播放器 runOnUiThread(this::initExoPlayer); } else { handleError("API错误: " + json.getString("msg"), json.getInt("code")); } } } catch (JSONException | IOException e) { Log.e("FetchURL", "获取播放地址异常", e); handleError("获取播放地址异常: " + e.getMessage(), -1); } } private void initExoPlayer() { // 释放现有播放器 if (mExoPlayer != null) { mExoPlayer.release(); } // 创建播放器 mExoPlayer = new ExoPlayer.Builder(this).build(); mExoPlayer.addListener(mPlayerListener); // 设置视频渲染器 mExoPlayer.setVideoSurfaceHolder(mSurfaceHolder); // 创建媒体源 DataSource.Factory dataSourceFactory = new DefaultHttpDataSource.Factory(); MediaSource mediaSource = new HlsMediaSource.Factory(dataSourceFactory) .createMediaSource(MediaItem.fromUri(Uri.parse(mPlaybackUrl))); // 准备播放 mExoPlayer.setMediaSource(mediaSource); mExoPlayer.prepare(); mExoPlayer.setPlayWhenReady(true); mProgressBar.setVisibility(View.VISIBLE); Log.d("ExoPlayer", "播放器初始化完成,开始播放"); } // ======================== 萤石云控制方法 ======================== private int mapDirection(String direction) { switch (direction) { default: return -1; } } private void controlPTZ(String direction) { int directionCode = mapDirection(direction); if (directionCode == -1) return; // 控制逻辑实现 } private void controlZoom(String command) { String direction = "ZOOM_IN".equals(command) ? "ZOOM_IN" : "ZOOM_OUT"; controlPTZ(direction); } // ======================== 通用功能方法 ======================== public void changeScreen(View view) { changeScreen(); } private void changeScreen() { if (mControlLayout.getVisibility() == View.VISIBLE) { mControlLayout.setVisibility(View.GONE); } else { mControlLayout.setVisibility(View.VISIBLE); } } private void handleError(String message, int errorCode) { String fullMessage = message + " (错误码: " + errorCode + ")"; // 萤石云特有错误码处理 switch (errorCode) { case 400001: fullMessage = "AccessToken无效"; break; case 400002: fullMessage = "设备不存在"; break; case 400007: fullMessage = "设备不在线"; break; case 400034: fullMessage = "验证码错误"; break; case 400035: fullMessage = "设备已被自己添加"; break; case 400036: fullMessage = "设备已被别人添加"; break; default: fullMessage = "萤石云错误: " + errorCode; } new AlertDialog.Builder(this) .setTitle("预览失败") .setMessage(fullMessage) .setPositiveButton("确定", (d, w) -> finish()) .setCancelable(false) .show(); } private void showErrorAndFinish(String message) { Toast.makeText(this, message, Toast.LENGTH_LONG).show(); new Handler().postDelayed(this::finish, 3000); } private void stopPreview() { if (mExoPlayer != null) { mExoPlayer.release(); mExoPlayer = null; Log.d("Preview", "预览已停止"); } } @Override protected void onDestroy() { super.onDestroy(); stopPreview(); Log.d("Lifecycle", "onDestroy"); } @Override protected void onPause() { super.onPause(); if (mExoPlayer != null) { mExoPlayer.setPlayWhenReady(false); Log.d("Lifecycle", "暂停播放"); } } @Override protected void onResume() { super.onResume(); if (mExoPlayer != null) { mExoPlayer.setPlayWhenReady(true); Log.d("Lifecycle", "恢复播放"); } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_main_opt, menu); return true; } }
06-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值