Android基础学习总结(十六)——基于ijkplayer封装支持简单界面UI定制的视频播放器

2023-11-09

前言

项目开发中遇到需要解析播放m3u8视频流的情况,但是原生的PlayerView非常慢,使用起来复杂,不适合上手,这里找到一款ijkplayer是Bilibili基于ffmpeg开发并开源的轻量级视频播放器,支持播放本地网络视频,也支持流媒体播放。支持Android&iOS。
这里感谢jjdxmashl基于ijkplayer封装了支持简单界面UI定制的视频播放器,操作简单实用,推荐大家使用。

简介

当前项目是基于ijkplayer项目进行的播放器界面UI封装。
是一个适用于 Android 的 RTMP 直播推流 SDK,可高度定制化和二次开发。特色是同时支持 H.264 软编/硬编和 AAC 软编/硬编。主要是支持RIMP、HLS、MP4、M4A等视频格式的播放。
作者项目地址:http://www.github.com/jjdxmashl/jjdxm_ijkplayer
作者简书地址:http://www.jianshu.com/p/6c938df18413

特性

  • 基于ijkplayer封装的视频播放器界面,支持 RTMP , HLS (http & https) , MP4,M4A 等;
  • 可根据需求去定制部分界面样式;
  • 常用的手势操作左边上下亮度,右边上下声音,左右滑动播放进度调整;
  • 支持多种分辨率流的切换播放;
  • 播放出错尝试重连;
  • 界面裁剪显示样式;

快速开始

step1:导入依赖

该项目已经打包到jcenter中心了,可以通过compile命令直接依赖,在主程序目录build.gradle中,添加以下代码:

compile ‘com.dou361.ijkplayer:jjdxm-ijkplayer:1.0.0

step2:简单的播放器实现

setContentView(R.layout.simple_player_view_player);
String url = "http://9890.vod.myqcloud.com/9890_9c1fa3e2aea011e59fc841df10c92278.f20.mp4";
player = new PlayerView(this)
        .setTitle("什么")
        .setScaleType(PlayStateParams.fitparent)
        .hideMenu(true)
        .forbidTouch(false)
        .showThumbnail(new OnShowThumbnailListener() {
            @Override
            public void onShowThumbnail(ImageView ivThumbnail) {
                Glide.with(mContext)
                        .load("http://pic2.nipic.com/20090413/406638_125424003_2.jpg")
                        .placeholder(R.color.cl_default)
                        .error(R.color.cl_error)
                        .into(ivThumbnail);
            }
        })
        .setPlaySource(url)
        .startPlay();

step3:多种不同的分辨率流的播放器实现

在布局中使用simple_player_view_player.xml布局

<include
    layout="@layout/simple_player_view_player"
    android:layout_width="match_parent"
    android:layout_height="180dp"/>

代码中创建一个播放器对象

/**播放资源*/
ist<VideoijkBean> list = new ArrayList<VideoijkBean>();
String url1 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f20.mp4";
String url2 = "http://9890.vod.myqcloud.com/9890_4e292f9a3dd011e6b4078980237cc3d3.f30.mp4";
VideoijkBean m1 = new VideoijkBean();
m1.setStream("标清");
m1.setUrl(url1);
VideoijkBean m2 = new VideoijkBean();
m2.setStream("高清");
m2.setUrl(url2);
list.add(m1);
list.add(m2);
/**播放器*/
player = new PlayerView(this)
            .setTitle("什么")
            .setScaleType(PlayStateParams.fitparent)
            .hideMenu(true)
            .forbidTouch(false)
            .showThumbnail(new OnShowThumbnailListener() {
                @Override
                public void onShowThumbnail(ImageView ivThumbnail) {
                    /**加载前显示的缩略图*/
                    Glide.with(mContext)
                            .load("http://pic2.nipic.com/20090413/406638_125424003_2.jpg")
                            .placeholder(R.color.cl_default)
                            .error(R.color.cl_error)
                            .into(ivThumbnail);
                }
            })
            .setPlaySource(list)
            .startPlay();

配置生命周期方法

为了让播放器同步Activity生命周期,建议以下方法都去配置,注释的代码,主要作用是播放时屏幕常亮和暂停其它媒体的播放。

