Android基础 - Activity

作者: Allens_Jiang | 来源:发表于2017-12-25 16:20 被阅读49次
老婆保佑,代码无BUG

目录

  • 生命周期
  • Activity保存当前状态
  • Activity之间的跳转
  • Activity 参数 回传
  • 启动模式
  • Activity完美退出的方法

一.Activity生命周期

一上来就是生命周期图,多少小伙伴,看到就头疼,不说了,都是泪啊。。。。


activity.png

独家解析,谈谈我的理解方式

  • onCreate()
    在Activity被创建时回调;这个不要多说
  • onStart()
    在Activity画面可视之前被回调,就是你能看到之前
  • onResume()
    在Activity界面可互动之前被回调,你现在可以随便点击了
  • onPause()
    回调后Activity不再可互动; 你现在不能点击了,没办法做交互
  • onStop()
    回调后Activity不再可视,你就看不到了
  • onDestroy()
    回调后Activity被销毁

是不是以一一对应的关系,这样记得话 我感觉很容易理解, 又方便记忆

撸一撸启动时候的生命周期怎么走

一个Activity的启动顺序

onCreate()——>onStart()——>onResume()

当另一个Activity启动时

第一个Activity onPause()——>
    第二个Activity             onCreate()——>
                              onStart()——>
                              onResume() ——>
第一个Activity onStop() 

当返回到第一个Activity时

第二个Activity onPause() ——> 
         第一个Activity onRestart()——>
                       onStart()——>
                       onResume() ——>
第二个Activity onStop()——>
              onDestroy()

用户按下Back键返回

onPause()——>onStop() 

如果新的Activity设置了透明主题,不会回调onStop() 透明主题看不到不代表没有啊

二.Activity保存当前状态

  • onSaveInstance
  • onRestoreInstance

这两个方法先有个印象,在应用程序设置改变(比如竖屏变横屏)、在内存不足需要腾出内存时,一个Activity可能被系统杀死(可能在之后重新启动),这时可能会造成信息的丢失,比如控件里暂时存放的数据、Activity对象里的属性值都会在Activity被系统杀死时丢失。 可以用onSaveInstance和onRestoreInstance来解决这个问题

来个例子

public class MainActivity extends Activity {
    private Button button;
    private TextView tv;
    private int num;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.button1);
        tv = (TextView) findViewById(R.id.textView1);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {//按钮一被点击
                num ++;//数字+1
                tv.setText(Integer.toString(num));//显示到TextView
            }
        });
    }
    //在Activity可能被系统杀死时回调,用来保存杀死前的一些状态,以便以后再启动时将保存下来的状态恢复到新的Activity
    //那些有id的控件的状态会默认被保存,在之后调用onRestoreInstanceState时再自动恢复
    //但是Activity类中的属性的值不会被自动保存,需要我们手动保存,保存到参数Bundle outState中
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);//这句是继承下来的默认逻辑,不要删除
        //将属性num的值以键值对的形式放进outState,键是一个字符串,名字随便起,但要见名知意,值就是要保存的值
        outState.putInt("number", num);//放进去以后即使这个Activity被销毁,这个Bundle里面的信息会被系统保存下来
    }
    //横竖屏切换Activity被杀死后,会马上再创建一个Activity,会回调这个方法去恢复原来丢失的信息
    //有id的控件的状态会自动恢复,但Activity属性的值需要我们在这个方法里手动恢复
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        //从系统维护的Bundle对象中取出之前保存进去的值,第一个参数是键,第二个参数是没有这个键值对情况下的默认值
        int n = savedInstanceState.getInt("number", 0);
//      tv.setText(Integer.toString(n));//将从Bundle中取出的数字转为字符串设置到TextView中
        num = n;//属性也要设置为取出来的值
    }
}

ps: 这排版看着怎么就那么难受呢 = =

三.Activity之间的跳转

activity之间的跳转,一般肯定用intent,至于不一般,在组件化中会使用路由,这玩意,还真是TM 挺麻烦的

(1)显示跳转

startActivity(new Intent(MainActivity.this,SecondActivity.class))

别忘了在manifest 添加activity

(2) 隐身跳转

在清单文件中注册action

  <activity android:name=".KfcActivity">
            <!-- 将这个KdfActivity的功能注册为吃,具体为com.qianfeng.EAT -->
            <intent-filter>
                <!-- 动作注册为com.qianfeng.EAT,一个这样的意图发给操作系统时,操作系统会找到这个符合条件的Activity并启动 -->
                <action android:name="com.allens.EAT"/>
                <category android:name="android.intent.category.DEFAULT"/><!-- 这个分类一定要写,不然会出错 -->
            </intent-filter>
        </activity>

activity中代码

Intent intent = new Intent("com.allens.EAT");// 创建一个意图,action为com.qianfeng.EAT
startActivity(intent);// 启动意图动作为com.qianfeng.EAT的一个Activity
// 启动后会将意图提交给操作系统,操作系统会在所以清单中扫描有没有一个Activity的action注册为com.qianfeng.EAT
// 如果有,就启动;如果一个也没有,就出错

