活动Activity

四大组件之——活动Activity

作为安卓四大组件之一,活动是一种包含用户应用界面的组件,可用于和用户交互

一.手工创建活动

(1)创建一个project,name自己起,比如activitytest

(2)java/com.example.activitytest,右键单击,出现New->Activity->EmptyActivity,弹出对话框,将活动命名,比如FirstActivity,此时不要勾选Generate Layout File(自动产生布局文件)和 Launcher Activivty(将当前活动创建为主活动)这两个控件,勾选Backwards Compatibility会向下兼容

(3)创建和加载布局res->New->Directory,创建layout目录,然后再在此目录下右键layout resource file,创建一个自己的布局文件,用setContentView(R.layout.layoutid)把布局文件传入FirstActivity的onCreate方法中

(4)在AndroidManifest中注册活动,采用标签在application中完成

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".NoAuto"
        android:label="This is my actrivity">
        <intent-filter>//配置主活动
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
</application>
在活动中使用Toast的步骤

Toast是一种交互消息提醒方式,通知短小信息,显示一段时间消失,不占用屏幕空间

使用时一般在需要提示信息的按钮上增加点击事件

 Button button=(Button)findViewById(R.id.button1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,"hhhh",Toast.LENGTH_SHORT).show();
            }
        });

makeText函数通过传入参数创建一个对象,第一个参数Context,toast所要求的上下文,可以是本身这个活动,第二个参数是要显示的内容,第三个参数是显示时间Toast.LENGTH_SHORT,Toast.LENGTH_LONG两种形式可选,一短一长。

在活动中使用菜单的步骤

菜单的使用可以节省屏幕空间

(1)res目录下新建一个Menu文件,res->New->Dictionary->menu,然后menu->new->menu resource file->新建的menu文件名字,这里我写了main

(2)在此文件中加入menu的一些参数

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="Add"></item>
    <item
        android:id="@+id/remove_item"
        android:title="Remove"></item>
</menu>

id是唯一标识符号,title是用于显示的内容,还有icon,还有,里面包裹item使用可以实现一个分组,这个显示出来和只用item没啥区别,主要是可以对这个分组进行一个组内集中处理

(3)继续操作MainActivity,进行重写onCreateOptionsMenu()方法

 @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main,menu);
        return true;
    }

getMenuInflater()获取MenuInflater对象,再调用inflate()方法就可以给当前活动创建菜单了,这个方法传入两个参数,一个是创建菜单的资源文件,另一个用来指定我们创建的菜单项将加入到哪一个资源文件中,直接使用传入的menu即可,返回值true表示可以将菜单显示出来,false表示不显示

(4)为每个item添加响应事件

 public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()){
            case R.id.add_item:
                Toast.makeText(this,"You click add",Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this,"You click Remove",Toast.LENGTH_SHORT).show();
                break;
            default:break;
        }
        return true;
    }

item.getItemId()判断点击是哪一个菜单项,然后给每个菜单项加入相应处理事件

二.Intent穿叉活动

intent是安卓各大组件交互的一种方式,不仅可以指明当前活动所要执行的动作,还可以在不同组件之间传递数据。一般被用作启动活动,服务,发送广播。

1.活动之间跳转
(1)显式Intent

Intent有多个构造函数的重载,其中一个是Intent(Context packageContext,Class<?> cls),第一个参数是要求提供一个启动活动的上下文,第二个活动表示想要启动的目标活动,这个构造函数就实现了构造意图。使用它要运用Activity中的startActivity()方法,他接受一个启动对象,将构造好的intent传入此方法中,就可以启动活动了。这种启动方式,活动意图明显,故称为显式启动。具体实现

首先在MainActivity同级目录下创建一个Main2Activity活动,具体做法包名->New->Activity->Empty Acivity->Main2Activity(活动名称),此时系统会自动创建他的布局文件注册等。为了简单,两个活动的布局文件都用一个按钮替换。然后修改MainActivity中代码如下,即给button1一个按钮响应事件

package com.example.tingyu.myactivity;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    private Button button1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button1=(Button)findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(MainActivity.this,Main2Activity.class);
                startActivity(intent);
            }
        });
    }
}

当想回到上一个活动,只需要按back键。

(2)隐式Intent

相比显式Intent,多用一些抽象的catagory和action等信息,交给系统去分析这个Intent进而确定启动合适的活动。

首先在注册文件中添加如下代码

<activity android:name=".Main2Activity">
            <intent-filter>
                <action android:name="com.example.activitytest.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

标签中明确指出当前活动可以响应com.example.activitytest.ACTION_START这个action,而则精确指明了当前活动能响应的Intent还可能带有的catagory,只有和同时匹配上述的action和catagory,这个活动才能响应此Intent。

