续第二课( 下)

写app必须掌握活动的生命周期。

[活动的生命周期]

[返回栈]

android每次启动的活动会覆盖在原活动之上,然后点击Back键会销毁最上层的活动。是使用Task来管理活动,一个任务就是一组存放在栈里面的活动的集合,这个栈被称为返回栈。

每当我们按下这个Back或者调用finish()方法去销毁一个活动,处于栈顶的活动就会出栈。


[活动状态]

  1. 运行状态

一个活动位于返回栈栈顶的时候,就是运行状态,也是系统最不愿意回收的状态的活动。

  1. 暂停状态

当一个活动不再处于栈顶,但还是可见时,就进入了暂停状态。如对话框。仅仅有在内存极低的情况下,系统才会回收这个活动

  1. 停止状态

当一个活动不处于栈顶且不可见时就进入了停止状态。系统有可能会回收。

  1. 销毁状态

当一个活动从返回栈中移除后就变成了销毁状态。系统回收这样的状态的活动,保证内存充足。


[活动的生存期]

Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节。

方法 简单介绍
onCreate() 每一个活动,我们都重写了这种方法。他会在活动第一次被创建的时候调用。

能够用来完毕活动的初始化操作。

如载入布局,绑定事件

onStart() 在活动由不可见变为可见时调用
onResume() 在活动准备好与用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,处于运行状态。
onPause() 这种方法在活动准备去启动或者恢复还有一个活动的时候调用。

通常在这种方法中释放一些消耗CPU的资源,以及保存一些重要数据,但这种方法的运行速度一定要快。否则会影响新栈顶活动的使用

onStop() 这种方法在活动不可见的时候调用。

它和onPause()差别:启动的活动是一个对话框式的活动。onStop()不会运行。

onDestory() 这种方法在活动被销毁之前调用
onRestart() 这种方法在活动由停止状态变为运行状态之前调用

除了onRestart()方法外。都为两量相应关系

三种生存期:

生存期 简单介绍
完整生存期 在onCreate()方法和onDestory()之间所经历的就是完整生存期
可见生存期 onStart()和onStop()方法之间所经历的。

前台生存期 在onResume()和onPause()之间经历的

都是从载入资源到释放资源,从而合理的管理资源。

image&quality=100&size=b4000_4000&sec=1490749307&di=f4b89aa27293365bf0aa4d308ff4f1fa&src=http://images2015.cnblogs.com/blog/759818/201602/759818-20160229131849783-503499100.png" alt="示意图" title="">


[体验活动的生命周期]

既然是体验,我们还是又一次new project吧,这次创建子活动勾选Launcher Activity。创建NormalActivity,DialogActivity.

编辑activity_normal.xml:

<LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is normal activity"
/> </LinearLayout>

编辑activity_dialog.xml:

<LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent"> <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text = "This is a dialog activity"/> </LinearLayout>

从名字上能够看出,一个是normal活动,一个是dialog活动(对话框式),可是上面的代码基本一样啊。

。。

我们须要去AndroidManifest.xml中改动:

        <activity android:name=".DialogActivity"
android:theme="@android:style/Theme.Dialog">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

我们给它添加了android:theme的属性。

如今去activity_main.xml中去添加button:

    <Button
android:id="@+id/start_normal_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start normalActivity"
/> <Button
android:id="@+id/start_dialog_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start dialogActivity"
/>

最后改动MainActivity中的代码:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Button startNormalActivity = (Button) findViewById(R.id.start_normal_activity);
Button startDialogActivity = (Button) findViewById(R.id.start_dialog_activity); startNormalActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, NormalActivity.class);
startActivity(intent);
}
}); startDialogActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, DialogActivity.class);
startActivity(intent);
}
}); } @Override
protected void onStart(){
super.onStart();
Log.d(TAG, "onStart");
} @Override
protected void onResume(){
super.onResume();
Log.d(TAG, "onResume");
} @Override
protected void onPause(){
super.onPause();
Log.d(TAG, "onPause");
} @Override
protected void onStop(){
super.onStop();
Log.d(TAG, "onStop");
} @Override
protected void onDestroy(){
super.onDestroy();
Log.d(TAG, "onDestory");
} @Override
protected void onRestart(){
super.onRestart();
Log.d(TAG, "onRestart");
}
}

