Android基础知识详解二
来源:互联网 发布:网络pt老虎机辅助 编辑:程序博客网 时间:2024/05/21 08:50
1.Activity的启动模式与特点。
Activity有四中启动模式,分别是:
1: standard
2: singleTop
3: singleTask
4: singleInstance
可以和activity的flags(通过Intent对象调用FLAG_ACTIVITY_* ,*代表常量)结合使用。
如下表所示, standard是默认模式并且适用于大多数类型的activity。
官方文档:
http://developer.android.com/intl/zh-cn/guide/topics/manifest/activity-element.html#lmode
2.Intent的使用方法,可以传递哪些数据类型。
intent间传送数据一般有两种常用的方法: 1、extra 2、data。
extra可以用Intent.putExtra放入数据。新启动的Activity可用Intent.getExtras取出Bundle,然后用Bundles.getLong,getInt,getBoolean,getString等函数来取放进去的值。
Data则是传输url。url可以是指我们熟悉的http,ftp等网络地址,也可以指content来指向ContentProvider提供的资源。Intent.setData可以放入数据,Intent.getData可以取出数据。
3 Activity的缓存方法?
看如下场景:
有A、B两个Activity,当从A进入到B中,如果系统内存不够,那么这时候A可能会被系统回收掉,这时候,我们再按back键,那么,执行的就不是A的onRestart()方法,而是onCreate()了,A被重新创建了一次,那么A中的临时数据可能就丢失了。
这时候如果要保存这些数据怎么办?当然是有办法的。Activity中有一个onSaveInstanceState()就是用来干这活的。先来看看它的代码实现:
protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}
我们看到,它有一个Bundle参数,通过outState.putString(key,value)、outState.putInt(key,value)等不同的方法将临时数据保存下来。
那么这些数据保存到哪里去了,又是什么时候调用?既然它能够起到缓存的作用,那么在Activity启动,也就是onCreate的时候,就肯定会去调用这些数据的是吗,我们来看看OnCreate()方法的实现:
@MainThread
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, “onCreate ” + this + “: ” + savedInstanceState);
if (mLastNonConfigurationInstances != null) {
mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
}
if (mActivityInfo.parentActivityName != null) {
if (mActionBar == null) {
mEnableDefaultActionBarUp = true;
} else {
mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
}
}
//这里是为了保存第一次的时候savedInstanceState 为空,由这里我们可以看到是取了值的。
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
if (mVoiceInteractor != null) {
mVoiceInteractor.attachActivity(this);
}
mCalled = true;
}
由上面我们就知道了它的运行机制了,那么我们自己该如何使用它呢,我写一段简短的代码大家看一下:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(“myStringData”,”11111111”);
outState.putInt(“myIntData”,1);
}
OK,在onCreate中取值。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//第一次创建,判空。
if( savedInstanceState != null ){
String myStringData = savedInstanceState.getString(“myStringData”);
int myIntData = savedInstanceState.getInt(“myIntData”);
…
}
}
知道了运行原理了,也知道该如何用了,下面我们来看看我们应该在什么场景下用它。
当某个activity很“容易”被系统销毁时,该onSaveInstanceState()就会被执行,除非该Activity是主动被用户销毁的,例如按back键时。
那么?什么是“容易”呢?有以下几种情况:
1:当用户按下HOME键时;显而易见,系统不知道你按下HOME键后要运行多少程序,而你按下HOME键前的Activity有可能会被系统回收掉,所以这时候必定会执行。
2:长按HOME键,运行其他程序,这个和第一情况类似。
3:按下电源键(关闭屏幕)时;这个不解释。
4:从Activity中启动一个新的Activity时,就是开篇的那种场景。
5:屏幕方向切换时,例如,从竖屏切换到横屏(如果不指定configchange属性),在切换前,系统会销毁Activity A,切换之后又会重新自动的创建Activity A,所以onSaveInstanceState()一定会被执行。
总而言之,onSaveInstanceState()的调用遵循一个重要原则,既系统“未经你许可”时销毁了你的Activity,则onSaveInstanceState()会被系统调用,这是系统的责任,因为它必须提供一个机会让你保存数据。
需要注意的几点:
1:布局中的每一个View默认实现了onSaveInstanceState()方法,这样的话,这个UI的任何改变都会自动的存储和在activity重新创建的时候自动的恢复。但是这种情况只有在你为这个UI提供了唯一的ID之后才起作用,如果没有提供ID,将不会存储它的状态。
2:由于默认的onSaveInstanceState()方法的实现帮助UI存储它的状态,所以如果你需要覆盖这个方法去存储额外的状态信息时,你应该在执行任何代码之前都调用父类的onSaveInstanceState()方法(super.onSaveInstanceState())。既然有现成的可用,那么我们到底还要不要自己实现onSaveInstanceState()?这得看情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量也保存了,那么就需要自己实现,否则就不需要。
3:由于onSaveInstanceState()方法调用的不确定性,你应该只使用这个方法去记录activity的瞬间状态(UI的状态)。不应该用这个方法去存储持久化数据。当用户离开这个activity的时候应该在onPause()方法中存储持久化数据(例如应该被存储到数据库中的数据)。
4:onSaveInstanceState()如果被调用,这个方法会在onStop()前被触发,但系统并不保证是否在onPause()之前或者之后触发。
另外,还有一个方法onRestoreInstanceState(Bundle outState)需要注意,两个方法不一定是成对出现的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行。另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原。
还有onRestoreInstanceState在onstart之后执行。至于这两个函数的使用,给出示范代码(留意自定义代码在调用super的前或后):
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean(“myBoolean”, true);
savedInstanceState.putDouble(“myDouble”, 1.0f);
savedInstanceState.putInt(“myInt”, 1);
savedInstanceState.putString(“myString”, “11111111”);
super.onSaveInstanceState(savedInstanceState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
boolean myBoolean = savedInstanceState.getBoolean(“myBoolean”);
double myDouble = savedInstanceState.getDouble(“myDouble”);
int myInt = savedInstanceState.getInt(“myInt”);
String myString = savedInstanceState.getString(“myString”);
}
4:Service的生命周期,两种启动方法,有什么区别。
1:采用普通方式开启服务:
使用Service的步骤:
1:定义一个Service;
2: 在Mainfest.xml文件中配置Service;
3:使用Context启动StartService(),开启服务;
4不再使用时,调用StopService(),停止服务;
使用普通服务的生命周期:
onCreate()—>onStartCommand()—>onDestroy()
说明:如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStart()和onStartCommand()。
服务停止的时候调用 onDestory()。服务只会被停止一次。
特点:一旦服务开启跟调用者(开启者)就没有任何关系了。
开启者退出了,开启者挂了,服务还在后台长期的运行。
开启者不能调用服务里面的方法。
2:开启绑定方式开启服务:
使用Service的步骤:
1.定义一个类继承Service2.在Manifest.xml文件中配置该Service3.使用Context的bindService(Intent, ServiceConnection, int)方法启动该Service4.不再使用时,调用unbindService(ServiceConnection)方法停止该服务
使用这种start方式启动的Service的生命周期如下:
onCreate() —>onBind()—>onunbind()—>onDestory()
注意:绑定服务不会调用onstart()或者onstartcommand()方法
特点:bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。
绑定者可以调用服务里面的方法。
绑定者如何调用服务里的方法呢?
首先定义一个Service的子类。
public class MyService extends Service {
public MyService() {}@Overridepublic IBinder onBind(Intent intent) { //返回MyBind对象 return new MyBinder();}private void methodInMyService() { Toast.makeText(getApplicationContext(), "服务里的方法执行了。。。", Toast.LENGTH_SHORT).show();}/** * 该类用于在onBind方法执行后返回的对象, * 该对象对外提供了该服务里的方法 */private class MyBinder extends Binder implements IMyBinder { @Override public void invokeMethodInMyService() { methodInMyService(); }}
}
自定义的MyBinder接口用于保护服务中不想让外界访问的方法。
public interface IMyBinder {
void invokeMethodInMyService();
}
接着在Manifest.xml文件中配置该Service
在Activity中绑定并调用服务里的方法
简单布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="start" android:text="开启服务" android:textSize="30sp" /><Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="invoke" android:text="调用服务的方法" android:textSize="30sp" />
绑定服务的Activity:
public class MainActivity extends Activity {
private MyConn conn;private Intent intent;private IMyBinder myBinder;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);}//开启服务按钮的点击事件public void start(View view) { intent = new Intent(this, MyService.class); conn = new MyConn(); //绑定服务, // 第一个参数是intent对象,表面开启的服务。 // 第二个参数是绑定服务的监听器 // 第三个参数一般为BIND_AUTO_CREATE常量,表示自动创建bind bindService(intent, conn, BIND_AUTO_CREATE);}//调用服务方法按钮的点击事件public void invoke(View view) { myBinder.invokeMethodInMyService();}private class MyConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //iBinder为服务里面onBind()方法返回的对象,所以可以强转为IMyBinder类型 myBinder = (IMyBinder) iBinder; } @Override public void onServiceDisconnected(ComponentName componentName) { }}
}
绑定本地服务调用方法的步骤:
1 在服务的内部创建一个内部类 提供一个方法,可以间接调用服务的方法
2 实现服务的onbind方法,返回的就是这个内部类
3 在activity 绑定服务。bindService();
4 在服务成功绑定的回调方法onServiceConnected, 会传递过来一个 IBinder对象
5 强制类型转化为自定义的接口类型,调用接口里面的方法。
- Android基础知识详解二
- [Android基础知识] 之二十二 UI设计之 LayoutInflater详解
- android 基础知识二
- Android 基础知识 二十
- Android基础知识(二)
- Android基础知识(二)
- 基础知识(二) LinkedHashMap 源码详解
- android service基础知识详解
- [Android基础知识] WebView详解
- Android 基础知识详解
- Android各种基础知识(二)
- Android基础知识(二)—-Menu
- Android基础知识总结(二)
- Android Scroll详解(一):基础知识
- Android Scroll详解(一):基础知识
- C++面向对象基础知识详解二
- JSP学习(二)------JSP基础知识详解
- Android系统回顾(二):Android基础知识
- 第十五周练习—— 判断字符串是否为回文
- ElasticSearch5.0——自定义排序规则
- 请求转发和请求重定向
- 【BLE】CC2541之配对密码的读取与修改
- 深入认识javascript中的eval函数
- Android基础知识详解二
- Linux常用命令之seq
- JUC原子类 Atomic***** 使用
- OPENCV人脸检测例子
- MongoDB简介及其主要特点
- mysql 通过子查询实现两列相除
- java 上传图片 cxf,servlet,spring 标准方式
- 存储的本质~
- AppStream cache update completed, but some metadata was ignored due to errors.