如果有两个不同的Activity,拥有相同的action,系统会让用户去选择去哪个Activity

四.跳转传值

intent 传值

// 传递参数
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
intent.putExtra("allens", s);
startActivity(intent);


//获取参数
String str = intent.getStringExtra("allens");

Bundle

Bundle bundle = new Bundle();
//往这个Bundle对象里以键值对形式放置信息
bundle.putString("inputtext", s)
//将这一捆信息一下子放进意图对象
intent.putExtras(bundle);

当然啦,一般我们都会传一些比较复杂的对象,比如在网络获取到的数据,需要调到一个详情界面,需要把获得的数据全部调到其他界面,简单来说,就是如何传递对象

这里给出两个东东

  • Parcelable
  • Serializable
    这两个都是接口,将对象序列化,然后传递到第二个Activity的

使用说明

//传递对象
  Bundle bundle = new Bundle();
  bundle.putSerializable("bundle_ser",person);//Parcelable 序列化对象
  intent.putExtras(bundle);


//获取对象
 Pen pen = (Pen)getIntent().getParcelableExtra("parcel_test");
intent.putExtra("tag1",data);// 序列化对象
Person per = (Person)intent.getSerializableExtra("tag1");

ps(大写的注意): 需要传递的对象都需要实现序列化接口,Android 中最好使用 Parcelable

至于二者的区别,我会在后期的文章中解释. 预知后事如何,请听下回分解


五.Activity 参数 回传

先记得这两个方法,后面解释

  • startActivityForResult
  • onActivityResult

有时候吧,我们需要一些参数,但是这些参数需要从第二个Activity中回传过来,哈哈,有借有还再借不能,PS 大兄弟们,救济救济我啊。。。最近穷死了 , 大写的哭

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, TwoActivity.class);
        //这里采用startActivityForResult来做跳转,此处的0为一个依据,可以写其他的值,但一定要>=0
        startActivityForResult(intent, 999);
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //startActivityForResult 中的参数要相同
        if (requestCode == 999) {
            //和setResult中的参数相同
            if (resultCode == 110) {
                String data1 = data.getStringExtra("data");
                Log.e("TAG", "data--->" + data1);
            }
        }
    }
}

public class TwoActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent();
        intent.putExtra("data", "测试的参数");
        //intent为A传来的带有Bundle的intent,当然也可以自己定义新的Bundle
        setResult(110, intent);
        finish();//此处一定要调用finish()方法
    }
}

六. 启动模式

这个问题,真心每次面试都会被问到,无奈

Activity 有4中启动模式,先说一下,然后慢慢解释

  • standard
  • singletop
  • singleTask
  • singleInstance

standard

默认的启动模式,也是标准的启动模式,打个比方,现在我们点击Button,启动当前的Activity,假设为Activity 的名字叫 A。 那么在任务栈中 就是
A A A A A A ......

稍等我一会,我去画个图 。说明一下

等待20分钟...


这太TM难画了

本着先后出的原则,任务栈中就是这样的,如果你想回退的话,只能 A3现出来,然后A2...

singletop

栈顶的两个Activity不会一样,如果栈顶有activity的实例, 则不需重新创建(只要不在栈顶就需要创建),可重用该实例,不过会调用onNewIntent()方法,如果栈顶不存在就重新创建新的实例并放入栈顶

在等我20分钟

不想吐槽了

看图,如果先启动A 然后启动 B 在启动A 那么任务栈中 是 A1 B A2 (从下往上看),如果此时 我们再次启动A 那么并不会想standard那样 再次启动一个 A 放入栈中,栈顶只有一个A 的实例,这就是singletop

singleTask

设置了singtask的Activity如果再一次启动,它就必须在最上面,如果有其他的在ta上面就会被弹出

这个不画图了,太丑了,我看不下去

意思很简单,谁设置了, 谁是老大,在栈顶

singleInstance

这种启动模式比较特殊,因为它会启用一个新的栈结构,将Acitvity放置于这个新的栈结构中,并保证不再有其他Activity实例进入。

扯了这么多,MD 怎么用啊!!!!!!!!

  • AndroidManifest.xml配置

launchMode 属性就是对应的启动模式

<activity
            android:name=".SingleInstanceActivity"
            android:label="singleInstance launchMode"
            android:launchMode="singleInstance"
            android:taskAffinity="">
  • Intent Flags设置
Intent intent = new Intent(StandardActivity.this, StandardActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

七.Activity完美退出的方法

我的推荐方法是 写一个单例类,将所有的Activity 都放到一个集合中,要退出的时候,将集合中的Activity 全部finish

点击跳转到代码


写在最后

以前也文章,其实就是想起来就写写,后来就不一样了,直接不写了!!!然后东西全写在有道云上,其实也还不错,但是吧,为了炫耀一下那么漂亮的老婆,哈哈哈哈哈哈。

当然,也希望,入坑的小伙伴能够一起进步。

最后,祝我新婚快乐,哈哈 刚刚结婚

相关文章

网友评论

    本文标题:Android基础 - Activity

    本文链接:https://www.haomeiwen.com/subject/ukelgxtx.html