@Override
protected void onPause() {
    super.onPause();
    if (player != null) {
        player.onPause();
    }
    /**demo的内容,恢复系统其它媒体的状态*/
    //MediaUtils.muteAudioFocus(mContext, true);
}

@Override
protected void onResume() {
    super.onResume();
    if (player != null) {
        player.onResume();
    }
    /**demo的内容,暂停系统其它媒体的状态*/
    MediaUtils.muteAudioFocus(mContext, false);
    /**demo的内容,激活设备常亮状态*/
    //if (wakeLock != null) {
    //    wakeLock.acquire();
    //}
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (player != null) {
        player.onDestroy();
    }
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (player != null) {
        player.onConfigurationChanged(newConfig);
    }
}

@Override
public void onBackPressed() {
    if (player != null && player.onBackPressed()) {
        return;
    }
    super.onBackPressed();
    /**demo的内容,恢复设备亮度状态*/
    //if (wakeLock != null) {
    //    wakeLock.release();
    //}
}

更多UI样式的设置

1.视频界面裁剪设置

可通过方法setScaleType(int type)去设置

  • PlayStateParams.fitParent:可能会剪裁,保持原视频的大小,显示在中心,当原视频的大小超过view的大小超过部分裁剪处理
  • PlayStateParams.fillParent:可能会剪裁,等比例放大视频,直到填满View为止,超过View的部分作裁剪处理
  • PlayStateParams.wrapcontent:将视频的内容完整居中显示,如果视频大于view,则按比例缩视频直到完全显示在view中
  • PlayStateParams.fitXY:不剪裁,非等比例拉伸画面填满整个View
  • PlayStateParams.f16_9:不剪裁,非等比例拉伸画面到16:9,并完全显示在View中
  • PlayStateParams.f4_3:不剪裁,非等比例拉伸画面到4:3,并完全显示在View中

2.播放器底部bar播放进度条样式定制

默认的进度样式是竖屏为上下样式,即进度条在播放时长的上面,横屏为左右样式,即进度条在播放时长的中间。样式定制主要是两个方法搭配使用toggleProcessDurationOrientation方法和setProcessDurationOrientation方法,横竖屏切换2中情况,和3种进度条样式

/**上下样式*/
PlayStateParams.PROCESS_PORTRAIT
/**左右样式*/
PlayStateParams.PROCESS_LANDSCAPE
/**中间两边样式*/
PlayStateParams.PROCESS_CENTER

总共有2的3次方中样式,下面只罗列几种样式
(1).横竖屏都为上下样式

player = new PlayerView(this) {
        @Override
        public PlayerView toggleProcessDurationOrientation() {
            return setProcessDurationOrientation(PlayStateParams.PROCESS_PORTRAIT);
        }
    }
            .setTitle("什么")
            .setProcessDurationOrientation(PlayStateParams.PROCESS_PORTRAIT)
            .setScaleType(PlayStateParams.fitparent)
            .forbidTouch(false)
            .hideCenterPlayer(true)
            .setPlaySource(list)
            .startPlay();

(2).横竖屏都为左右样式

player = new PlayerView(this) {
        @Override
        public PlayerView toggleProcessDurationOrientation() {
            return setProcessDurationOrientation(PlayStateParams.PROCESS_LANDSCAPE);
        }
    }
            .setTitle("什么")
            .setProcessDurationOrientation(PlayStateParams.PROCESS_LANDSCAPE)
            .setScaleType(PlayStateParams.fitparent)
            .forbidTouch(false)
            .hideCenterPlayer(true)
            .setPlaySource(list)
            .startPlay();

(3).横屏为上下样式竖屏为左右样式

player = new PlayerView(this) {
        @Override
        public PlayerView toggleProcessDurationOrientation() {
            return setProcessDurationOrientation(getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE?PlayStateParams.PROCESS_LANDSCAPE:PlayStateParams.PROCESS_PORTRAIT);
        }
    }
            .setTitle("什么")
            .setProcessDurationOrientation(PlayStateParams.PROCESS_LANDSCAPE)
            .setScaleType(PlayStateParams.fitparent)
            .forbidTouch(false)
            .hideCenterPlayer(true)
            .setPlaySource(list)
            .startPlay();

