Android第一行代码-Activity

Android第一行代码

Activity

1、Activity基本用法

一种可以包含用户界面的组件,一个应用可以包含0或多个活动

在创建activity的时候:

  • 1、如果勾选Generate Layout File表示会自动为FirstActivity创建一个对应的布局文件
  • 2、勾选Launcher Activity表示会自动将FirstActivity设置为当前项目的主Activity
  • 3、任何Activity都应该重写onCreate()方法。

2、创建和加载布局

Android程序讲究逻辑和视图分离,最好每一个Activity都能对应一个布局,布局是用来显示页面内容的。

在创建好Layout文件之后,会布局编辑器,窗口左下角有两个切换卡:

  • Design:可视化布局编辑器,在这可以通过拖放的方式编辑布局。
  • Text:通过XML文件的方式编辑布局。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 1"
        />
</LinearLayout>

上面线性布局中添加了一个Button元素,并在内部增加了几个属性:

  • 1、android:id 给当前的元素定义一个唯一的标识符。
  • 2、在XML中引用一个id,就是用@id/id_name这种语法,如果在XML中定义一个id,则需要使用@+id/id_name这种语法
  • 3、android:layout_width 指定当前元素的宽度。
  • 4、android:layout_height 指定当前元素的高度。warp_content表示当前元素的高度只要能刚好包含里面的内容就行
  • 5、android:text 指定了元素显示的文字内容

右侧工具栏Preview用来预览当前布局

加载布局(在Activity中加载布局)
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //传入布局文件的id
        setContentView(R.layout.first_layout);
    }
}

在setContentView()方法用来给当前的Activity加载布局。一般会传入一个布局文件的id。项目中的任何资源都会在R文件中生成一个相应的资源id。

在AndroidManifest文件中注册(所有的activity都要在AndroidManifest.xml中进行注册)

AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity"></activity>
    </application>

</manifest>

所有的activity都要在AndroidManifest.xml中进行注册才能生效。Activity的声明要放在< application>标签内。这里是通过Activity标签来对Activity进行注册的。

在< activity>标签内,我们使用android:name来指定具体注册哪一个Activity,.FirstActivity是com.example.activitytest.FirstActivity的缩写。因为manifest标签中已经通过package属性制定了程序的包名。所以才可以省略。

配置主Activity(activity标签内部添加标签)

如果不配置主Activity,那么程序就不知道启动哪个Activity。配置主Activity就是要在标签的内部加入标签。并且在这个标签内部添加和

修改后的AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>
在Activity中使用Toast

Toast是Android提供的一个很好的提醒方式,可以将一些短小的信息通知给用户,并在一段按后自动消失。

package com.example.activitytest;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        //findViewById()这个方法获取在布局文件中定义的元素
        //findViewById方法返回的是一个View对象,我们可以向下转型将其转成Button对象
        Button button1 = findViewById(R.id.button1);
        //通过调用setOnClickListener方法为按钮注册一个监听器
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //makeText静态方法创建一个Toast对象,然后调用show将toast显示出来即可。
                //makeText的三个参数,
                // 第一个参数是Context即Toast要求的上下文,由于活动本身就是一个Context对象,因此这里直接传入FirstActivity.this即可
                //第二个参数是Toast显示的文本内容
                //第三个参数是Toast显示的时长
                Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

在活动中使用Menu()

res目录下创建menu目录,在menu文件夹中创建Menu resource file。

<?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
        android:id="@+id/remove_item"
        android:title="Remove"/>
</menu>

在这里插入图片描述

标签用来创建具体的菜单项,然后通过android:id给这个菜单项指定一个唯一的标识,android:title给菜单项指定一个名称。