跑路。顺带观察一下logcat:

好了,你如今已经体验了一遍完整的生命周期。

我碰到了一个问题,start_dialog_activity这个button运行时除了错,原因是给dialog这个activity的theme里面的属性和DialogActivity继承的一个AppCompatActivity类不兼容,所以仅仅要把继承的AppCompatActivity改为Activity就能够了。


[活动被回收怎么办?]

当一个活动进入到了停止状态。有可能被系统回收。这样的话。返回之前的处于停止状态的活动是能够的。仅仅只是不会运行onRestart() 方法而是运行的onCreate()方法,也就是说这样的情况下,返回之前 被回收的活动是会被又一次创建的。

只是问题来了,这样暂时的数据会丢失,只是问题不大。Activity中提供了onSaveInstanceState()回调方法。这种方法能够保证在活动被回收之前一定被调用,因此我们能够通过这种方法来保存暂时数据。

onSaveInstanceState()方法携带一个Bundle类型的參数,Bundle类提供了一些列方法保存数据,putString)(),putInt()等等,每一个保存方法须要传入两个參数,第一个參数是键。用于取值,第二个是真正要保存的数据。

和Intent的几乎相同。

MainActivity:

    protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Something i just typed";
outState.putString("data_key",tempData);
}

保存完数据,可是该怎样取出数据呢?

onCreate()方法中有一个Bundle类型的參数。就靠它

MainActivity:

Log.d(TAG, "onCreate");
if(savedInstanceState != null){
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG,tempData);
}

并且我们还能够将Bundle对象存放在Intent中。到了目标活动中再取出Bundle,再从Bundle中一一取出数据。


[活动的启动模式]

启动模式分为四种:

  1. standard
  2. singleTop
  3. singleTask
  4. singleInstance

能够在androidManifest.xml中通过给标签中指定android:launchMode属性来选择。


1.standard

活动默认的启动模式。因此,我们之前所使用过的都是standard模式。

每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于standard模式下的活动,系统不会在乎这个活动是否已在返回栈中存在。每次启动都会创建该活动的一个新的实例。

打开之前的ActivityTest项目。

改动FirstActivity:

public class FirstActivity extends AppCompatActivity {

    private static final String Tag = "FirstActivity";

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.first_layout); Log.d(Tag, this.toString());
Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Toast.makeText(FirstActivity.this, "You click me", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(FirstActivity.this , FirstActivity.class);
startActivity(intent);
}
}); Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
String data = "Hello huchi";
Intent intentString = new Intent(FirstActivity.this, SecondActivity.class);
intentString.putExtra("extra_data",data);
//startActivity(intentString);
startActivityForResult(intentString, 1); }
}); Button button4 = (Button) findViewById(R.id.button_4);
button4.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intentSecond = new Intent("com.example.wrjjrw.activitytest.ACTION_START");
intentSecond.addCategory("com.example.wrjjrw.activitytest.MY_CATEGORY");
intentSecond.putExtra("extra_data","error");
startActivity(intentSecond);
}
}); Button button5 = (Button) findViewById(R.id.button_5);
button5.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intentToBaidu = new Intent(Intent.ACTION_VIEW);
intentToBaidu.setData(Uri.parse("http://blog.csdn.net/jaywrzz/article/details/65937639"));
startActivity(intentToBaidu);
}
});
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(this, "You clicked Remove" ,Toast.LENGTH_SHORT).show();
break;
case R.id.huchi_item:
Toast.makeText(this, "I love huchi,too", Toast.LENGTH_LONG).show();
break;
default:
}
return true;
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case 1:
if(resultCode == RESULT_OK){
String returnedData = data.getStringExtra("data_return");
Log.d("FirstActivity",returnedData);
}
break;
default:
}
}
}

我们看到他能够启动他自己,跑路。

03-30 12:38:54.424 7273-7273/com.example.wrjjrw.activitytest D/FirstActivity: com.example.wrjjrw.activitytest.FirstActivity@42900c50
03-30 12:38:59.485 7273-7273/com.example.wrjjrw.activitytest D/FirstActivity: com.example.wrjjrw.activitytest.FirstActivity@4293a0c8