3.隐藏部分不想要的界面

//隐藏返回键,true隐藏,false为显示
PlayerView hideBack(boolean isHide)
//隐藏菜单键,true隐藏,false为显示
PlayerView hideMenu(boolean isHide)
//隐藏分辨率按钮,true隐藏,false为显示
PlayerView hideSteam(boolean isHide)
//隐藏旋转按钮,true隐藏,false为显示
PlayerView hideRotation(boolean isHide)
//隐藏全屏按钮,true隐藏,false为显示
PlayerView hideFullscreen(boolean isHide)
//隐藏中间播放按钮,ture为隐藏,false为不做隐藏处理,但不是显示
PlayerView hideCenterPlayer(boolean isHide)

4.视频移动流量是播放提醒

//设置2/3/4/5G和WiFi网络类型提示 true为进行2/3/4/5G网络类型提示 false 不进行网络类型提示
PlayerView setNetWorkTypeTie(boolean isGNetWork)

5.视频加载前显示缩略图

player.showThumbnail(new OnShowThumbnailListener() {
                @Override
                public void onShowThumbnail(ImageView ivThumbnail) {
                    /**加载前显示的缩略图*/
                    Glide.with(mContext)
                            .load("http://pic2.nipic.com/20090413/406638_125424003_2.jpg")
                            .placeholder(R.color.cl_default)
                            .error(R.color.cl_error)
                            .into(ivThumbnail);
                }
            })

6.默认显示上下操作栏bar

//设置是否禁止隐藏bar,true为一直显示,false为点击可以隐藏或显示
PlayerView setForbidHideControlPanl(boolean flag)

7.设置播放出错后尝试重连的方式和重连的时间

//设置自动重连的模式或者重连时间,isAuto true 出错重连,false出错不重连,connectTime重连的时间
setAutoReConnect(boolean isAuto, int connectTime)

8.视频界面的旋转

当前默认使用setPlayerRotation方法为90、270、0轮询切换,如果需要指定角度旋转可以使用setPlayerRotation方法

//旋转角度
PlayerView setPlayerRotation()
//旋转指定角度
PlayerView setPlayerRotation(int rotation)

自定义视频界面

