续第二课( 下)

写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.

android从放弃到坚持放弃第二课(下)的更多相关文章

  1. 【Android开发学习笔记】【第二课】Activity学习

    什么是Activity,就是我们所看到的 需要理解以下四句话: 1.一个Activity就是一个类,并且这个类需要集成Activity: 2.需要重写OnCreat方法 3.每个Activity都需要 ...

  2. Android OpenGL教程-第二课【转】

    第二课 你的第一个多边形: 在第一个教程的基础上,我们添加了一个三角形和一个四边形.也许你认为这很简单,但你已经迈出了一大步,要知道任何在OpenGL中绘制的模型都会被分解为这两种简单的图形. 读完了 ...

  3. Android之ViewPager 第二课

    在这里只粘贴部分代码 在第一课中,只有View滑动完毕,才触发动画效果,令滑块移动,在第二课中,将实现滑块与View同步运行. SecondActivity.java package com.andr ...

  4. 【第二课】深入理解Handler

    简要讲解Handler是做什么的 我们知道,在Android中,app启动会启动一个进程一个线程——UI线程,UI线程是主线程,并且不允许这个线程阻塞超过5秒,一旦超过5秒就会ANR. 所以较为耗时的 ...

  5. Kotlin入门第二课:集合操作

    测试项目Github地址: KotlinForJava 前文传送: Kotlin入门第一课:从对比Java开始 初次尝试用Kotlin实现Android项目 1. 介绍 作为Kotlin入门的第二课, ...

  6. CI(CodeIgniter)框架入门教程——第二课 初始MVC

    本文转载自:http://www.softeng.cn/?p=53 今天的主要内容是,使用CodeIgniter框架完整的MVC内容来做一个简单的计算器,通过这个计算器,让大家能够体会到我在第一节课中 ...

  7. OpenCV 第二课 认识图像的存储结构

    OpenCV 第二课 认识图像的存储结构 Mat Mat 类包含两部分,矩阵头和矩阵体.矩阵头包含矩阵的大小,存储方式和矩阵体存储空间的指针.因此,Mat中矩阵头的大小是固定的,矩阵体大小是不定的. ...

  8. Kali Linux Web 渗透测试视频教程— 第二课 google hack 实战

    Kali Linux Web 渗透测试— 第二课 代理简介 文/玄魂 课程地址: http://edu.51cto.com/course/course_id-1887.html 目录 shellKal ...

  9. ruby代码重构第二课

    (文章都是从我的个人主页上粘贴过来的, 大家也可以访问我的主页 www.iwangzheng.com) 在第一课里提取出了相通的代码,第二课里就把常量提取出来吧 一般把常量的定义写的对应的app/mo ...

随机推荐

  1. com.tongyan.tutelage:bdservice_v1

    3-21 10:14:20.833 2892-2892/? E/art: No implementation found for long com.baidu.platform.comjni.map. ...

  2. 从chrome商店直接下载crx文件

      从chrome商店直接下载crx文件 CreateTime--2018年5月21日17点18分 Author:Marydon 1.前提 需要知道你所下载的插件的id 查看方法: 第一步:打开扩展程 ...

  3. eclipse中查看某个方法(函数)被谁调用

    用了好久一直不知道eclipse中怎样实现vs中查找全部引用的功能,今天最终发现了哈哈 选中要查找的方法名,右键->References->Workspace 能够定位到详细的调用位置,快 ...

  4. BZOJ 1603 [Usaco2008 Oct]打谷机 dfs

    题意:id=1603">链接 方法:暴力 解析: 搜1到n路径上的边权异或和-. 这几个水题刷的我有点-.. 代码: #include <cstdio> #include ...

  5. tomcat的web项目的远程热发布

    已经发布的项目war包更改了怎么办?我常用的做法是: .把war包上传服务器 .远程登录服务器后台 .停止tomcat服务 .用新的war包替换老的war包 .启动tomcat服务 后来才知道原来to ...

  6. CUGBACM Codeforces Tranning 3 题解

    链接:http://acm.hust.edu.cn/vjudge/contest/view.action? cid=62515#overview 描写叙述:第三场CF训练了.这次做的挺搞笑的,我记得这 ...

  7. Atitit.web预览播放视频的总结

    Atitit.web预览播放视频的总结 1. 浏览器类型的兼容性(chrome,ff,ie) 1 2. 操作系统的兼容性 1 3. 视频格式的内部视频格式跟播放器插件的兼容性.. 2 4. 指定播放器 ...

  8. Virtex6 PCIe 超简版基础概念学习(二)

    Virtex6 PCIe 超简版基础概念学习(二) 分类:FPGAPCIe (2081)  (0)  举报  收藏 文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 ise14.7 ...

  9. 每日英语:Air Pollution From Coal Use Cuts Lifespans in China, Study Shows

    Air pollution from coal combustion likely cut life expectancy in parts of China by more than five ye ...

  10. 实现在edittext中任意插入图片

    Myedittext: public class MyEditText extends EditText { public MyEditText(Context context) { super(co ...