版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1434864
最近,开始学习android官网提供的training 官方文档。比起一般学习教材,官网上的内容,给我最大的感受是,这更像是软件设计的艺术。它不仅仅讲每个知识点具体应该如何做,能达到效果,另外一点非常重要的内容是:对应每个知识点,我们需要注意什么,这里为什么不能写具体的coding,在那就能写了。废话不多说,开始翻译、记录、学习。
这是Android启动应用时,activity将要走过的路线。和之前我学到的Activity图有所出路。
这两张图都描述了activity的行走路线,我个人更喜欢第一张图。第一张图的描述,类似于金字塔型。这非常形象地描述了Activity从onCreate()开始是如何一步一步走向顶端的Resumed。由图也能看出,一个activity经过onCreate()以及onStart()后,倘若activity始终处于运行状态,它将停留在Resumed状态下。接着,图片又描述了Paused状态以及Stopped状态。它们在不同的情况下,又能回到Resumed状态,最后便是金字塔的另外一端,Destroyed。这也就意味着Activity最终将释放所有资源,从内存中退出。
用户操作手机的过程,都会相应的调用状态函数,因此,我们应该清楚这些注意点,对应的都是哪些状态函数。以及写该状态函数时,需要注意的点。
在上图展示的六个状态,其中三个是属于静态的,而另外三个是瞬态的(将直接跳转到下一状态。)。静态的便是:Resumed、Paused、Stopped,这三个状态能长时间存在。
在这个状态下,activity运行在前台,用户能够做任何操作。
只有当前activity被另外一个activity部分遮住,或者另外一个activity为半透明,总之不能被全部遮住,才会跳转到这个状态下。值得注意的是:在这个状态下是不能接收用户输入操作并且不能执行任何用户操作。
在这个状态下,当前activity被全部遮住,即对用户不可见,但是它还在后台俏俏的待命。当activity 停止时,当前activity实例以及状态信息,诸如成员变量等都保留在内存中,但不能执行任何用户操作。
这便是activity最基本的生命周期。接下来,将介绍每个状态对应具体的行为。
想了解activity创建后,所有状态是如何依次执行的,只要重写各种状态回调函数即可。这里列出最常用的onCreat()方法的构建。
TextView mTextView;
// Member variable for text view in the layout
@Override
public
void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Set the user interface layout for this Activity
// The layout file is defined in the project res/layout/main_activity.xml file
`setContentView(R.layout.main_activity);`
// Initialize member TextView so we can manipulate it later
`mTextView =` `(TextView) findViewById(R.id.text_message);`
Log.d("debug","oncreate() callback......");
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if
(Build.VERSION.SDK_INT >=
Build.VERSION_CODES.HONEYCOMB)
{
// For the main activity, make sure the app icon in the action bar
// does not behave as a button
ActionBar actionBar = getActionBar();
`actionBar.setHomeButtonEnabled(false);`
}
}
当用户正常使用APP时,有时候便会发生切换视图组件,导致当前activity暂停的情况。只要当前activity的一部分视图能被用户看见,但用户的操作不聚焦在当前activity上,便会发生状态转移。
一旦activity从paused状态回到resumed状态,就会调用onResume方法。当用户调用onPause方法后,很大的概率将要导致用户离开APP,这也就暗示着会相继发生onStop方法。因此,我们通常在onPause()方法中需注意几点:
举个例子:当我们使用相机时,在onPause()方法中记得释放它。
@Override
public
void onPause()
{
super.onPause();
// Always call the superclass method first
// Release the Camera because we don't need it when paused
// and other activities might need to use it.
if
(mCamera !=
null)
{
`mCamera.release();`
`mCamera =` `null;`
}
}
但一般情况下,也并非保存所有的用户数据,除非用户是希望当离开APP时,有自动保存的功能,草稿箱适合这样的情况下使用。而且,我们应该尽量避免保存数据的操作时间过程,如需要写入数据库等操作,这会影响用户切换到其他activity的用户体验。尽量将这些繁杂的操作在onStop()方法中执行。总之,在onPause()中,尽量简化代码,以获得更快的转移效果。
Note: 当activity进入paused状态后,它之前所初始化的组件信息是存储在内存中的,并不会消失,因此也无需在onResume()方法中重新进行初始化。
正如前面代码所示,如果你在onPause方法中,释放了一些系统资源,那么一旦用户回到activity就需要相应的初始化释放掉的资源。其次,初始化之前只在onResume方法中初始化的资源。
@Override
public
void onResume()
{
super.onResume();
// Always call the superclass method first
// Get the Camera instance as the activity achieves full user focus
if
(mCamera ==
null)
{
`initializeCamera();` `// Local method to handle camera init`
}
}
在我们的程序中,恰当的停止以及重启我们的程序是必要的。设计软件时,需给用户一种完整的app体验。Stopped发生的场景:
这里同样需要注意的一点是:如同进入Paused状态一样,系统还会保留当前activity实例在我们的内存中。因此,也可以不用重写onStop()和onRestart()方法。对于绝大多数简单的应用,只需要在activity进入stopped状态之前,重写onPause()方法,来关闭一些正在执行的动作,释放系统资源即可。
还需要注意一点的是:有时候系统由于内存资源使用紧张的情况下,会莫名其妙的直接kill掉你的app程序,这时候它是不会调用onDestroy()方法的,因此,在onStop中,如果APP涉及一些大资源,如数据库的读写操作的使用时,建议在onStop方法中,保存用户数据并关掉这些资源,避免内存泄漏。
如用户在编辑内容时,onStop方法中保存这些内容:
@Override
protected
void onStop()
{
super.onStop();
// Always call the superclass method first
// Save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
ContentValues values =
new
ContentValues();
`values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());`
`values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());`
`getContentResolver().update(`
`mUri,` `// The URI for the note to update.`
`values,` `// The map of column names and new values to apply to them.`
null,
// No SELECT criteria are used.
null
// No WHERE columns are used.
);
}
记得,在onRestart方法中,重新获得这些数据即可。但是否所有的用户数据需要保存呢?不然,视图组件的状态,系统其实会自动记录在内存中,如在editText中,编写的用户数据,完全不需要保存,当用户从stopped状态回到resumed状态后,editText里的内容由系统自动调用。甚至在destroyed状态下,这些数据依然留存。因此,对于我们来讲,注意那些非视图组件的信息的留存即可。
在官方文档中,它其实并不提倡使用onRestart方法,除非一些应用是确定不会进入destroyed状态,只会停留在stopped状态。但为了以防万一,还是建议使用onStart方法,并且在onStart方法中,要注意当前的系统环境是否支持某些初始化操作。如:
@Override
protected
void onStart()
{
super.onStart();
// Always call the superclass method first
// The activity is either being restarted or started for the first time
// so this is where we should make sure that GPS is enabled
LocationManager locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if
(!gpsEnabled)
{
// Create a dialog here that requests the user to enable GPS, and use an intent
// with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action
// to take the user to the Settings screen to enable GPS when they click "OK"
}
}
@Override
protected
void onRestart()
{
super.onRestart();
// Always call the superclass method first
// Activity being restarted from stopped state
}
最后还需注意的一点是:在onDestroy()方法中,是最后释放所有系统资源的机会,切忌别让app内存泄漏了。o(︶︿︶)o
Destroyed发生的场景:
当然,并非所有的程序APP如我们所想,能顺利结束,有很多种情况让它意外退出,因此,为了防止意外退出的发生,系统提供了一种机制来保存activity的实例,这种机制便是 通过bundle绑定“instance state”,以键值对的方式保存在bundle对象中。当程序app启动时,自动加载系统的实例状态,呈现在用户面前。前面提到的editText中的文本信息的留存,便是最好的例证。
可惜,系统只能保存有限的信息,编写程序时,有很多用户数据是并非由系统来完成管理的。因此,如果想要保存额外的信息,需要借助onSaveInstanceState()方法来实现。
由图可以看出,在进入Destroyed之前,该方法自动执行,我们只要在这里记录一些用户信息,传给bundle即可。当下次app重启时,在onCreate方法和onRestoreInstanceState方法中,都能够重新加载信息。有两个地方供我们提取出之前维护的信息,选择其中一个方法即可。
来个例子:
static
final
String STATE_SCORE =
"playerScore";
static
final
String STATE_LEVEL =
"playerLevel";
...
@Override
public
void onSaveInstanceState(Bundle savedInstanceState)
{
// Save the user's current game state
`savedInstanceState.putInt(STATE_SCORE, mCurrentScore);`
`savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);`
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
重新加载用户保存的信息:
@Override
protected
void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if
(savedInstanceState !=
null)
{
// Restore value of members from saved state
`mCurrentScore = savedInstanceState.getInt(STATE_SCORE);`
`mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);`
}
else
{
// Probably initialize members with default values for a new instance
}
...
}
这里需要注意的一点是:savedInstanceState判空的细节,因为程序很有可能正常退出,因此savedInstanceState,在app创建一个新的实例时,定为空。这也验证了,只有当程序意外退出时,才会调用onSaveInstanceState方法。
当然,我们也可以选择更加方便的方法,无需判空,重写onRestoreInstanceState方法即可:
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
分享结束、fighting!o(∩_∩)o