可以复制以下布局内容到自己的项目中,注意已有的id不能修改或删除,可以增加view,可以对以下布局内容调整显示位置或者自行隐藏

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/app_video_box"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black"
    android:orientation="vertical">


    <com.dou361.ijkplayer.widget.IjkVideoView
        android:id="@+id/video_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout
        android:id="@+id/ll_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/black"
        android:orientation="vertical">

        <!-- 封面显示-->
        <ImageView
            android:id="@+id/iv_trumb"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitXY"
            android:visibility="visible"/>
    </LinearLayout>

    <!--重新播放-->
    <LinearLayout
        android:id="@+id/app_video_replay"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#33000000"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">
        <!-- 播放状态-->
        <TextView
            android:id="@+id/app_video_status_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/small_problem"
            android:textColor="@android:color/white"
            android:textSize="14dp"/>

        <ImageView
            android:id="@+id/app_video_replay_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="8dp"
            android:src="@drawable/simple_player_circle_outline_white_36dp"/>
    </LinearLayout>
    <!-- 网络提示-->
    <LinearLayout
        android:id="@+id/app_video_netTie"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#33000000"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="8dp"
            android:gravity="center"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:text="您正在使用移动网络播放视频\n可能产生较高流量费用"
            android:textColor="@android:color/white"/>

        <TextView
            android:id="@+id/app_video_netTie_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/simple_player_btn"
            android:gravity="center"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:text="继续"
            android:textColor="@android:color/white"/>
    </LinearLayout>

    <!--加载中-->
    <LinearLayout
        android:id="@+id/app_video_loading"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        android:visibility="gone">

        <ProgressBar
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:indeterminateBehavior="repeat"
            android:indeterminateOnly="true"/>
        <TextView
            android:id="@+id/app_video_speed"
            android:layout_width="wrap_content"
            android:layout_marginTop="4dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:visibility="gone"
            android:text="188Kb/s"
            android:textColor="@android:color/white"/>
    </LinearLayout>

    <!-- 中间触摸提示-->
    <include
        layout="@layout/simple_player_touch_gestures"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>

    <!-- 顶部栏-->
    <include layout="@layout/simple_player_topbar"/>
    <!-- 底部栏-->
    <include
        layout="@layout/simple_player_controlbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"/>

    <!--声音亮度控制-->
    <LinearLayout
        android:id="@+id/simple_player_settings_container"
        android:layout_width="250dp"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:background="#80000000"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:visibility="visible">

        <LinearLayout
            android:id="@+id/simple_player_volume_controller_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:src="@drawable/qcloud_player_icon_audio_vol_mute"/>

            <SeekBar
                android:id="@+id/simple_player_volume_controller"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="150dp"
                android:layout_height="wrap_content"/>

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:src="@drawable/qcloud_player_icon_audio_vol"/>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/simple_player_brightness_controller_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:padding="5dp"
                android:src="@drawable/qcloud_player_icon_brightness"/>

            <SeekBar
                android:id="@+id/simple_player_brightness_controller"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="150dp"
                android:layout_height="wrap_content"/>

            <ImageView
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:src="@drawable/qcloud_player_icon_brightness"/>
        </LinearLayout>

    </LinearLayout>


    <!--分辨率选择-->
    <LinearLayout
        android:id="@+id/simple_player_select_stream_container"
        android:layout_width="150dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:background="#80000000"
        android:gravity="center_vertical"
        android:visibility="gone">

        <ListView
            android:id="@+id/simple_player_select_streams_list"
            android:layout_width="150dp"
            android:layout_height="wrap_content"/>
    </LinearLayout>


    <ImageView
        android:id="@+id/play_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginTop="8dp"
        android:src="@drawable/simple_player_center_play"/>

</RelativeLayout>

播放器PlayerView对象

PlayerView(Activity activity)

