1 Android 组件
2018年,已经开始1/4,感觉自己不能在放纵自己了,要想提高就要先迈步,写博客就是我的第一步,它是我这一年是否成长的见证。各位同仁,如有写的不好的地方,请多多指点,你的指点会让我更加认清我自己,在此先表达我的谢意!
1、Activity
1、功能:是android 四大组件之一,可以用于显示view,app与用户交互的媒介。
<fragment
android:id="@+id/myFragment"
android:name="com.ugdao.activityandfragment.MyFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"></fragment>
04-16 17:03:59.557 27124-27124/? E/AAA: onAttach:
04-16 17:03:59.557 27124-27124/? E/AAA: onCreate:
04-16 17:03:59.557 27124-27124/? E/AAA: onCreateView:
04-16 17:03:59.567 27124-27124/? E/aaa: onCreate:
04-16 17:03:59.557 27124-27124/? E/AAA: onActivityCreated:
04-16 17:03:59.567 27124-27124/? E/AAA: onStart:
04-16 17:03:59.567 27124-27124/? E/aaa: onStart:
04-16 17:03:59.567 27124-27124/? E/aaa: onResume:
04-16 17:03:59.567 27124-27124/? E/AAA: onResume:
04-16 17:17:05.297 28898-28898/com.ugdao.activityandfragment E/AAA: onPause:
04-16 17:17:05.297 28898-28898/com.ugdao.activityandfragment E/aaa: onPause:
04-16 17:17:05.687 28898-28898/com.ugdao.activityandfragment E/AAA: onStop:
04-16 17:17:05.687 28898-28898/com.ugdao.activityandfragment E/aaa: onStop:
04-16 17:17:05.687 28898-28898/com.ugdao.activityandfragment E/AAA: onDestroy:
04-16 17:17:05.687 28898-28898/com.ugdao.activityandfragment E/AAA: onDetach:
04-16 17:17:05.687 28898-28898/com.ugdao.activityandfragment E/aaa: onDestroy:
04-16 17:31:49.177 30550-30550/? E/aaa: onCreate:
04-16 17:31:49.177 30550-30550/? E/aaa: onStart:
04-16 17:31:49.177 30550-30550/? E/aaa: onResume
04-16 17:31:57.857 30550-30550/com.ugdao.activityandfragment E/AAA: onAttach:
04-16 17:31:57.857 30550-30550/com.ugdao.activityandfragment E/AAA: onCreate:
04-16 17:31:57.867 30550-30550/com.ugdao.activityandfragment E/AAA: onCreateView:
04-16 17:31:57.867 30550-30550/com.ugdao.activityandfragment E/AAA: onActivityCreated:
04-16 17:31:57.867 30550-30550/com.ugdao.activityandfragment E/AAA: onStart:
04-16 17:31:57.867 30550-30550/com.ugdao.activityandfragment E/AAA: onResume
04-16 18:07:13.837 884-884/com.ugdao.activityandfragment E/AAA: onPause:
04-16 18:07:13.837 884-884/com.ugdao.activityandfragment E/aaa: onPause:
04-16 18:07:14.217 884-884/com.ugdao.activityandfragment E/AAA: onStop:
04-16 18:07:14.217 884-884/com.ugdao.activityandfragment E/aaa: onStop:
04-16 18:07:14.217 884-884/com.ugdao.activityandfragment E/AAA: onDestroy:
04-16 18:07:14.217 884-884/com.ugdao.activityandfragment E/AAA: onDetach:
04-16 18:07:14.217 884-884/com.ugdao.activityandfragment E/aaa: onDestroy:
Activity异常时候的生命周期(minSdkVersion 15)
(1)当我们正常启动activity时候,会走 onCreate onStart onResume三个生命周期方法
(2)当我们从竖屏切换到横屏的时候,生命周期如下:
04-17 02:38:31.374 20350-20350/com.ugdao.activityandfragment E/aaa: onPause:
04-17 02:38:31.386 20350-20350/com.ugdao.activityandfragment E/aaa: onStop:
04-17 02:38:31.386 20350-20350/com.ugdao.activityandfragment E/aaa: onDestroy:
04-17 02:38:31.532 20350-20350/com.ugdao.activityandfragment E/aaa: onCreate:
04-17 02:38:31.534 20350-20350/com.ugdao.activityandfragment E/aaa: onStart:
04-17 02:38:31.534 20350-20350/com.ugdao.activityandfragment E/aaa: onRestoreInstanceState:
04-17 02:38:31.536 20350-20350/com.ugdao.activityandfragment E/aaa: onResume:
(3)再在这个基础上切换到竖屏,生命周期如下:
04-17 02:56:19.770 21306-21306/com.ugdao.activityandfragment E/aaa: onPause:
04-17 02:56:19.779 21306-21306/com.ugdao.activityandfragment E/aaa: onStop:
04-17 02:56:19.779 21306-21306/com.ugdao.activityandfragment E/aaa: onDestroy:
04-17 02:56:19.845 21306-21306/com.ugdao.activityandfragment E/aaa: onCreate:
04-17 02:56:19.846 21306-21306/com.ugdao.activityandfragment E/aaa: onStart:
04-17 02:56:19.847 21306-21306/com.ugdao.activityandfragment E/aaa: onRestoreInstanceState:
04-17 02:56:19.850 21306-21306/com.ugdao.activityandfragment E/aaa: onResume:
(4)在清单文件中,给activity配置configChanges属性,属性设置为orientation|screenSize,代码如下:
<activity android:name=".MainActivity"<span style="background-color:rgb(255,0,0);"> android:configChanges="orientation|screenSize"</span>>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
切换横竖屏后,就不会在走生命周期:只会走onConfigurationChanged方法,并且横竖都只走一次。
04-17 03:02:53.806 21684-21684/com.ugdao.activityandfragment E/aaa: onConfigurationChanged:
(5)在清单文件中,给activity配置configChanges属性,属性设置为orientation|keyboardHidden,代码如下:
结果:和4一样。
注意点:
当minSdkVersion >=13时
orientation 或者orientation|keyboardHidden|screenSize,都不会重新调用各自的生命周期。
当minSdkVersion<13时
(1)不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
(2)设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
(3)设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法
禁止横竖屏的切换方法:
一、在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"
Activity四种启动模式:
(1)standard:默认模式,无论我们将要启动的activity在栈中的位置是否是在栈顶或栈的其它位置,都会重新创建一个实例。
(2)singleTop:栈顶模式:如果我们要启动的activity是在栈顶,在栈中就不会创建新的实例,会直接复用,如果不在栈顶,就会重新创建一个实例。
(3)singleTask:栈中单实例模式,我们将要启动的activity,如果其在栈中有实例就会直接复用这个实例,如果不是在栈顶,其上面的实例会出栈,其回到栈顶。
(4)singleInstance:特点是:启动界面的时候,它会创建一个新栈,栈中只有这一个实例,多用于跨进程通讯时候用。如:来电话显示界面。
Activity 之间传递数据
bundle理解:可以理解为是intent中的数据。
数据保存方式:
①可以把数据保存到intent对象中
②也可以把数据保存到bundle对象中,在把bundle对象封装到intent中。代码如下:
//把数据封装至intent对象中
intent.putExtra("malename", "张三");
intent.putExtra("femalename", "李四");
//把数据封装至bundle对象中
Bundle bundle = new Bundle();
bundle.putString("malename", "张三" );
bundle.putString("femalename", "李四" );
//把bundle对象封装至intent对象中
intent.putExtras(bundle);
startActivity(intent);
它们俩谁更好呢,线面来分析一下:
场景一:如果是我们只启动一个界面,并且传递的值只在这个启动界面里用到,这样我们直接通过intent直接传值比较好,因为如果需要bundle保存数据的话,我们需要创建对象,我们知道创建对象是会消耗内存的,所以建议使用intent直接传值。
场景二:如果我们通过A界面可以跳转到B和C界面
直接用Intent我们就会写两遍,并且写两遍传值的方法,如果Bundle我们只需用一个Bundle对象即可,最为公用。这样就减少了代码量。所以这种情况推荐使用bundle。
如何返回数据:
基本流程:
①使用startActivityForResult(Intent intent, int requestCode)方法打开Activity;
②在新Activity中调用setResult(int requestCode,int resultCode,Intent data)方法;
③在原来的activity中重写onActivityResult(int requestCode, int resultCode,Intent data)方法;
④注意新的activitity的启动模式不能是SingleTask模式,因为如果新Activity在栈中已经创建,启动它时候是不会重新走onCreate生命周期方法的,而是会走onNewIntent方法和onResume()方法。在这个方法里我们将接收到一个新的intent,用这个intent覆盖我们之前启动此activity的intent,这样我们getIntent()方法的时候,就是最新的intent。代码如下:
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
service
1、简介:
service是Android四大组件之一,其可以在后台长时间的执行工作,它不和用户产生Ui交互。如果没有显示指定service的进程,那么service和activity是运行在当前app中的Ui Thread中,其不能做耗时操作,如果想做耗时操作,需要开启子线程进行。
2、service的启动方式及生命周期
(1)start方式启动:生命周期:
onCreate onStartCommand onDestroy
一般使用以下两种方法创建一个startService
①继承Service类
②继承IntentService类,intentService类父类是Service,若不同时处理多个请求,优先选择IntentService,重写onHandleIntent()
方法,此方法已经默认帮我们开启了一个子线程,操作完成后不需要我们手动调用stopService,onHandleIntent()方法会主动调用此方法。当我们调用startService(intent),会立即回调startCommand方法。onHandleIntent方法是在onStartCommand方法之后执行。
注意:
①在项目中有可能多次启动了此service,但是当我们调用stopService()方法或者是stopSelf方法此服务就会停止。
②若系统正在调用多个onStartCommand请求,如果其中一个请求启动时,需要停止此请求,为了避免把整个服务停掉,需要选择stopSelf(int)方法,此方法的参数就是启动请求的id,当我们调用stopSelf(int)方法时候,此id会和startCommand方法中的启动id进行比较,如果相等,就停止,如果在调用stopSelf(int)之前,service又接受了一个新的start请求,那么这个启动请求的id与stopSelf(int)传递的id不一样,就不能提停止此服务,这样就解决了这个问题。
(2)service绑定方式:生命周期
onCreate onBind onUnbind onDestroy
注意:创建bound service 必须重写onBind回调方法,因为此方法返回一个IBind接口,此接口是组件和service的通讯的桥梁。
组件绑定此服务的时候,会获取IBind接口,通过类型转换,可以获取此service的实例,通过实例可以调用service的方法。代码如下:
}
...
bindService(new Intent(MainActivity.this, MyService.class), serviceConnection, Context.BIND_AUTO_CREATE);
...
}
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, <span style="background-color:rgb(255,0,0);">IBinder iBinder</span>) {
MyService myservice = (MyService) iBinder;
myservice.stopSelf(1);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
注意点: 我们创建service时候一定要在清单文件中进行配置,如果是通过Android studio自动生成的不用配置。