说说 Activity 那些事

hany 8年前
   <p>Activity就是每一个应用的界面,凡事显示在app中的界面都是Activity或者由Activity启动。</p>    <h3>基本使用</h3>    <ul>     <li>使用as快捷建立Activity</li>    </ul>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0f1e256ae8509094bc48fdf2f1086704.png"></p>    <ul>     <li>常规创建</li>    </ul>    <ol>     <li>在app/src/main/AndroidManifest.xml注册</li>     <li>编写java代码继承自Activity或者它的子类</li>    </ol>    <p>自动创建的Activity如下所示:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/604488f7a2cd06ea8231be2d50c4981d.png"></p>    <p>就是一个activity的标签</p>    <h3>传递数据</h3>    <p>我们现在创建两个Activity由MainActivity向SecondActivity传递一个字符串“HelloWorld”</p>    <ul>     <li>在MianActivity中设置带有数据的intent</li>    </ul>    <p style="text-align:center"><img src="https://simg.open-open.com/show/50a731931713a429a24d0e6d7fadd16b.png"></p>    <ul>     <li>startActivityForResult启动activity,第二个参数是请求码</li>     <li>重写onActivityResult接受数据</li>    </ul>    <p>SecondActivity</p>    <pre>  <code class="language-java">setResult(666);          String hello = getIntent().getBundleExtra("hello").getString("nihao");</code></pre>    <p>设置结果码—>拿到数据</p>    <h3>完整代码</h3>    <pre>  <code class="language-java">public class MainActivity extends AppCompatActivity {        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);      }  //在按钮中注册的方法      public void start(View view) {          Intent intent = new Intent(MainActivity.this, SecondActivity.class);          Bundle bundle = new Bundle();          bundle.putString("nihao", "HelloWorld");          intent.putExtra("hello", bundle);          startActivityForResult(intent, 0);      }        @Override      protected void onActivityResult(int requestCode, int resultCode, Intent data) {          if (resultCode == 666) {              System.out.println("世界你好");          }      }  }        public class SecondActivity extends AppCompatActivity {        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_second);            setResult(666);          String hello = getIntent().getBundleExtra("hello").getString("nihao");            TextView textView = (TextView) findViewById(R.id.tv);          textView.setText(hello);      }    //在按钮中注册的方法      public void finsh(View view) {          this.finish();      }  }</code></pre>    <h2>生命周期</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/11bf721965aff48bccaf026a33266e1b.png"></p>    <ol>     <li>onCreate方法负责初始化数据、视图、绑定事件的监听</li>     <li>onStart和onStop是从是否可见的角度分析</li>     <li>onResume和onPause是从是否在前台的角度分析</li>     <li>onStart可见不能获得焦点—>onResume可见能获得焦点—->onPause可见不能获得焦点—->onStop不可见不能获得焦点</li>    </ol>    <p>Android官方周期</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0861913975a197c753928d46743785b0.png"></p>    <h3>正常的生命周期</h3>    <p>onCreate—->onStart——>onResume——>onPause—–>onStop—–onDestory正好6个生命周期</p>    <p><img src="https://simg.open-open.com/show/c8ab9da93b1952cb185afd714823cdaa.png"></p>    <h3>异常生命周期</h3>    <p>用户按主页键</p>    <p><img src="https://simg.open-open.com/show/8a8e5ac6f5929ee88585b7994e557d60.png"></p>    <p>然后再次返回这个activity:</p>    <p><img src="https://simg.open-open.com/show/f69745f8af0ac4edc57dde3e3ca5f440.png"></p>    <p>突然来一个电话</p>    <p><img src="https://simg.open-open.com/show/b9f0114bac7792e2b470d8259e502a15.png"></p>    <p>生命周期和上面的一样</p>    <p>当要启动的另一个Activity主题色是透明的时候那么这时这个Activity不会调用onStop方法</p>    <p>也就是说它还可见,符合逻辑</p>    <p>系统配置改变比如说屏幕旋转</p>    <p><img src="https://simg.open-open.com/show/e882f34d4eb84b06f314546300f78281.png"></p>    <p>当前的Activity被销毁重新创建</p>    <p>在屏幕旋转的时候会调用onSaveInstanceState和onRestoreInstanceState用来保存和恢复组件的状态(注意as默认创建的Activity继承自AppCompatActivity,这里的两个方法要使用使用AppCompatActivity中的)</p>    <p>当状态改变调用onSaveInstanceState保存状态然后调用onRestoreInstanceState恢复状态:</p>    <p><img src="https://simg.open-open.com/show/339dd3d9d2a022aa78743e3ed27ec06d.png"></p>    <p>旋转屏幕时状态分析</p>    <p>当屏幕发生旋转后数据会保存到savedInstanceState和onCreate方法中的savedInstanceState</p>    <pre>  <code class="language-java">protected void onRestoreInstanceState(Bundle savedInstanceState)</code></pre>    <p><img src="https://simg.open-open.com/show/693d616af7e64cd8995b9bac668d8086.png"></p>    <p>橙色线表示屏幕旋转</p>    <p>那么会保存view的哪些信息呢?这要看对应的view的onSaveInstanceState方法,比如EditText的正在编辑的信息就会丢失。</p>    <p>那么怎么屏蔽屏幕旋转的信息呢???</p>    <p style="text-align: center;">—————–看法宝——————-</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/11ff08057a64158186b25d063c17e5d2.png"></p>    <p>只要在activity注册的时候加入configChanges标签就可以,注意假如是屏蔽旋转的话应该是orientation|screenSize两个属性</p>    <p><img src="https://simg.open-open.com/show/36e4d681b76bc82bb8b303fd1d0d8160.png"></p>    <p>从此妈妈再也不用担心我的学习了,哈哈哈!!!!</p>    <p>####锁屏和屏幕解锁</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/060c2a264e1f328337d6cce96be33c22.png"></p>    <p>只是调用了onPause和onStop没有销毁Activity</p>    <p>###可见性</p>    <p>activity的完整生存期会在 onCreate() 调用和 onDestroy() 调用之间发生。</p>    <p>activity的可见生存期会在 onStart() 调用和 onStop() 调用之间发生。系统会在activity的整个生存期内多次调用 onStart() 和onStop(), 因为activity可能会在显示和隐藏之间不断地来回切换。</p>    <p>activity的前后台切换会在 onResume() 调用和 onPause() 之间发生。 因为这个状态可能会经常发生转换,为了避免切换迟缓引起的用户等待,这两个方法中的代码应该相当地轻量化。</p>    <h3>activity回收和保存信息</h3>    <p>onSaveInstanceState方法</p>    <p>在activity 可能被回收之前 调用,用来保存自己的状态和信息,以便回收后重建时恢复数据(在onCreate()或onRestoreInstanceState()中恢复)。旋转屏幕重建activity会调用该方法,但其他情况在onRause()和onStop()状态的activity不一定会调用 ,下面是该方法的文档说明。</p>    <p>系统灵活的来决定调不调用该方法, 但是如果要调用就一定发生在onStop方法之前,但并不保证发生在onPause的前面还是后面。</p>    <p>onRestoreInstanceState方法</p>    <p>这个方法在onStart 和 onPostCreate之间调用,在onCreate中也可以状态恢复,但有时候需要所有布局初始化完成后再恢复状态。</p>    <h2>启动模式</h2>    <p>就是启动Activity的方式:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/866827a548dcdbb1bd306663ced0c176.png"></p>    <p>只要在Activity中指定launchMode属性就可以完成启动模式的改变。</p>    <p>在上面的案例中我们从MainActivity到SecondActivity有木有发现不按下结束键只是返回也能返回到MainActivity,我擦MainActivty那家伙还活着呢??让我们探究下正常的启动模式</p>    <h3>正常的启动模式</h3>    <p><img src="https://simg.open-open.com/show/eab0fb3c55cbd9c57cd1f241bf4de59a.png"></p>    <p>就是先启动的Activity先入栈,出栈是最后出栈,所以当SecondActivity死后,可以看见MianActivity,在MainActivity中添加一个不断重新启动自己的button</p>    <p>然后进入Terminal:adb shell 然后dumpsys activity</p>    <p>查看当前运行的activity:</p>    <p><img src="https://simg.open-open.com/show/77d0f2759e65a553ddce34dbe9ab0951.png"></p>    <p>每一个都在栈中。</p>    <p>新建一个Activity2项目在其中只是设置一个按钮,启动Activity项目中的MianActivity:</p>    <p><img src="https://simg.open-open.com/show/36101febfc23d80af637460a1cf5a27a.png"></p>    <p>发现Activity中的Mian在项目2的栈内,于是有一个结论:</p>    <p>正常模式启动的Activity,谁启动它,它就在那一个栈</p>    <p>跨应用启动Activity代码</p>    <pre>  <code class="language-java">Intent intent = new Intent();     intent.setClassName("win.haotinayi.activity","win.haotinayi.activity.MainActivity");</code></pre>    <p>就是设置包名,在设置Activity的全名</p>    <h3>SingleTop</h3>    <p>就是当要启动的Activity恰好在栈顶的时候,那么就不再重复创建:</p>    <p><img src="https://simg.open-open.com/show/62c56c4172f56ca84ca933925554c223.png"></p>    <p>无论怎么启动都只有一个实例。</p>    <h3>SingleTask</h3>    <p>栈内单例模式,分为三种情况:</p>    <ol>     <li>当有Activity需要的栈时,并且是栈顶,啥也不说了,直接复用</li>     <li>当有Activity需要的栈时,并且不是栈顶,那么在它上面的全部干掉,自己当大哥</li>     <li>当没有Activity需要的栈时,创建栈</li>    </ol>    <p>把MianActivity设置成SingleTask模式,首先打开Activity项目,让两个Activity同时存在:</p>    <p><img src="https://simg.open-open.com/show/eab0fb3c55cbd9c57cd1f241bf4de59a.png"></p>    <p>并且MianActivity不是栈顶,然后在通过Activity2打开MainActivity:</p>    <p><img src="https://simg.open-open.com/show/48d345972cc1d0945bc31e83fd5ab1da.png"></p>    <p>SecondActivity被干掉了,大哥是MianActivity,那么什么是Activity的需要栈呢? <strong>默认是包名</strong></p>    <p>使用属性taskAffinity可以改掉,现在来一个恶作剧:</p>    <p><img src="https://simg.open-open.com/show/7eda0d5a3394f48291fd96675d4472a5.png"></p>    <p>这时再次启动项目发现,项目的栈改变了:</p>    <p><img src="https://simg.open-open.com/show/f76e42e96cdfa7877d65ccc6754d7446.png"></p>    <h3>SingleInstance</h3>    <p>Activity只能单独存在一个栈中,换句话说就是整个手机就你一个实例</p>    <h3>使用Intent来标示启动模式</h3>    <pre>  <code class="language-java">Intent intent = new Intent(MainActivity.this, SecondActivity.class);          intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);          startActivity(intent);</code></pre>    <p>####标志的分类</p>    <ul>     <li>FLAG_ACTIVITY_NEW_TASK</li>    </ul>    <p>与”singleTask”模式相同,在新的 task 中启动 activity。如果要启动的 activity 已经运行于某 task 中,则那个 task 将调入前台。</p>    <ul>     <li>FLAG_ACTIVITY_SINGLE_TOP</li>    </ul>    <p>与 “singleTop”模式相同,如果要启动的 activity位于back stack 顶,系统不会重新创建目标Activity实例,而是直接复用Task栈顶的Activity。</p>    <ul>     <li>FLAG_ACTIVITY_CLEAR_TOP</li>    </ul>    <p>此种模式在launchMode中没有对应的属性值。如果要启动的 activity 已经在当前 task 中运行,则不再启动一个新的实例,且所有在其上面的 activity 将被销毁。</p>    <h2>Activity优先级</h2>    <p>从高到低排序:</p>    <ol>     <li>显示且能获得焦点(前台)的Activity</li>     <li>显示不能获得焦点(非前台),一个打开Dialog的Activity</li>     <li>不可见,已经处于暂停或者直接onStop后的Activity</li>    </ol>    <p>当内存不足的时候低优先级的Activity就会被杀掉,如果一个组件没有放在四大组件中,那么很快被杀死,所以后台任务最好放到一个四大组件中,防止被干掉。</p>    <h2>注意</h2>    <h3>Activity的全屏</h3>    <pre>  <code class="language-java">// 去除标题栏          requestWindowFeature(Window.FEATURE_NO_TITLE);          setContentView(R.layout.activity_main);          getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);</code></pre>    <p>requestWindowFeature要在setContentView调用之前否则会崩溃</p>    <h3>Activity的公开性</h3>    <p>一般设置Activity为非公开的</p>    <pre>  <code class="language-java"><activity    ......   android:exported="false" /></code></pre>    <p>注意:非公开的Activity不能设置intent-filter,以免被其他activity唤醒(如果拥有相同的intent-filter)。</p>    <p> </p>    <p>来自:http://haotianyi.win/2017/03/01/01-说说Activity那些事/</p>    <p> </p>