//生命周期方法回调
PlayerView onPause()
PlayerView onResume()
PlayerView onDestroy()
PlayerView onConfigurationChanged(final Configuration newConfig)
boolean onBackPressed()
//显示缩略图
PlayerView showThumbnail(OnShowThumbnailListener onShowThumbnailListener)
//设置播放信息监听回调
PlayerView setOnInfoListener(IMediaPlayer.OnInfoListener onInfoListener)
//设置播放器中的返回键监听
PlayerView setPlayerBackListener(OnPlayerBackListener listener)
//设置控制面板显示隐藏监听
PlayerView setOnControlPanelVisibilityChangListenter(OnControlPanelVisibilityChangeListener listener)
//百分比显示切换
PlayerView toggleAspectRatio()
//设置播放区域拉伸类型
PlayerView setScaleType(int showType)
//旋转角度
PlayerView setPlayerRotation()
//旋转指定角度
PlayerView setPlayerRotation(int rotation)
//设置播放地址包括视频清晰度列表对应地址列表
PlayerView setPlaySource(List<VideoijkBean> list)
//设置播放地址单个视频VideoijkBean
PlayerView setPlaySource(VideoijkBean videoijkBean)
//设置播放地址单个视频地址时带流名称
PlayerView setPlaySource(String stream, String url)
//设置播放地址单个视频地址时
PlayerView setPlaySource(String url)
//自动播放
PlayerView autoPlay(String path)
//开始播放
PlayerView startPlay()
//设置视频名称
PlayerView setTitle(String title)
//选择要播放的流
PlayerView switchStream(int index)
//暂停播放
PlayerView pausePlay()
//停止播放
PlayerView stopPlay()
//设置播放位置
PlayerView seekTo(int playtime)
//获取当前播放位置
int getCurrentPosition()
//获取视频播放总时长
long getDuration()
//设置2/3/4/5G和WiFi网络类型提示 true为进行2/3/4/5G网络类型提示 false 不进行网络类型提示
PlayerView setNetWorkTypeTie(boolean isGNetWork)
//是否仅仅为全屏
PlayerView setOnlyFullScreen(boolean isFull)
//设置是否禁止双击
PlayerView setForbidDoulbeUp(boolean flag)
//设置是否禁止隐藏bar
PlayerView setForbidHideControlPanl(boolean flag)
//当前播放的是否是直播
boolean isLive()
//是否禁止触摸
PlayerView forbidTouch(boolean forbidTouch)
//隐藏所有状态界面
PlayerView hideAllUI()
获取顶部控制barview
View getTopBarView()
//获取底部控制barview
View getBottonBarView()
//获取旋转view
ImageView getRationView()
//获取返回view
ImageView getBackView()
//获取菜单view
ImageView getMenuView()
//获取全屏按钮view
ImageView getFullScreenView()
//获取底部bar的播放view
ImageView getBarPlayerView()
//获取中间的播放view
ImageView getPlayerView()
//隐藏返回键,true隐藏,false为显示
PlayerView hideBack(boolean isHide)
//隐藏菜单键,true隐藏,false为显示
PlayerView hideMenu(boolean isHide)
//隐藏分辨率按钮,true隐藏,false为显示
PlayerView hideSteam(boolean isHide)
//隐藏旋转按钮,true隐藏,false为显示
PlayerView hideRotation(boolean isHide)
//隐藏全屏按钮,true隐藏,false为显示
PlayerView hideFullscreen(boolean isHide)
//隐藏中间播放按钮,ture为隐藏,false为不做隐藏处理,但不是显示
PlayerView hideCenterPlayer(boolean isHide)
//显示或隐藏操作面板
PlayerView operatorPanl()
//全屏切换
PlayerView toggleFullScreen()
//设置自动重连的模式或者重连时间,isAuto true 出错重连,false出错不重连,connectTime重连的时间
setAutoReConnect(boolean isAuto, int connectTime)
//进度条和时长显示的方向切换
PlayerView toggleProcessDurationOrientation()
//设置进度条和时长显示的方向,默认为上下显示,PlayStateParams.PROCESS_PORTRAIT为上下显示PlayStateParams.PROCESS_LANDSCAPE为左右显示PlayStateParams.PROCESS_CENTER为中间两边样式
setProcessDurationOrientation(int portrait)
//显示菜单设置
showMenu()
//获取界面方向
int getScreenOrientation()
//显示加载网速
PlayerView setShowSpeed(boolean isShow)

ijkplayer封装的视频播放信息返回码监听

通过setOnInfoListener去监听

/*
 * Do not change these values without updating their counterparts in native
 */
int MEDIA_INFO_UNKNOWN = 1;//未知信息
int MEDIA_INFO_STARTED_AS_NEXT = 2;//播放下一条
int MEDIA_INFO_VIDEO_RENDERING_START = 3;//视频开始整备中
int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;//视频日志跟踪
int MEDIA_INFO_BUFFERING_START = 701;//开始缓冲中
int MEDIA_INFO_BUFFERING_END = 702;//缓冲结束
int MEDIA_INFO_NETWORK_BANDWIDTH = 703;//网络带宽,网速方面
int MEDIA_INFO_BAD_INTERLEAVING = 800;//
int MEDIA_INFO_NOT_SEEKABLE = 801;//不可设置播放位置,直播方面
int MEDIA_INFO_METADATA_UPDATE = 802;//
int MEDIA_INFO_TIMED_TEXT_ERROR = 900;
int MEDIA_INFO_UNSUPPORTED_SUBTITLE = 901;//不支持字幕
int MEDIA_INFO_SUBTITLE_TIMED_OUT = 902;//字幕超时

int MEDIA_INFO_VIDEO_INTERRUPT= -10000;//数据连接中断
int MEDIA_INFO_VIDEO_ROTATION_CHANGED = 10001;//视频方向改变
int MEDIA_INFO_AUDIO_RENDERING_START = 10002;//音频开始整备中

int MEDIA_ERROR_UNKNOWN = 1;//未知错误
int MEDIA_ERROR_SERVER_DIED = 100;//服务挂掉
int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;//数据错误没有有效的回收
int MEDIA_ERROR_IO = -1004;//IO错误
int MEDIA_ERROR_MALFORMED = -1007;
int MEDIA_ERROR_UNSUPPORTED = -1010;//数据不支持
int MEDIA_ERROR_TIMED_OUT = -110;//数据超时