在MainActivity中响应事件改为如下:

每个Intent只能指定一个action,但是却可以有多个category,如果注册文件中不含有对应catagory,就会报错,例如,将注释下面的语句与注释语句换位,这时可以在注册文件中添加如下语句

<category android:name="com.example.activitytest.MY_CATEGORY"/>
public void onClick(View v) {
            Intent intent=new Intent("com.example.activitytest.ACTION_START");
            //intent.addCategory("android.intent.category.DEFAULT");
            intent.addCategory("com.example.activitytest.MY_CATEGORY");
            startActivity(intent);
        }
    });
}
更多隐式Intent用法

除了可以启动相同项目下的活动,还可以启动其他程序的活动,例如

 public void onClick(View v) {
                Intent intent=new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
            }

首先指定Intent的action是Intent.ACTION_VIEW,这是一个系统内置的action,然后通过Uri.parse()方法解析成一uri对象,再调用Intent的setData()方法将这个uri对象传进去。我们还可以在intent-filter标签再配置标签,更精确指明当前活动应该响应什么类型的数据。但data标签一般不宜携带过多的数据,对于上述浏览器,只需指定<Data android:scheme=“http”/>就可以相应http中的协议了

![1534250454587.png](https://i.loli.net/2018/08/14/5b72cdf7f2db2.png)
2.活动间数据传递
向下一个活动传递数据
 button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String data="hello main2Activity";
            Intent intent=new Intent(MainActivity.this,Main2Activity.class);
            intent.putExtra("Extra",data);
            startActivity(intent);
        }
    });
}

putExtra()方法第一个参数是键,第二个参数是真正要传递的值

第二个活动用来接收参数

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Intent intent=getIntent();
        String data=intent.getStringExtra("Extra");
        TextView textView=(TextView)findViewById(R.id.text1);
        textView.setText(data);
    }

先用getIntent()来接收启动本活动的intent,然后调用getStringExtra()方法,传入相应的键值,就可以得到传递的数据了,还可以有getBooleanExtra() getIntExtra()根据传入的值不同。

返回数据给上一个活动

只需要按back键就行了

(1)在第一个活动中加如下代码

 Intent intent=new Intent(MainActivity.this,Main2Activity.class);
 startActivityForResult(intent,1);

在活动销毁时返回数据给上一个活动 startActivityForResult()方法,,接收两个参数,第一个是Intent,第二个参数是一个唯一标识的状态码,这里写成了1

(2)接下来给第二个活动给按钮增加点击事件

 Button button=(Button)findViewById(R.id.button2);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent();
                intent.putExtra("data_return","helloActivity");
                setResult(RESULT_OK,intent);
                finish();
            }
        });
    }

构造一个空的Intent,专门用来传递值,然后putExtra()方法传递,接下来setResult()方法有两个参数,第一个是向上一个活动返回处理结果,RESULT_OK和RESULT_CANCELED两种,第二个是带有数据的intent,然后调用finish()方法销毁活动

(3)在第一个活动中重写onActivityResult()方法

由于startActivityForResult()方法来启动第二个活动,第二个活动被销毁后会回调上一个活动的onActivityResult()方法,因此需要在第一个活动中重写这个方法来得到返回的数据。

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        switch(requestCode){
            case 1:
                if(resultCode==RESULT_OK){
                    String returnedData=data.getStringExtra("data_return");
                    Log.d("FirstActivity",returnedData);
                }
                break;
                default:
        }
    }

onActivityResult()一共有三个参数,第一个参数requestCode是我们启动活动时传入的请求码,第二个参数resultCode是返回数据时传入的处理结果,第三个参数是携带着返回数据的Intent

因为一个活动可能调用startActivityForResult()方法启动很多不同活动,所以要先通过requestCode来判断是不是要找的活动;然后再通过resultCode判断数据处理结果是不是成功的

这样打开程序,按下活动2的按钮就可以回到活动1并返回值,但是如果是按back键,而不是点击按钮,就不能返回值给活动1了,这个时候可以通过重写onBackPressed()方法解决这个问题。

 @Override
    public void onBackPressed() {
        Intent intent=new Intent();
        intent.putExtra("data_return","helloActivity");
        setResult(RESULT_OK,intent);
        finish();
    }

就和上面的按钮代码一样就行。

三.活动的生命周期

1.活动状态

每个活动在其生命周期会出现四种状态:

(1)运行状态

返回栈栈顶位置,最不愿回收的状态

(2)暂停状态

不在栈顶,但仍然可见,一般不愿回收,除非内存极低

(3)停止状态

不在栈顶,也不可见,系统仍然为其保存状态和成员变量,但不可靠,内存低立马收回