发现假设打开它自己三下,也就须要

2.singleTop

似乎standard不是非常合理。singleTop在启动活动时假设发现返回栈的栈顶已是该活动。则觉得能够直接使用它,不会再创建新的活动实例。

改动AndroidManifest.xml

        <activity
android:name=".FirstActivity"
android:launchMode="singleTop"
android:label="This is huchi&apos;s FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

发现无论点多少次logcat都没有信息打印了。

只是在FirstActivity并未处于栈顶时。这时再启动FirstActivity,还是会创建新的实例的。

我们发如今FirstActivity和SecondActivity两个活动中跳来跳去能够在logcat看到打印的消息。


3.singleTask

singleTask模式能够解决上述问题。每次启动活动时,系统会在返回栈中检查是否存在该活动的实例。假设发现已经存在则直接使用该实例,并把在这个活动上面的全部活动统统出栈,假设没有发现就会创建一个新的活动实例。

改动FirstActivity:

    @Override
protected void onRestart() {
super.onRestart();
Log.d(Tag, "onRestart");
}

改动SecondActivity,加入onDestroy():

public class SecondActivity extends AppCompatActivity {

    private static  final  String Tag = "SecondActivity";
// @Override
// public void onBackPressed() {
// Intent intent = new Intent();
// intent.putExtra("data_return", "back_to_firstActivity");
// setResult(RESULT_OK, intent);
// finish();
// } @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second); Button button3 = (Button) findViewById(R.id.button_3);
button3.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intentFirst = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intentFirst);
}
}); Button buttonFinishSecond = (Button) findViewById(R.id.button_finish);
buttonFinishSecond.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent();
intent.putExtra("data_return","byebye huchi");
setResult(RESULT_OK, intent);
finish();
}
}); Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Log.d("SecondActivity",data); } @Override
protected void onDestroy() {
super.onDestroy();
Log.d(Tag, "onDestroy");
}
}

跑路。观察logcat


4.singleInstance

最特殊最复杂的模式。

会启动一个新的返回栈来管理这个活动(假设singleTask模式下指定了不同的taskAffinity).singleInstance 能够实现其它程序和我们的程序共享一个活动的实例。在这样的模式下会有一个单独的返回栈来管理这个活动,无论是哪个应用程序来訪这个活动。都公用同一个返回栈。

实践出真知:

改动AndroidManifest.xml:

        <activity android:name=".SecondActivity"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="com.example.wrjjrw.activitytest.ACTION_START" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="com.example.wrjjrw.activitytest.MY_CATEGORY" />
</intent-filter>
</activity>

FirstActivity:

        Log.d(Tag, "Task id is " + getTaskId());

        Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Toast.makeText(FirstActivity.this, "You click me", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(FirstActivity.this , SecondActivity.class);
startActivity(intent);
}
});

改动SecondActivity:

        Log.d(Tag, "Task id is "+ getTaskId());

        Button button3 = (Button) findViewById(R.id.button_3);
button3.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intentFirst = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intentFirst);
}
});

activity_third:

    <Button
android:id="@+id/button_to_first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="return first"
></Button>

改动ThirdActivity

        Log.d(Tag, "Task id is "+ getTaskId());

        Button button3 = (Button) findViewById(R.id.button_3);
button3.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intentFirst = new Intent(SecondActivity.this, ThirdActivity.class);
startActivity(intentFirst);
}
});

我们发现从FirstActivity跳转到SecondActivity。再跳转到ThirdActivity后,此时按back键返回回到的就是FirstActivity。


[实践出真知]

[知晓当前是哪一个活动?]

在集体编程时。可能会找不到界面相应的活动。

新建一个BaseActivity:

public class BaseActivity extends AppCompatActivity {

    private static final String Tag = "BaseActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(Tag, getClass().getSimpleName());
}
}

由于BaseActivity继承的是AppCompatActivity,我们能够让其它三个活动继承BaseActivity。也就是说其它活动onCreate的时候,就会运行父类的onCreate,也就都会运行Log.d(Tag, getClass().getSimpleName());这句话,然后我们就知道哪个界面相应的是哪个活动了。