参考自http://blog.csdn.net/jiujiedexiaoming/article/details/52319676

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android基础学习总结(十六)——基于ijkplayer封装支持简单界面UI定制的视频播放器 的相关文章

  • Android 布局不需要的填充

    所以我有这个布局文件 如下 正如您所看到的 没有填充或边距 dimen xml 文件也没有任何填充 边距 最后 我根本不以编程方式更改布局
  • PHP服务器端IAB验证openssl_verify总是返回0

    我使用以下函数 服务器端 php 来验证 IAB v3 事务 我从 Android 应用程序传递过来 Override protected void onActivityResult int requestCode int resultCo
  • 如何使用gradle这样的格式更改apk名称?

    当我使用 gradle 构建应用程序时 我想将 app release apk 文件名更改为如下所示 format appname of package name V version code yyMMdd R T explain appn
  • 居中复选框视图

    如果除了 或代替 复选框之外 您还对单选按钮感兴趣 请参阅this https stackoverflow com questions 16701806 centering views 2而是提问 尽管存在
  • Android平台源码中哪里可以找到版本信息

    Android 平台源文件中的版本信息在哪里找到 我尝试查找 设置 gt gt 中列出的有关手机的一些信息 显示的一些信息包括固件版本 模块编号 基带版本 内核版本 你可以给它办理登机手续platform build core versio
  • 删除 json 对象字符串中的“\”

    如何删除下面字符串中的特殊字符 String x message content toom recipients id 1000001865 room subject room 我使用了 x replaceAll 但它不起作用 您必须转义正
  • Android 从键盘读取

    我的登录屏幕根本没有文本字段 当用户使用 RFID 扫描仪扫描他的 id 令牌时 我会得到一个 8 个字符长的字符串 其原理与使用键盘相同 只是更快 我希望我的登录活动在用户扫描其令牌时而不是之前执行 有一个聪明的方法来实现这个吗 我不能有
  • Android/Java 创建辅助类来创建图表

    Goal 创建用于图形生成的辅助类 背景 我有 3 个片段 每个片段收集一些传感器数据 加速度计 陀螺仪 旋转 并使用 GraphView 绘制图表 以下是其中一个片段的代码 该代码当前工作正常 public class Gyroscope
  • 调试 Java InterruptedException,即查找原因

    在调试Android应用程序时 有时中断异常发生并使应用程序崩溃 我已经能够在默认异常处理程序上设置断点 但调用堆栈不提供信息 at java util concurrent locks AbstractQueuedSynchronizer
  • 将 firebase auth 与 google app engine 云端点集成

    有人可以指定 使用一些示例代码 如何验证谷歌云端点中的 firebase 令牌吗 最近提出的问题根本没有澄清 如何将 Firebase 身份验证与 Google 应用引擎端点集成 https stackoverflow com questi
  • Android 中带有透明背景的 ImageButton [重复]

    这个问题在这里已经有答案了 我已经按照这篇文章在android中制作ImageButton 安卓图像按钮 https stackoverflow com questions 2283444 android image button 图像出现
  • Proguard - 找不到任何超级类

    我收到此错误 Unexpected error while performing partial evaluation Class org apache log4j chainsaw Main Method
  • 以编程方式应用样式资源

    我没有找到一种以编程方式做到这一点的方法 所以我在这里发布这个问题 我也没有找到与此相关的任何问题 我有一个资源样式 在 res values styles xml 中定义 我想做的是使用 java 将这种样式应用到我正在操作的 View
  • 如何从webkit浏览器中检测Android版本和品牌?

    如何通过webkit浏览器检测Android版本和品牌 可靠吗 我相信你可以检查用户代理 但是 我认为它不安全 因为有很多方法可以用来欺骗用户代理 在谷歌上搜索这个问题给了我们很多答案 它甚至可以在默认浏览器上运行 您只需输入 about
  • Android 发布到 facebook 墙,stream.publish 几天来就中断了

    我有很多使用 FB android sdk 发布的应用程序 github com facebook facebook android sdk 我所有使用 FB 的应用程序几天后就停止工作了 这必然是 FB 方面的更改或错误 因为我的应用程序
  • Android - 正确使用 invalidateOptionsMenu()

    我一直在寻找很多invalidateOptionsMenu 我知道它的作用 但我想不出这种方法在现实生活中有用的任何例子 我的意思是 例如 假设我们要添加一个新的MenuItem to our ActionBar 我们可以简单地获取菜单on
  • 使用 Glide 库设置图像加载完成后进度条的可见性

    您好 我想要一个图像进度条 该进度条将在图像加载时显示 但当图像加载完成时 我想将其设置为消失 早些时候我为此使用了毕加索库 但我不知道如何将它与 Glide 库一起使用 我知道有一些资源就绪功能 但我不知道如何使用它 谁能帮我 毕加索图书
  • 当我使用 ListView 时,ListTile OnTap 正在工作。但是当我使用 ListWheelScrollView 时它不起作用

    当我使用 ListView 时 ListTile OnTap 正在工作 但是当我使用 ListWheelScrollView 时它不起作用 我的意思是它不会被窃听 观点发生变化 但我似乎无法点击它 我在很多地方和链接中寻找解决方案 但仍然找
  • Android中绑定适配器有什么用?

    我一直在阅读有关Android中绑定适配器的文章 但我似乎不明白它 何时使用绑定适配器 有人可以用一个简单的例子来解释它吗 我读过的一篇文章在主活动中有一个绑定适配器 绑定适配器有一个参数 toastMessage 显然 只要 toastM
  • 进程被杀死后不会调用 onActivityResult

    我有一个主要活动 Main 和另一个活动 Sub 由 Main 调用 startActivityForResult new Intent this SubActivity class 25 当我在 Sub 时 我终止该进程 使用任务管理器或