(4)销毁状态

不在返回栈中,系统最愿回收

执行finish()方法可以手动销毁活动

2.活动生存期

七个回调方法贯穿活动生命周期始终

onCreate(),活动第一次创建时使用,初始化

onStart(),活动由不可见变为可见

onResume(),活动处于栈顶准备好和用户交互时使用,此时活动一定处于返回栈栈顶,并且处于运行状态

onPause(),活动准备去启动或恢复另一个活动时启用,方法要快,不然影响新栈顶活动的使用。

onStop(),活动完全不可见时启用,与onPause区别在于当启动一个对话框的活动(不在栈顶,仍然可见,在注册文件中样式采用Dialog,即标签中 添加android:theme="@style/Theme.AppCompat.Dialog",系统有很多主题,也可以定制自己的主题),使用onPause而不是onStop

onDestory(),活动被销毁的时候调用,释放内存

onRestart(),活动由停止变为运行状态调用,活动重启

(1)完整生存期 onCreate()->onDestory()
(2)可见生存期onStart()->onStop()
(3)前台生存期onResume()->onPause()
onSaveInstanceState()方法:

用于保存一些临时数据,可以保证系统回收活动之前该活动一定会被调用,因此可以解决活动被回收时候临时数据不能得到保存的问题。onSaveInstanceState()方法携带一个Bundle类型的参数,Bundle提供了一系列方法用来保存参数,比如putString(),putInt()等等,每个方法都有两个参数,第一个是键,第二个是值

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

恢复数据使用onCreate()方法,它平常Bundle带有的是空的值,但是如果有调用onSaveInstanceState()方法保存数据,它就可以一把值全部传递过去

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG,"----onCreate");
        setContentView(R.layout.activity_main);
        if(savedInstanceState!=null){
            String tempData=savedInstanceState.getString("data_key");
            Log.d(TAG,tempData);
        }
     }

Bundle和Intent可以结合使用,存取数据,先放在Bundle里,然后放在Intent里,到了取出时候先取出Intent的Bundle,再一一取出Bundle中的数据

四.活动的四种启动模式

(1)standard

系统默认的启动模式,每次启动,不管栈顶是否有活动,都创建一个该活动的实例,并把他放到返回栈的栈顶

(2)singleTop

对于栈顶已经有的活动,不再创建该活动的实例,直接使用

(3)singleTask

查找返回栈,里面有要用的活动,直接返回,把此活动上面的所有活动出栈

(4)singleInstance

为其启用一个新的返回栈来管理活动,(每一应用程序有一个返回栈)从而实现多个应用程序可以共享此活动的实例

通过更改注册文件中的android:launchMode 属性可以选择不同的启动模式·

五.活动的最佳实践

1.知晓当前是哪一个活动

新建一个普通类,就在活动的相同目录下,他继承AppCompatActivity类,并重写onCreate()方法,打印内容,让所有活动都继承他,因为所有活动间接继承 AppCompatActivity,所以正常,不受影响

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity",getClass().getSimpleName());
    }
}

可以自己定义三个活动,用按钮点击事件进行跳转,然后观察日志文件就可以了。

2.随时随地退出程序

这里退出程序主要是针对返回栈过多,所以需要多次按back键,这是可以加一个对所有活动的统一管理,然后在需要退出所有活动的时候进行方法的调用

新建一个类ActivityCollector 作为活动的管理者,将每个活动存放在链表中

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();
            }
        }
        activities.clear();
    }
    }

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity",getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
    }

重写BaseActivity的onDestroy()方法,其实相当于自己构造了一个返回栈。然后当想退出程序的时候,只需要在需要的地方调用 ActivityCollector.finishAll()方法就可以了 。

也可以杀死当前进程以确保程序完全退出,调用android.os.Process.killProcess(android.os.process.myPid());

killProcess接受一个进程的id,杀死当前进程,不能杀死其他进程,myPid()方法可以获取到当前进程id。

3.活动的启动最佳方法

对比直接在点击事件里写Intent跳转逻辑,这样写更利于维护

 public static void actionStart(Context context,String data1,String data2){
        Intent intent=new Intent(context,ThirdActivity.class);
        intent.putExtra("param1",data1);
        intent.putExtra("param2",data2);
        context.startActivity(intent);
    }
button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SecondActivity.actionStart(SecondActivity.this,"data1","data2");//替代写法
//                Intent intent=new Intent(SecondActivity.this,ThirdActivity.class);
//                intent.putExtra("param1","data1");
//                intent.putExtra("param2","data2");
//                startActivity(intent);之前的写法
            }
        });

参考:郭霖《第一行代码》第二版

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值