03-30 14:09:16.085 9459-9459/com.example.wrjjrw.activitytest D/BaseActivity: FirstActivity
03-30 14:09:19.440 9459-9459/com.example.wrjjrw.activitytest D/BaseActivity: SecondActivity
03-30 14:09:21.617 9459-9459/com.example.wrjjrw.activitytest D/BaseActivity: ThirdActivity

[随时随地退出程序]

仅仅须要一个专门的集合类对全部的活动进行管理。

BaseActivity:


public class ActivityCollector { public static List<Activity> activities = new ArrayList<>(); public static void addActivity(Activity activity){
activities.add(activity);
} public static void removeActivity(Activity activity){
activities.remove(activity);
} public static void finishAll(){
for(Activity activity: activities){
if(!activity.isFinishing())
activity.finish();
}
} }

BaseActivity:

public class BaseActivity extends AppCompatActivity {

    private static final String Tag = "BaseActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(Tag, getClass().getSimpleName());
ActivityCollector.addActivity(this);
} @Override
protected void onDestroy(){
super.onDestroy();
ActivityCollector.removeActivity(this);
} }

这样就能够把存在的活动放在一个数组里。

以后无论想在什么时候地方退出程序。仅仅要调用ActivityCollector.finishAll().

    public static void finishAll(){
for(Activity activity: activities){
if(!activity.isFinishing())
activity.finish();
}
android.os.Process.killProcess(android.os.Process.myPid());
}

我进行了一番尝试:

        Button button10 = (Button) findViewById(R.id.button_to_finish);
button10.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
ActivityCollector.finishAll();
}
});

美好的。

[启动活动的最佳写法]

尽管我们写的intent无论是语法上还是规范上都符合。但在对接的时候总是会有疑问???不清楚这个活动须要哪些数据。

改动SecondActivity:

    public static void actionStart(Context context, String data1, String data2){
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("param1",data1);
intent.putExtra("param2",data2);
context.startActivity(intent);
}

改动FirstActivity:

        Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Toast.makeText(FirstActivity.this, "You click me", Toast.LENGTH_SHORT).show();
SecondActivity.actionStart(FirstActivity.this, "data1", "data2");
}
});

[问题]

问:为啥我自己主动生成的都不是Linearlayout?

答:Click me,下一次学习笔记中将详细学习。

问:啥是taskAffinity?

答:Click me.

最新文章

  1. PHP收藏
  2. Java 获取当前系统时间方法比较
  3. 【jquery】基于 jquery 实现 ie 浏览器兼容 placeholder 效果
  4. Android Studio 初级安装
  5. Java基础类库
  6. Python 的列表解析和生成表达式的异同
  7. 教你使用Android SDK布局优化工具layoutopt
  8. 动态上传多个文件(asp)
  9. Tomcat 6 支持 NIO -- Tomcat的四种基于HTTP协议的Connector性能比较(转载)
  10. 在Lambda表达式中使用循环变量
  11. 利用jQuery接受和处理xml数据
  12. web开发相关
  13. [进程管理] Linux中Load average的理解
  14. bootstrap-paginator分页示例 源码 MVC
  15. virtual 函数只有在用指针或引用的方式访问,才会导致多态。
  16. 惊闻企业Web应用生成平台 活字格 V4.0 免费了,不单可视化设计器免费,服务器也免费!
  17. 【剑指offer】输出链表倒数第K个元素
  18. HTML元素ID和JS方法名重复,JS调用失败
  19. ubuntu-16.04.1-desktop-amd64.iso:ubuntu-16.04.1-desktop-amd64:安装Oracle11gR2
  20. FastAdmin composer json 版本说明

热门文章

  1. vlc模块间共享变量
  2. OPENERP 构建动态视图
  3. 干货首发,能够清理,带动画的自己定义控件CuteEditText
  4. js获取事件源及触发该事件的对象
  5. 偏最小二乘回归(PLSR)- 1 概览
  6. Android高效异步图片加载框架
  7. Zoie中文文档及简单解析
  8. JavaScript常用語句
  9. MVC之Ajax.BeginForm使用详解之更新列表 mvc验证jquery.unobtrusive-ajax
  10. MFC显示GIF动画图片