随机推荐

  • 解决 Fedora 下部分网页不能正常打开的问题(Linux 通用)

    使用命令 ifconfig 可以查看本地的网卡信息 ifconfig a 一般以wlp开头的为无线网卡 用 ifconfig XXXX 网卡名可以单独查看某一个网卡的信息 如下所示 wlp0s20f3 flags 4163
  • 异常的笔记

    异常 很重要 有利于我们平时处理问题 异常就是代表程序出现了问题 常见的异常比如说 数组越界 除法除0 异常的体系是什么 java lang Throwable Error Exception RuntimeException 其他异常 E
  • UE4 Niagara粒子系统基础笔记

    目录 Niagara基础概念 Niagara官方建议 Niagara堆栈面板 Niagara渲染模式 材质 Niagara和蓝图 Niagara常用模块 Niagara常用技巧 Niagara ModuleScript Niagara基础概
  • RTP和RTCP详解

    1 RTP和RTCP详解 文章目录 1 RTP和RTCP详解 1 1 概述 1 2 RTP协议详解 1 3 RTCP协议详解 1 1 概述 在流媒体相关的领域 我们进场会看到RTP RTCP 其用于流式传输的最常见的码流传输协议 位于传输层
  • Python单元测试:pytest

    pytest默认使用的是main system packages 如果需要在虚拟环境中运行 需要运行 python m pytest test py 如果需要打印中间结果 pytest test py s
  • 跨时钟域电路设计——多bit信号&FIFO

    多个bit信号的跨时钟域仅仅通过简单的同步器同步时不安全的 如下图 虽然信号都同步到目的时钟域 可完成的功能却与设计的初衷不相符 解决方案之一为对信号进行格雷码编码 但此方案只适用于连续变化的信号 另一种方案为增加新的控制信号en 确保传输
  • 机器学习和深度学习引用量最高的20篇论文(2014-2017)

    机器学习和深度学习的研究进展正深刻变革着人类的技术 本文列出了自 2014 年以来这两个领域发表的最重要 被引用次数最多 的 20 篇科学论文 以飨读者 机器学习 尤其是其子领域深度学习 在近些年来取得了许多惊人的进展 重要的研究论文可能带
  • 1200兆路由器网速_家庭网络配置问题案例:六类网线上网速度只有100兆

    有这样一个案例 家中布置了一根6类网线 8芯中间带个塑料十字的双绞线 网线约10米长 全部为埋地管道暗线 水晶头为568B线序 电脑插也为6类 西门子 568B线序接法 现在出现一个问题 就是网线一个连接移动光猫 为路由器模式 千兆口 然后
  • mac-右键-用VSCode打开

    1 点击访达 搜索自动操作 2 选择快速操作 3 执行shell脚本 替换代码如下 for f in do open a Visual Studio Code f done command s保存会出现一个弹框 保存为 用VSCode打开
  • IDEA2021.2创建java web项目(很详细,手把手创建)

    该文章适合人群 初学java web 不用maven或者gradle创建java web项目 忘记了怎么创建web项目 错误示范 上来直接创建java ee 项目 这样创建出来的项目有Maven或者Gradle包管理 正确演示 1 创建项目
  • “威胁”员工全来上班后,马斯克“尴尬”了:车没地停、工位不够坐、Wi-Fi 还太差

    点击蓝色 程序员黄小斜 关注我哟 加个 星标 每天和你一起多进步一点点 整理 郑丽媛 出品 程序人生 ID coder life 每一个特斯拉员工每周都要在办公室工作 40 个小时 如果你不来 那么我们就认为你辞职了 在马斯克 蛮横 地放出
  • python机器学习——NLTK及分析文本数据(自然语言处理基础)

    NLTK NLTK Natural Language Toolkit 自然语言处理工具包 在NLP 自然语言处理 领域中 最常使用的一个Python库 自带语料库 词性分类库 自带分类 分词功能 NLTK安装 安装 pip install
  • OpenCart 常见错误解决

    1 GC 报错 错误内容 opencart SessionHandler gc ps files cleanup dir opendir var lib php5 failed Permission denied 解决方法 更改 php i
  • 【论文记录】Boosting Detection in Crowd Analysis via Underutilized Output Features

    Boosting Detection in Crowd Analysis via Underutilized Output Features Abstract Crowd Hat使用一种混合的2D 1D压缩技术进行细化空间特征与获取特定人群
  • k8s删除pod镜像没响应marking for deletion pod TaintManagerEviction

    使用命令强制删除 Pod的状态为 Marking for deletion 表示该Pod正在被标记为待删除状态 但实际上并没有被删除 这可能是因为以下原因之一 删除操作被阻塞 可能是由于某些资源或容器正在使用该Pod 导致删除操作被阻塞 您
  • Python报错:module 'scipy' has no attribute 'xxx'

    首先看使用的函数在不在这几个当中 以 interpolate 为例 scipy 将 interpolate 单独定义为一个小子库 所以调用的时候不能单独写 import scipy 而是要写成 import scipy interpolat
  • 路由器打印机服务器系统,路由器怎么设置打印机服务器

    路由器怎么设置打印机服务器 内容精选 换一换 CDC Change Data Capture 即数据变更抓取 通过为源端数据源开启CDC ROMA Connect可实现数据源的实时数据同步以及数据表的物理删除同步 ROMA Connect支
  • DS排序--希尔排序

    目录 题目描述 思路分析 AC代码 题目描述 给出一个数据序列 使用希尔排序算法进行降序排序 间隔gap使用序列长度循环除2直到1 输入 第一行输入t 表示有t个测试示例 第二行输入n 表示第一个示例有n个数据 n gt 1 第三行输入n个
  • PowerBUS 双总线收发器

    随着智能化的发展 人的需求变高 在一个环境内 如果子设备较多 距离适中 大多数是布置485总线加电源地需要4根线 这样就会导致走线复杂 线的成本也较高 如果用BLE或者wifi无线连接时也需要电源地2根线 成本更高 而powerbus双总线
  • Android基础学习总结(十六)——基于ijkplayer封装支持简单界面UI定制的视频播放器

    前言 项目开发中遇到需要解析播放m3u8视频流的情况 但是原生的PlayerView非常慢 使用起来复杂 不适合上手 这里找到一款ijkplayer是Bilibili基于ffmpeg开发并开源的轻量级视频播放器 支持播放本地网络视频 也支持