package com.example.activitytest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class FirstActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        //findViewById()这个方法获取在布局文件中定义的元素
        //findViewById方法返回的是一个View对象,我们可以向下转型将其转成Button对象
        Button button1 = findViewById(R.id.button1);
        //通过调用setOnClickListener方法为按钮注册一个监听器
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //makeText静态方法创建一个Toast对象,然后调用show将toast显示出来即可。
                //makeText的三个参数,
                // 第一个参数是Context即Toast要求的上下文,由于活动本身就是一个Context对象,因此这里直接传入FirstActivity.this即可
                //第二个参数是Toast显示的文本内容
                //第三个参数是Toast显示的时长
                Toast.makeText(FirstActivity.this,"You clicked Button 1",Toast.LENGTH_SHORT).show();
            }
        });
    }
    
    //重写方法可以使用快捷键Ctrl+O
    //Menu是一个接口
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //Inflater [ɪnf'leɪtər] 打气筒,充气机,网络
        //getMenuInflater()方法可以获得MenuInflater对象
        //然后调用它的inflate()方法就可以给当前活动创建菜单
        //inflate第一个参数指定我们通过哪一个资源文件来创建菜单,这里指定main.xml
        //第二个参数指定我们的菜单项添加到哪一个Menu对象中
        getMenuInflater().inflate(R.menu.main,menu);
        //表示允许将创建的菜单显示出来
        //false表示创建的菜单将无法显示
        return true;
    }

    //定义菜单响应事件
    //MenuItem是一个接口
    @Override
    public boolean onOptionsItemSelected(@NonNull 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;
            default:
        }
        return true;
    }
}

三、使用Intent在活动之间穿梭

如果有多个活动,在启动器中点击应用的图标只会进入到该应用的主活动。如何跳转其他活动呢?

Intent分为两种:显示Intent和隐式Intent

1、使用显示Intent

创建第二个Activity即SecondActivity,并生成对应的layout文件,AndroidStudio会自动在AndroidManifest中进行注册,由于不是主活动,不需要在AndroidManifest.xml中的activity标签中配置< intent-filter>标签中的内容。一系列操作结束后,如何启动这第二个活动?

Intent [ɪn’tent] 专注、意图
Intent是Android程序中各组件之间进行交互的一个重要的方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间进行传递数据。

Intent一般可被用于启动活动、启动服务以及发送广播等场景。

显示Intent

Intent的多个构造函数的重载:

  • Intent(Context packageContext,Class<?> cls),第一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动活动的目标活动

startActivity()方法是专门用于启动活动的。他接收一个Intent参数,把构建好的Intent传入startActivity()方法就可以启动目标活动。

//在主活动的onCreate函数中添加如下代码即可点击button1按钮启动SecondActivity了。
button1.setOnClickListener(new View.OnClickListener(){
	@Override
	public void onClick(View v){
		//FirstActivity作为上下文,SecondActivity为目标活动
		//那么我们的意图就非常明显了,即在FirstActivity的基础上打开SecondActivity,并通过startActivity来执行
		Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
		startActivity(intent);
	}
})
隐式Intent(不指明具体想要启动哪个活动)

不明确指出我们想要启动哪一个活动,而是指定一系列更为抽象的action和category等信息,然后交给系统去分析这个Intent,并帮我们找出合适的活动去启动。

通过在< activity>标签下配置< intent-filter>的内容,可以指定当前活动能够响应的action和category

如:

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

从上面的配置在AndroidManifest.xml的action可以看出,指明了当前活动可以响应com.example.activitytest.ACTION_START这个action。而< category>标签则包含了一些附加信息,更精确指明了当前活动能够响应的Intent中还可能带有的category,只有< action> < category>中的内容同时能够匹配上Intent中指定的action和category的时候,这个活动才能响应该Intent

比如FirstActivity的onCreate下面的代码就可以启动上面所定义的activity:

button1.setOnClickListener(new View.onClickListener(){
	@Override
	public void onClick(View v){
		//因爲上面xml文件指明了activity的action為com.example.activitytest.ACTION_START
		//创建Intent(意向),要傳入相應參數
		//就會調用相應的activity
		Intent intent = new Intent("com.example.activitytest.ACTION_START");
		startActivity(intent);
	}
})
更多隐式Intent的用法

Intent让多个应用程序之间的功能共享成为可能,比如你打电话,没必要自己去实现一个拨打电话功能,只需要调用系统的拨打电话功能即可。

button1.setOnClickListener(new View.OnClickListener(){
	@Override
	public void onClick(View v){
		//Intent.ACTION_VIEW在Intent类中定义为
		//public static final String ACTION_VIEW = "android.intent.action.VIEW";
		Intent intent = new Intent(Intent.ACTION_VIEW);
		intent.setData(Uri.parse("tel:10086"));
		startActivity(intent);
	}
});

在上面的代码中首先指定了意向的action为Intent.ACTION_VIEW。setData制定了当前正在操作的数据,而这些数据通常都是以字符串的形式传入到Uri.parse()方法中解析产生的。

<activity android:name=".ThirdActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:scheme="tel" />
    </intent-filter>
</activity>

如果在Intent中设置了Data,我们可以在中再配置一个标签,用于精确制定当前活动能够响应什么类型的数据。标签中主要可以配置以下内容:

  • 1、andorid:scheme:用于指定数据的协议部分,如上例中的http部分
  • 2、android:host:用于指定数据的主机名部分,如上例中的www.baidu.com
  • 3、android:port:用于指定数据的端口部分,一般紧随在主机名之后
  • 4、android:path:用于制定主机名和端口之后的部分,如一段网址中跟在域名之后的内容
  • 5、andorid:mimeType:用于指定可以处理的数据类型,允许使用通配符的方式进行指定。

只有标签中指定的内容和Intent中携带的Data完全一致时,当前活动才能够响应该Intent

向下一个活动传递数据(放入Intent,从Intent取出)

在启动活动的时候传递数据的思路很简单,Intent中提供了一系列putExtra()方法的重载,可以吧我们想要传递的数据暂存在Intent中,启动另外一个活动的时候,只需要把数据从Intent中再取出即可

例子:
想把FisrtActivity中的一个字符串传递到SecondActivity中。

button1.setOnClickListener(new View.OnClickListener() {
   @Override
    public void onClick(View v) {
        String data = "Hello SecondActivity";
        Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
        intent.putExtra("extra_data",data);
        startActivity(intent);
    }
});

在SecondActivity将传递的数据取出,并打印:

public class SecondActivity extends AppCompatActivity {

	//Bundle主要用于传递数据,它保存的是数据,是以key-value(键值对)的形式存在的
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity",data);
    }
}

getIntent()用于获取到用于启动SecondActivity的Intent,然后调用getStringExtra()方法来获取传递的数据。

返回数据给上一个活动(startActivityForResult())

Activity中还有一个startActivityForResult()也是用来启动活动的,但是这个方法期望在活动销毁的时候能够返回一个结果给上一个活动。
startActivityForResult方法的两个参数:

  • 1、Intent
  • 2、请求码,用于在之后的回调中判断数据的来源。

例子:
修改FirstActivity中按钮的点击事件

button1.setOnClickListener(new View.OnClickListener() {
   @Override
    public void onClick(View v) {

        Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
       	
        startActivityForResult(intent,1);
    }
});

startActivityForResult()方法用来启动SecondActivity,请求码只要唯一即可。

SecondActivity中给按钮添加点击事件,并在点击事件中添加返回数据的逻辑。

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        Button button2 = (Button)findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                //把数据放入Intent中
                intent.putExtra("data_return","Hello FirstActivity");
                //专门向上一个活动返回处理结果
                setResult(RESULT_OK,intent);
                finish();
            }
        });
    }
}

setResult()方法专门用于向上一个活动返回数据。有两个参数:

  • 第一个参数用于向上一个活动返回处理结果,一般是RESULT_OK或RESULT_CANCELED
  • 第二个为Intent,调用finish()来销毁当前活动。

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

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    switch (requestCode){
        case 1:
            if (requestCode == RESULT_OK){
                String returnedData = data.getStringExtra("data_return");
                Log.d("FirstActivity",returnedData);
            }
            break;
        default:
    }
}
  • 1、requestCode为启动活动时传入的请求码
  • 2、resultCode即在返回数据时传入的处理结果
  • 3、Intent

上面是通过点击按钮,如果通过Back回到FirstActivity是数据就无法返回。可以在SecondActivity中重写onBackPressed()方法解决:

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

活动的生命周期

返回栈

Android的活动是可以层层叠加的,我们每启动一个新的活动,就会覆盖在原活动之上,点击back就会销毁最上面的活动,下面的一个活动就会重新显示出来。

==Android是使用任务来管理活动的,一个任务就是一组存放在栈中的活动的集合,这个栈就称为返回栈。==每启动一个新的活动,就会入栈,处于栈顶的位置,按下back或者调用finish()方法去销毁一个活动的时候,处于栈顶的活动就会出栈,前一个入栈的活动就会重新处于栈顶的位置,系统总是会显示处于栈顶的活动给用户。

活动状态(运行、暂停、停止、销毁)

  • 1、运行状态:活动位于栈顶,系统最不愿意回收,因为会给用户带来非常差的体验)
  • 2、暂停状态:不处于栈顶,但是仍然可见(因为并不是每个活动都会占满整个屏幕),这时活动处于暂停状态。系统也不愿意去回收这种活动,因为回收可见东西都会给用户体验带来不好的影响,只有在内存极低的情况下,系统才会考虑回收这种活动
  • 3、停止状态:当活动不在栈顶位置且完全不可见的时候,系统仍然回味这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存的时候,处于停止状态的活动可能会被系统回收
  • 4、销毁状态:一个活动从栈中移除就变成了销毁状态。

活动的生存期(7个回调函数,OnCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart)

Activity定义了7个回调函数,覆盖了活动生命周期的每一个环节。

  • 1、onCreate:每个活动都会重写这个方法,会在活动第一次被创建的时候调用,你应该在这个方法中完成活动的初始化,比如加载布局、绑定事件等
  • 2、onStart:这个方法在活动由不可见变为可见的时候调用
  • 3、onResume:恢复。这个方法在活动准备好和用户进行交互的时候调用,此时的活动位于返回栈的栈顶,并且处于运行状态。
  • 4、onPause:这个方法在系统准备去启动或者恢复另一个活动的时候调用,我们常常会在这个方法中将一些消耗cpu的资源释放掉,以及保存一些关键数据,但是这个方法的执行一定要快,不然会影响到新的栈顶活动的使用。
  • 5、onStop:这个方法在活动完全不可见的时候调用,他和onPause的区别在于,如果启动的新活动是一个对话框式的活动,那么onPause方法会得到执行,而onStop方法并不会执行
  • 6、onDestroy:这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态
  • 7、onRestart:这个方法在活动由停止变为运行状态之前调用,也就是活动被重新启动了。

以上7个方法除了onRestart之外都是两两相对的,从而又可以将活动分为3中生存期。

  • 完整生存期:活动在onCreate和onDestroy之间所经历的,就是完整生存期。
  • 可见生存期:onStart和onStop之间所经历的是可见生存期。在可见生存期内,活动对于用户总是可见的。
  • 前台生存期:活动在onResume和onPause方法之间所经历的就是前台生存期,在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的,我们平时看到和接触最多的也就是这个状态下的活动。

在这里插入图片描述

体验活动的生命周期

如何将一个普通活动设置为对话框式的活动?下面将DialogActivity设置为对话框式活动

  • 修改AndroidManifest.xml的标签的配置,添加android:theme属性
<activity android:name=".DialogActivity" android:theme="@android:style/Theme.Dialog">
</activity>

android:theme属性用于给当前活动指定主题,有很多内置主题,也可以定制自己的主题,@android:style/Theme.Dialog就是让DialogActivity使用对话框式的主题。

package com.example.activitylifecycletest;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    public 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);
        final 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,"onDestroy");
    }

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

从上面的代码可以看到,给两个按钮注册了点击事件

当MainActivity第一次被创建的时候会执行onCreate()、onStart()、onResume()方法。

点击按钮1会启动NormalActivity:

  • 1、点击第一个按钮,由于NormalActivity会把MainActivity完全遮挡住,因此onPause()和onStop()方法都会执行。
  • 2、按下back,会返回MainActivity,执行onRestart、onStart、onResume方法

点击按钮2会启动DialogActivity:

  • 1、点击按钮2可以看到onPause()方法得到了执行,onStop()并没有执行。因为DialogActivity并没有完全遮挡住MainActivity。此时MainActivity只是进入了暂停状态。
  • 2、按下Back键返回MainActivity也应该只有onResume()方法会得到执行。

最后在MainActivity按下Back键退出程序,依次会执行onPause() onStop() onDestroy()

活动被回收了怎么办(onSaveInstanceState())

这个方法保证在活动被回收之前会被调用,因此可以通过这个方法来解决活动被回收时临时数据得不到保存的问题
onSaveInstanceState()会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,不如putString()方法保存字符串。

onSaveInstanceState函数的两个参数:

  • 1、键
  • 2、需要保存的内容
@Override
protected void onSaveInstanceState(Bundle outState){
	super.onSaveInstanceState(outState);
	String tempData = "Something you just typed";
	outState.putString("data_key",tempData);
}

数据已经保存下来了,如何恢复?onCreate()其实有一个Bundle类型的参数,这个参数一般情况下都是null,但是如果在活动被系统回收之前有通过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对象中,然后再将Bundle对象存放在Intent里,到了目标活动之后先从Intent中取出Bundle,再从Bundle中一一取出数据。

活动的启动模式(standard、singleTop、singletask、singleInstance)

可以在AndroidManifest.xml中通过标签指定android:launchMode属性来选择启动模式。

standard

@Override
protected void onCreate(Bundle savedInstanceState){
	super.onCreate(savedInstanceState);
	Log.d("FirstActivity",this.toString());
	setContentView(R.layout.first_layout);
	Button button1 = (Button)findViewById(R.id.button_1);
	button1.setOnClickListener(new View.onClickListener(){
		@Override
		public void onClick(View v){
			Intent intent = new Intent(FirstActivity.this,FirstActivity.class);
			startActivity(intent);
		}
	});
}

==standard模式下,每当启动一个新的活动,都会创建该活动的一个新的实例。==所以每次点击按钮,都会创建FirstActivity的实例。多次点击,需多次按back键才能退出程序。

在这里插入图片描述

singleTop

<activity
	android:launchMode="singleTop">
</activity>	

当启动模式指定为singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用他,不会再创建新的活动实例。但是如果启动活动不是栈顶,那么就会创建新的实例入栈。

在这里插入图片描述

singleTask

当活动的启动模式为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在,则直接使用该实例,并把这个活动之上的所有活动统统出栈,如果没有则会创建一个新的活动实例。
在这里插入图片描述

singleInstance

指定为singleInstance模式的活动会启动一个新的返回栈来管理这个活动。

如果我们想其他程序和我们的程序可以共享这个活动的实例,如何实现?

  • 1、前面的三中启动模式是做不到的,因为每个程序都会有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。
  • 2、在singleInstance模式下,会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都公用的同一个返回栈,也就解决了共享活动实例的问题。

在这里插入图片描述

将活动2的运行模式修改成singleTask,在活动1的onCreate中开启活动2,在活动2的onCreate中开启活动3,那么活动1和活动3就会在一个返回栈中,活动2会在一个单独的返回栈中。到活动3点击back,那么直接会回退到活动1,那么这个返回栈就空了,再点击back,就显示了另一个返回栈的栈顶活动,即就到了活动2.

活动的最佳实践

如何判断程序的当前页面是哪个活动?

通过new-》java Class来创建一个类BaseActivity类,BaseActivity不需要再AndroidManifest.xml中进行注册。让BaseActivity继承自AppCompatActivity,修改BaseActivity代码,让其他活动类继承自BaseActivity。

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

修改之后每进入一个活动的页面,该活动的类名就会被打印出来。这样我们就可以时时刻刻知晓当前页面对应的是哪个活动了。

随时退出程序(用专门的集合类对所有活动进行管理)

新建一个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();
		}
	}
}

在BaseActivity的onCreate()方法中调用ActivityCollector的addActivity()方法,onDestroy方法中调用ActivityCollector的removeActivity()方法.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值