如果您想了解Android实现视频字幕Subtitle和横竖屏切换示例的相关知识,那么本文是一篇不可错过的文章,我们将对android视频播放横竖屏切换进行全面详尽的解释,并且为您提供关于Androi
如果您想了解Android 实现视频字幕Subtitle和横竖屏切换示例的相关知识,那么本文是一篇不可错过的文章,我们将对android视频播放横竖屏切换进行全面详尽的解释,并且为您提供关于Android Activity 横竖屏切换的生命周期、Android Activity横竖屏切换生命周期详解、android 中禁止横竖屏切换、Android 如何只禁止某一个Layout在横竖屏切换的时候重新加载的有价值的信息。
本文目录一览:- Android 实现视频字幕Subtitle和横竖屏切换示例(android视频播放横竖屏切换)
- Android Activity 横竖屏切换的生命周期
- Android Activity横竖屏切换生命周期详解
- android 中禁止横竖屏切换
- Android 如何只禁止某一个Layout在横竖屏切换的时候重新加载
Android 实现视频字幕Subtitle和横竖屏切换示例(android视频播放横竖屏切换)
系统自带的VideoView有些视频格式不支持,那么我们可以用第三方实现的VideoView替代系统的来播放视频,比较流行的有ijkplayer、vitamio。
最近有个需求就是需要给视频添加字幕,其实也挺简单的。字幕比较常用的格式是srt,实际它就是文本,把它解析出来,然后根据时间再展示就OK。还有就是实现了即使旋转按钮关闭,根据方向感应器也能做到横竖屏切换。
本文用的是系统VideoView,然后播放sd卡中的视频来作为演示(源码中带有f2.mp4和f2.srt,运行时拷贝到sd卡就行)。下面简单介绍一下源码:
MainActivity包括显示字幕和如何实现横竖屏如何切换:
public class SubtitleActivity extends Activity implements View.OnClickListener,OnTouchListener{ private VideoView videoView ; TextView tvSrt,mCurrentTime,mTotalTime,resolution_switch,mediacontroller_file_name; ImageView mediacontroller_play_pause,switch_screen; private SeekBar progress_seekbar; private AudioManager mAM; private long totalDuration; private boolean mShowing = true,mDragging,isResolution; private static final int PARSE_SRT = 0; private static final int FADE_OUT = 1; private static final int SHOW_PROGRESS = 2; private static final int CHANGE_VIDEOVIEW_BG = 3; private static final int SCREEN_ORIENTATION_USER = 4; private static final int sDefaultTimeout = 3000; private RelativeLayout videoview_layout,mMediaController; private ListView resolution_listview; private boolean isPortraint = true; private static int LockScreen = -1;// 用于记录是否关闭屏幕旋转,0为关闭1为开启 private int screenWidth,videoViewHeight; List<VideoPathObject> videopathList=new ArrayList<VideoPathObject>(); Handler mHandler=new Handler(){ public void handleMessage(Message msg){ long pos; switch (msg.what) { case PARSE_SRT: SrtParser.showSRT(videoView,tvSrt) ; //每隔500ms执行一次showSRT(),根据时间匹配显示哪句字幕 mHandler.sendEmptyMessageDelayed(0,500); break; case FADE_OUT: showOrHideController(); break; case SHOW_PROGRESS: pos = setControllerProgress(); if (!mDragging && mShowing) { msg = obtainMessage(SHOW_PROGRESS); sendMessageDelayed(msg,1000 - (pos % 1000)); } break; case CHANGE_VIDEOVIEW_BG: videoView.setBackgroundColor(0x00000000); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_subtitle); videoView = (VideoView)this.findViewById(R.id.videoView ); mAM = (AudioManager) getSystemService(Context.AUdio_SERVICE); screenWidth = APPApplication.screenWidth; videoViewHeight = screenWidth * 9 / 16; tvSrt = (TextView)findViewById(R.id.srt);//项目中显示字幕的控件 mediacontroller_file_name= (TextView)findViewById(R.id.mediacontroller_file_name); // String[]splitStr=Constant.videoUrl1.split("/"); // mediacontroller_file_name.setText(splitStr[splitStr.length-1]); mTotalTime = (TextView) findViewById(R.id.mediacontroller_time_total); mCurrentTime = (TextView) findViewById(R.id.mediacontroller_time_current); resolution_switch = (TextView) findViewById(R.id.resolution_switch); mediacontroller_play_pause = (ImageView) findViewById(R.id.mediacontroller_play_pause); switch_screen = (ImageView) findViewById(R.id.switch_screen); videoview_layout = (RelativeLayout) findViewById(R.id.videoview_layout); mediacontroller_play_pause.setonClickListener(this); progress_seekbar = (SeekBar) findViewById(R.id.mediacontroller_seekbar); videoview_layout = (RelativeLayout) findViewById(R.id.videoview_layout); mMediaController = (RelativeLayout) findViewById(R.id.media_controller); resolution_listview = (ListView) findViewById(R.id.resolution_listview); resolution_switch.setonClickListener(this); videoView.setonTouchListener(this); progress_seekbar.setonSeekBarchangelistener(mSeekListener); LayoutParams params = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT,videoViewHeight); videoview_layout.setLayoutParams(params); try { // 1代表开启自动旋转true,0代表未开启自动旋转false // Settings.System.getInt(mContext.getContentResolver(),Settings.System.ACCELEROMETER_ROTATION,0); LockScreen = Settings.System.getInt(getContentResolver(),Settings.System.ACCELEROMETER_ROTATION); } catch (SettingNotFoundException e) { // Todo Auto-generated catch block e.printstacktrace(); } // String rawUri = "android.resource://" + getPackageName() + "/" + R.raw.renwei; Uri uri = Uri.parse(Constant.videoUrl1); //设置视频控制器 // videoView.setMediaController(new MediaController(this)); //播放完成回调 videoView.setonCompletionListener( new MyPlayerOnCompletionListener()); videoView.setonPreparedListener(new OnPreparedListener() { //@Override public void onPrepared(MediaPlayer mp) { totalDuration=videoView.getDuration(); if (mTotalTime != null) mTotalTime.setText("/"+generateTime(totalDuration)); } }); //设置视频路径 videoView.setVideoURI(uri); //开始播放视频 videoView.start(); SrtParser.parseSrt(this); SrtParser.showSRT(videoView,tvSrt) ; mHandler.sendEmptyMessageDelayed(0,500); initVideoResolution(); } private void initVideoResolution(){ VideoPathObject object1=new VideoPathObject(); object1.videoStatus="超清"; videopathList.add(object1); VideoPathObject object2=new VideoPathObject(); object2.videoStatus="高清"; videopathList.add(object2); VideoPathObject object3=new VideoPathObject(); object3.videoStatus="标清"; videopathList.add(object3); switchResolution(videopathList); } class MyPlayerOnCompletionListener implements MediaPlayer.OnCompletionListener { @Override public void onCompletion(MediaPlayer mp) { Toast.makeText( SubtitleActivity.this,"播放完成了",Toast.LENGTH_SHORT).show(); } } private OnSeekBarchangelistener mSeekListener = new OnSeekBarchangelistener() { public void onStartTrackingTouch(SeekBar bar) { mDragging = true; mHandler.removeMessages(SHOW_PROGRESS); mAM.setStreamMute(AudioManager.STREAM_MUSIC,true); } public void onProgressChanged(SeekBar bar,int progress,boolean fromuser) { if (!fromuser) return; int newposition = (int)(totalDuration * progress) / 1000; String time = generateTime(newposition); videoView.seekTo(newposition); mCurrentTime.setText(time); } public void onStopTrackingTouch(SeekBar bar) { videoView.seekTo(((int)totalDuration * bar.getProgress()) / 1000); hideMediaController(sDefaultTimeout); mAM.setStreamMute(AudioManager.STREAM_MUSIC,false); mDragging = false; mHandler.sendEmptyMessageDelayed(SHOW_PROGRESS,1000); } }; private void switchResolution(final List<VideoPathObject> videopathList) { resolution_switch .setText(videopathList.get(videopathList.size() - 1).videoStatus); mediacontroller_play_pause.setimageResource(R.drawable.player_play); final ResolutionAdapter adapter = new ResolutionAdapter(videopathList,SubtitleActivity.this); resolution_listview.setAdapter(adapter); resolution_listview .setonItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0,View arg1,int position,long arg3) { // Todo Auto-generated method stub // // currentPosition = videoView.getCurrentPosition(); // currentPosition = videoView.getCurrentPosition(); // Log.d("gaolei","currentPosition---------1------" // + currentPosition); VideoPathObject pathObject = videopathList .get(position); //// playVideo(pathObject.videoUrl); // adapter.changePosition(position); resolution_switch.setText(pathObject.videoStatus); resolution_listview.setVisibility(View.GONE); } }); } public void showOrHideController() { if (mShowing) { mHandler.removeMessages(SHOW_PROGRESS); mHandler.removeMessages(FADE_OUT); mMediaController.setVisibility(View.GONE); resolution_listview.setVisibility(View.GONE); mShowing = false; } else { mHandler.sendEmptyMessage(SHOW_PROGRESS); mMediaController.setVisibility(View.VISIBLE); hideMediaController(sDefaultTimeout); mShowing = true; } } public void hideMediaController(int sDefaultTimeout) { mHandler.sendEmptyMessageDelayed(FADE_OUT,sDefaultTimeout); } private long setControllerProgress() { if (videoView == null || mDragging) return 0; int position = videoView.getCurrentPosition(); if (progress_seekbar != null) { if (totalDuration > 0) { long pos = 1000L * position / totalDuration; // Log.d("gaolei","progress--------------" + pos); progress_seekbar.setProgress((int) pos); } int percent = videoView.getBufferPercentage(); progress_seekbar.setSecondaryProgress(percent * 10); } if (mCurrentTime != null) mCurrentTime.setText(generateTime(position)); return position; } private static String generateTime(long position) { int totalSeconds = (int) (position / 1000); int seconds = totalSeconds % 60; int minutes = (totalSeconds / 60) % 60; int hours = totalSeconds / 3600; if (hours > 0) { return String.format(Locale.US,"%02d:%02d:%02d",hours,minutes,seconds).toString(); } else { return String.format(Locale.US,"%02d:%02d",seconds) .toString(); } } private void updatePausePlay() { if (videoView.isPlaying()) { videoView.pause(); mediacontroller_play_pause .setimageResource(R.drawable.player_pause); } else { videoView.start(); mediacontroller_play_pause.setimageResource(R.drawable.player_play); } } public void showResolution(View view) { if (!isResolution) { resolution_listview.setVisibility(View.VISIBLE); isResolution = true; } else { resolution_listview.setVisibility(View.GONE); isResolution = false; } } public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { changetoFullScreen(); Log.d("gaolei","ORIENTATION_LANDSCAPE-------------"); } if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { changetoSmallScreen(); Log.d("gaolei","ORIENTATION_PORTRAIT-------------"); } } public void switchScreen(View view) { if (isPortraint) { handToFullScreen(); } else { handToSmallScreen(); } } public void handToSmallScreen() { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT); changetoSmallScreen(); /** * 这里点击按钮转屏,用户5秒内不转屏幕,将自动识别当前屏幕方向 */ autoSwitchScreenorientation(); } public void handToFullScreen() { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE); changetoFullScreen(); autoSwitchScreenorientation(); } private void changetoFullScreen() { isPortraint = false; LayoutParams params = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT,APPApplication.screenWidth); videoview_layout.setLayoutParams(params); videoView.setLayoutParams(params); WindowManager.LayoutParams windowparams = getwindow().getAttributes(); windowparams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; getwindow().setAttributes(windowparams); getwindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); switch_screen.setimageResource(R.drawable.player_switch_small); } private void changetoSmallScreen() { isPortraint = true; LayoutParams params = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT,videoViewHeight); videoview_layout.setLayoutParams(params); videoView.setLayoutParams(params); WindowManager.LayoutParams windowparams = getwindow().getAttributes(); windowparams.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); getwindow().setAttributes(windowparams); getwindow() .clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); switch_screen.setimageResource(R.drawable.player_switch_big); } public void autoSwitchScreenorientation() { // 手动旋转屏幕,5s后会执行感应的方向 new Timer().schedule(new TimerTask() { @Override public void run() { // Todo Auto-generated method stub setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); Log.d("gaolei","SCREEN_ORIENTATION_FULL_SENSOR"); } },5000); } @Override public boolean onTouch(View v,MotionEvent event) { // Todo Auto-generated method stub switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { showOrHideController(); break; } } return false; } @Override public void onClick(View view) { // Todo Auto-generated method stub switch(view.getId()){ case R.id.mediacontroller_play_pause: Log.d("gaolei","mediacontroller_play_pause"); updatePausePlay(); break; case R.id.resolution_switch: resolution_listview.setVisibility(View.VISIBLE); break; } } public void jumpToMain(View view){ startActivity(new Intent(this,MainActivity.class)); } public void onRestart(){ super.onRestart(); videoView.start(); mediacontroller_play_pause.setimageResource(R.drawable.player_play); } public void onStop(){ super.onStop(); videoView.pause(); mediacontroller_play_pause.setimageResource(R.drawable.player_pause); } }
SrtParser就是解析字幕文件的算法:
public class SrtParser { public static ArrayList<SRT>srtList; public static int lastEndTime; /** * 解析SRT字幕文件 * 字幕路径 */ public static void parseSrt(Context context) { InputStream inputStream = null; try { // inputStream=context.getResources().openRawResource(R.raw.renwei2); inputStream = new FileInputStream(Constant.srtUrl1); // Todo Auto-generated catch block BufferedReader br = new BufferedReader(new InputStreamReader( inputStream,"GB2312")); String line = null; srtList = new ArrayList<SRT>(); StringBuffer sb = new StringBuffer(); while ((line = br.readLine()) != null) { // Log.d("gaolei","br.readLine()-----------"+br.readLine()); if (!line.equals("")) { Log.d("gaolei","line-------------------"+ line); sb.append(line).append("@"); continue; } Log.d("gaolei","sb.toString()-----------"+sb.toString()); String[] parseStrs = sb.toString().split("@"); // 该if为了适应一开始就有空行以及其他不符格式的空行情况 if (parseStrs.length < 3) { sb.delete(0,sb.length());// 清空,否则影响下一个字幕元素的解析</i> continue; } SRT srt = new SRT(); // 解析开始和结束时间 String timetotime = parseStrs[1]; int begin_hour = Integer.parseInt(timetotime.substring(0,2)); int begin_mintue = Integer.parseInt(timetotime.substring(3,5)); int begin_scend = Integer.parseInt(timetotime.substring(6,8)); int begin_milli = Integer.parseInt(timetotime.substring(9,12)); int beginTime = (begin_hour * 3600 + begin_mintue * 60 + begin_scend) * 1000 + begin_milli; int end_hour = Integer.parseInt(timetotime.substring(17,19)); int end_mintue = Integer.parseInt(timetotime.substring(20,22)); int end_scend = Integer.parseInt(timetotime.substring(23,25)); int end_milli = Integer.parseInt(timetotime.substring(26,29)); int endTime = (end_hour * 3600 + end_mintue * 60 + end_scend) * 1000 + end_milli; System.out.println("开始:" + begin_hour + ":" + begin_mintue + ":" + begin_scend + ":" + begin_milli + "=" + beginTime + "ms"); System.out.println("结束:" + end_hour + ":" + end_mintue + ":" + end_scend + ":" + end_milli + "=" + endTime + "ms"); // 解析字幕文字 String srtBody = ""; // 可能1句字幕,也可能2句及以上。 for (int i = 2; i < parseStrs.length; i++) { srtBody += parseStrs[i]+ "\n"; } // 删除最后一个"\n" srtBody = srtBody.substring(0,srtBody.length() - 1); // 设置SRT srt.setBeginTime(beginTime); srt.setEndTime(endTime); srt.setSrtBody(new String(srtBody.getBytes(),"UTF-8")); srtList.add(srt); sb.delete(0,sb.length());// 清空,否则影响下一个字幕元素的解析 } lastEndTime=srtList.get(srtList.size()-1).getEndTime(); br.close(); } catch (IOException e) { // Todo Auto-generated catch block e.printstacktrace(); } //每隔500ms执行一次()取 } public static void showSRT(VideoView videoView,TextView tvSrt) { // Log.d("gaolei","srt_map.size()--------------"+srt_map.size()); int currentPosition = videoView.getCurrentPosition();//vv是VideoView播放器 if(currentPosition>lastEndTime){ tvSrt.setVisibility(View.GONE); return; } for(int i=0;i<srtList.size();i++){ SRT srtbean =srtList.get(i); if (currentPosition > srtbean.getBeginTime() && currentPosition < srtbean.getEndTime()) { tvSrt.setText(srtbean.getSrtBody()); //显示过的就删掉,提高查询效率 srtList.remove(i); break;//找到后就没必要继续遍历下去,节约资源 } } } }
运行效果图:
项目源码,点击下载......
以上这篇Android 实现视频字幕Subtitle和横竖屏切换示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持编程小技巧。
您可能感兴趣的文章:
- Android实现横竖屏切换的实例代码
- android实现在横竖屏切换时页面信息不被重置的示例分享
- Android 屏幕横竖切换详解
- Android实现屏幕旋转方法总结
- 解决Android手机屏幕横竖屏切换
- 解析Android横竖屏切换的问题
Android Activity 横竖屏切换的生命周期
前言
在开发中常要处理横竖屏切换,怎么处理先看生命周期
申明
Activity 横竖屏切换时需要回调两个函数 ,所以在此将这个两个函数暂时看成是Activity 横竖屏切换的生命周期的一部分,这两个函数如下
onSaveInstanceState(Bundle outState) :Activity 即将销毁时保存数据 onRestoreInstanceState(Bundle savedInstanceState) : Activity 重建或者恢复时候取出数据
横竖屏切换生命周期
1、启动程序进入Activity界面
2、旋转屏幕
3、再次旋转屏幕
4 在AndroidManifest.xml中设置
android:configChanges="orientation|screenSize",切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
注意:
MiniSdkVersion大于等于 13 时候:android:configChanges="orientation" 或者 android:configChanges="orientation|keyboardHidden" 重新调用各个生命周期
MiniSdkVersion小于 13 时候:
(1)不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
(2)设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
(3)设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
5、屏幕切换避免,重走Activity生命周期
从上面屏幕切换生命周期可以看出每次切换都在重新创建,为了不必要的麻烦比如视频播放屏幕旋转等,避免重走生命周期就是一个比较好的解决方案
(1)android 2.3之前的版本 android:configChanges="orientation|keyboardHidden"
(2)android 3.0之后的版本 android:configChanges="orientation|screenSize"
横竖屏设置
Android横竖屏切换在手机开发中比较常见,很多软件在开发过程中为了避免横竖屏切换时引发不必要的麻烦,通常禁止掉横竖屏的切换。
一、在AndroidManifest.xml中设置activity中的android:screenorientation属性值来实现。
(1)竖屏:android:screenorientation="portrait"
(2)横屏:android:screenorientation="landscape"
二、在Java代码中通过类似如下代码来设置 (不推荐这种方法,在大的app不同方向启动时会慢)
(1)竖屏: setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
(2)横屏:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
三、如果要彻底禁止翻转,忽略重力感应带来的切换,(模拟器上不管用,在真机上是正确的)
(1)忽略重力:android:screenorientation="nosensor"
横竖屏辨识
一、在onConfigurationChanged里判断,为了onConfigurationChanged在监听屏幕方向变化有效需要以下条件
(1)AndroidManifest.xml增加权限:<uses-permission android:name="android.permission.CHANGE_CONfigURATION"></uses-permission>
(2)AndroidManifest.xml里设置的MiniSdkVersion和 TargetSdkVersion属性大于等于13
(3)在AndroidManifest.xml的Activity里增加:android:configChanges="keyboard|screenSize|orientation|layoutDirection"
(4)在onConfigurationChanged(Configuration newConfig)进行判断
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if(newConfig.orientation == 1)//竖屏 if(newConfig.orientation == 2)// 横屏 }
二、因为当屏幕变为横屏的时候,系统会重调用Activity的onCreate方法可以在onCreate中来检查当前的方向,然后可以让你的setContentView来载入不同的layout xml。
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){ Log.i("info","landscape"); // 横屏 } else if(this.getResources().getConfiguration().orientation ==Configuration.ORIENTATION_PORTRAIT) { Log.i("info","portrait"); // 竖屏 }
注意:该方法是在AndroidManifest.xml中不设置onConfigurationChanged才能重走生命周期
横竖屏切换布局文件设置
如果要让软件在横竖屏之间切换,由于横竖屏的高宽会发生转换,有可能会要求不同的布局。可以通过以下方法来切换布局
(1)在res目录下建立layout-land和layout-port目录,相应的layout文件名称不变,比如main.xml。layout-land是横屏的layout,layout-port是竖屏的layout,其他的不用管,模拟器会自动寻找。
(2)在上面横竖屏辨识中,如果横竖屏出现变化,在onCreate()或者onConfigurationChanged()判断方向,就可以在相应的方法中重新setContentView来载入不同的layout xml布局文件
横竖屏切换数据保存与读取
另外,android中每次屏幕的切换动会重启Activity,所以应该在Activity销毁前保存当前活动的状态,在Activity再次Create的时候载入配置,那样,进行中的游戏就不会自动重启了!
Activity 数据保存
(1)如果因为系统资源紧张而导致Activity的Destory或者旋转屏幕时被destroyed与Recreated, 系统会在用户回到这个Activity时有这个Activity存在过的记录,系统会使用那些保存的记录数据(instance state)它是一些存放在Bundle对象中的key-value pairs,系统默认使用 Bundle保存信息
(2)为了可以保存额外更多的数据到instance state,要重写写这个回调函数onSaveInstanceState(Bundle outState),系统会在Activity被异常Destory时传递Bundle对象,这样我们就可以增加额外的信息到Bundle中并保存到系统中。若系统在Activity被Destory之后想重新创建这个Activity实例时,之前的Bundle对象会(系统)被传递到你我们activity的
(3)Activity开始stop,系统会调用 onSaveInstanceState(Bundle outState) ,Activity可以用键值对的集合来保存状态信息。这个方法会默认保存Activity视图的状态信息,如在 EditText组件中的文本或 ListView 的滑动位置
Activity 数据恢复
(1)当Activity从Destory中重建,我们可以从系统传递的Activity的Bundle中恢复保存的状态。 onCreate() 与 onRestoreInstanceState() 回调方法都接收到了同样的Bundle,里面包含了同样的实例状态信息。
(2)由于 onCreate() 方法会在第一次创建新的Activity实例与重新创建之前被Destory的实例时都被调用,我们必须在尝试读取 Bundle 对象前检测它是否为null。如果它为null,系统则是创建一个新的Activity实例,而不是恢复之前被Destory的Activity。
(3)也可以选择实现 onRestoreInstanceState() ,而不是在onCreate方法里面恢复数据。 onRestoreInstanceState()方法会在 onStart() 方法之后执行. 系统仅仅会在存在需要恢复的状态信息时才会调用 onRestoreInstanceState() ,因此不需要检查 Bundle 是否为null。
以上所述是小编给大家介绍的Android Activity 横竖屏切换的生命周期的相关知识,希望对大家有所帮助!
Android Activity横竖屏切换生命周期详解
关于Activity生命周期和横竖屏切换时,生命周期的执行过程,网上有很多文章。但是都写的很模糊,并且不完善。一般的我们去切换屏幕方向都是不希望Activity被重新创建,这时就需要对一些属性进行设置,或者使用代码设置。文章通过以上方面解析Activity在横竖屏切换时,生命周期方法执行过程。
-
1.Activity生命周期
-
2.configChanges属性解析
-
3.orientation属性
-
4.keyboardHidden属性
-
5.screenSize属性
-
6.总结
-
activity生命周期方法
默认情况下,activity从创建到销毁会执行以下生命周期方法
onCreate -->onStart–>onResumeo -->nPause -->onStop -->onDestroy
- configChanges属性详解
1.orientation 屏幕在纵向和横向间旋转
2.keyboardHidden 键盘显示或隐藏
3.screenSize 屏幕大小改变了
4.fontScale 用户变更了首选的字体大小
5.locale 用户选择了不同的语言设定
6.keyboard 键盘类型变更,例如手机从12键盘切换到全键盘
7.touchscreen或navigation 键盘或导航方式变化,一般不会发生这样的事件
常用的包括:orientation keyboardHidden screenSize,设置这三项界面不会走Activity的生命周期,只会回调onConfigurationChanged方法。
- screenorientation属性详解
1.unspecified 默认值,由系统判断状态自动切换
2.landscape 横屏
3. portrait 竖屏
4.user 用户当前设置的orientation值
5. behind 下一个要显示的Activity的orientation值
6. sensor 使用传感器 传感器的方向
7. nosensor 不使用传感器 基本等同于unspecified 仅landscape和portrait常用,代表界面默认是横屏或者竖屏,还可以再代码中更改。
1.AndroidManifest没有设置configChanges属性
- 竖屏启动: onCreate -->onStart–>onResume
- 切换横屏: onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate–>onStart --> onRestoreInstanceState–>onResume -->onPause -->onStop -->onDestroy
- 横屏启动: onCreate -->onStart–>onResume
- 切换竖屏: onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate–>onStart --> onRestoreInstanceState–>onResume -->onPause -->onStop -->onDestroy
2.AndroidManifest设置了configChanges android:configChanges=“orientation”
- 竖屏启动: onCreate -->onStart–>onResume
- 切换横屏: onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate–>onStart --> onRestoreInstanceState–>onResume -->onPause -->onStop -->onDestroy
- 横屏启动: onCreate -->onStart–>onResume
- 切换竖屏: onPause -->onSaveInstanceState -->onStop -->onDestroy -->onCreate–>onStart --> onRestoreInstanceState–> onResume -->onPause -->onStop -->onDestroy
3.AndroidManifest设置了configChanges android:configChanges=“orientation|keyboardHidden|screenSize”
- 竖(横)屏启动:onCreate -->onStart–>onResume
- 切换横(竖)屏:onConfigurationChanged (Android 6.0 Android 7.0 Android 8.0)
4.AndroidManifest设置了configChanges android:configChanges=“orientation|screenSize”
- 竖(横)屏启动:onCreate -->onStart–>onResume
- 切换横(竖)屏:onConfigurationChanged (Android 6.0 Android 7.0 Android 8.0)
- 注意:代码动态设置横竖屏状态(onConfigurationChanged当屏幕发生变化的时候回调)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- 总结
1.没有设置configChanges属性,当前的界面调用onSaveInstanceState走一遍流程,然后重启调用onRestoreInstanceState再走一遍完整流程,最终destory。
2.设置了configChanges属性为orientation之后,Android6.0 同没有设置configChanges情况相同,完整的走完了两个生命周期,调用了onSaveInstanceState和onRestoreInstanceState方法;Android 7.0则会先回调onConfigurationChanged方法,剩下的流程跟Android 6.0 保持一致;Android 8.0 系统更是简单,
只是回调了onConfigurationChanged方法,并没有走Activity的生命周期方法。
3.设置android:configChanges=“orientation|keyboardHidden|screenSize” 则都不会调用Activity的其他生命周期方法,只会调用onConfigurationChanged方法。
4.没有了keyboardHidden跟3是相同的,orientation代表横竖屏切换 screenSize代表屏幕大小发生了改变,
设置了这两项就不会回调Activity的生命周期的方法,只会回调onConfigurationChanged 。
android 中禁止横竖屏切换
在 Android 中要让一个程序的界面始终保持一个方向,不随手机方向转动而变化的办法: 只要在 AndroidManifest.xml 里面配置一下就可以了。
在 AndroidManifest.xml 的 activity (需要禁止转向的 activity) 配置中加入 android:screenOrientation=”landscape” 属性即可 (landscape 是横向,portrait 是纵向)。例如:
Java 代码
1. <application android:persistent="true"
2. android:label="@string/home_title"
3. android:icon="@drawable/ic_launcher_home">
4.
5. <activity android:name="Home"
6. android:theme="@style/Theme"
7. android:launchMode="singleInstance"
8. android:stateNotNeeded="true"
9. android:screenOrientation="portrait">
10. <intent-filter>
11. <action android:name="android.intent.action.MAIN" />
12. <category android:name="android.intent.category.HOME"/>
13. <category android:name="android.intent.category.DEFAULT" />
14. </intent-filter>
15. </activity>
<application android:persistent="true"
android:label="@string/home_title"
android:icon="@drawable/ic_launcher_home">
<activity android:name="Home"
android:theme="@style/Theme"
android:launchMode="singleInstance"
android:stateNotNeeded="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
另外,android 中每次屏幕方向切换时都会重启 Activity,所以应该在 Activity 销毁前保存当前活动的状态,在 Activity 再次 Create 的时候载入配置,那样,进行中的游戏就不会自动重启了!
要避免在转屏时重启 activity,可以通过在 androidmanifest.xml 文件中重新定义方向 (给每个 activity 加上 android:configChanges=”keyboardHidden|orientation” 属性),并根据 Activity 的重写 onConfigurationChanged (Configuration newConfig) 方法来控制,这样在转屏时就不会重启 activity 了,而是会去调用 onConfigurationChanged (Configuration newConfig) 这个钩子方法。例如:
Java 代码
1. if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
2. // 横向
3. setContentView(R.layout.file_list_landscape);
4. }else{
5. // 竖向
6. setContentView(R.layout.file_list);
7. }
if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
// 横向
setContentView(R.layout.file_list_landscape);
}else{
// 竖向
setContentView(R.layout.file_list);
}
在模拟器中,要使程序转屏可以使用快捷键 F12 或 Ctrl+F11 来切换。当然在用命令行启动模拟器时可以直接使用参数 emulator.exe -skin HVGA-L 来启动横屏的程序。
android 禁止横竖屏切换时调用 onCreate 函数
2011-08-04 18:04 385 人阅读 评论 (0) 收藏 举报
在横竖屏切换的时候会重新调用 onCreate 方法,可以使用以下方法禁止切换的过程中调用 onCreate 方法,如果你需要横屏和竖屏使用不同的布局文件,可能这种方式是不行的,经过我自己写代码测试,如果当前是竖屏,经过切换后它并不会使用横屏的布局文件,而是将竖屏的布局文件使用在横屏状态下,不知道是我写的不合适还是本来就这样,希望和大家讨论这个问题。
禁止调用 onCreate 方法:在 Mainifest.xml 的 Activity 元素中加入 android:configChanges="orientation|keyboardHidden" 属性
我写的测试程序:
view plaincopy to clipboardprint?package lzu.LandAndPortraintTest;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
public class LandAndPortraintTest extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
printSentence();
}
public void printSentence(){
System.out.println("printSentence");
}
public void printPortraintSentence(){
System.out.println("printSentence Portraint");
}
public void printLandscapeSentence(){
System.out.println("printSentence Landscape");
}
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
{
printLandscapeSentence();
}
else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
{
printPortraintSentence();
}
}
}
package lzu.LandAndPortraintTest;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
public class LandAndPortraintTest extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
printSentence();
}
public void printSentence(){
System.out.println("printSentence");
}
public void printPortraintSentence(){
System.out.println("printSentence Portraint");
}
public void printLandscapeSentence(){
System.out.println("printSentence Landscape");
}
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
{
printLandscapeSentence();
}
else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
{
printPortraintSentence();
}
}
} layout-land 下 main.xml 文件:view plaincopy to clipboardprint?<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>layout-port 下 main.xml 文件:view plaincopy to clipboardprint?<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
/>
</LinearLayout>
values 下 strings.xml 文件:view plaincopy to clipboardprint?<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, LandAndPortraintTest!</string>
<string name="app_name">LandAndPortraintTest</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, LandAndPortraintTest!</string>
<string name="app_name">LandAndPortraintTest</string>
</resources>
Android 如何只禁止某一个Layout在横竖屏切换的时候重新加载
Android中有办法让一个Activity只加载port/land布局,如:
android:screenOrientation="portrait"
android:screenOrientation="landscape"
我现在想,只固定某一个Layout为竖直方向,如何能做到呢?
今天的关于Android 实现视频字幕Subtitle和横竖屏切换示例和android视频播放横竖屏切换的分享已经结束,谢谢您的关注,如果想了解更多关于Android Activity 横竖屏切换的生命周期、Android Activity横竖屏切换生命周期详解、android 中禁止横竖屏切换、Android 如何只禁止某一个Layout在横竖屏切换的时候重新加载的相关知识,请在本站进行查询。
本文标签: