一行代码-安卓 第二章 活动


参考章节

2.1 创建基本活动

  1. 你可能会对@+id/button_1这种语法感到陌生,但如果把加号去掉,变成@id/button_1,这样你就会觉得有些熟悉了吧,这不就是在XML中引用资源的语法吗?只不过是把string替换成了id。是的,如果你需要在XML中引用一个id,就使用@id/id_name这种语法,而如果你需要在XML中定义一个id,则要使用@+id/id_name这种语法。
<?xml version="1.0" encoding="utf-8"?>
	<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest2">
    <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/Theme.ActivityTest2">
        <activity
            android:name=".FirstActivity"
            android:exported="true">
            <!--配置主活动,其中xml语法 (<p/>) == (<p>...</p>) -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/> 
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>
  1. Toast的用法非常简单,通过静态方法makeText()创建出一个Toast对象,然后调用show()将Toast显示出来就可以了。这里需要注意的是,makeText()方法需要传入3个参数。第一个参数是Context,也就是Toast要求的上下文,由于活动本身就是一个Context对象,因此这里直接传入FirstActivity.this即可。第二个参数是Toast显示的文本内容,第三个参数是Toast显示的时长,有两个内置常量可以选择Toast.LENGTH_SHORT和Toast.LENGTH_LONG。
package com.example.activitytest2;

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);
        Button button1 = (Button) findViewById(R.id.buttom_1); // 通过id获取按钮,返回一个View对象,转换成Button对象
//        button1.setOnClickListener(v -> Toast.makeText(FirstActivity.this, "You clicked Button_1",
//                Toast.LENGTH_LONG).show());
        button1.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
            @Override
            public void onClick(View v) {
                Toast.makeText(FirstActivity.this, "You clicked Button_1",
                        Toast.LENGTH_LONG).show();
//                finish(); // 销毁
            }
        });
    }
}
  1. inflate()方法接收两个参数,第一个参数用于指定我们通过哪一个资源文件来创建菜单,这里当然传入R.menu.main。第二个参数用于指定我们的菜单项将添加到哪一个Menu对象当中,这里直接使用onCreateOptionsMenu()方法中传入的menu参数。然后给这个方法返回true,表示允许创建的菜单显示出来,如果返回了false,创建的菜单将无法显示。
 
    @Override
    public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu); // 创建一个MenuInflater对象,调用inflater方法给当前活动创建菜单
        return super.onCreatePanelMenu(featureId, menu);
    }

    /**
     * This hook is called whenever an item in your options menu is selected.
     * The default implementation simply returns false to have the normal
     * processing happen (calling the item's Runnable or sending a message to
     * its Handler as appropriate).  You can use this method for any items
     * for which you would like to do processing without those other
     * facilities.
     *
     * <p>Derived classes should call through to the base class for it to
     * perform the default menu handling.</p>
     *
     * @param item The menu item that was selected.
     * @return boolean Return false to allow normal menu processing to
     * proceed, true to consume it here.
     * @see #onCreateOptionsMenu
     */
    @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;
    }

2.2 使用Intent在活动之间跳转

2.2.1使用显示和隐式Intent

  1. 其中一个是Intent(Context packageContext, Class<? >cls)。这个构造函数接收两个参数,第一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动的目标活动,通过这个构造函数就可以构建出Intent的“意图”。然后我们应该怎么使用这个Intent呢?Activity类中提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个Intent参数,这里我们将构建好的Intent传入startActivity()方法就可以启动目标活动了。

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        Button button1 = (Button) findViewById(R.id.buttom_1); // 通过id获取按钮,返回一个View对象,转换成Button对象
//        button1.setOnClickListener(v -> Toast.makeText(FirstActivity.this, "You clicked Button_1",
//                Toast.LENGTH_LONG).show());
        button1.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
            @Override
            public void onClick(View v) {
//                Toast.makeText(FirstActivity.this, "You clicked Button_1",
//                        Toast.LENGTH_LONG).show();
//                finish(); // 销毁
                // 构建一个Intent对象,传入上下文和目标活动
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                // 执行Intent
                startActivity(intent);
            }
        });
    }
  1. ,隐式Intent则含蓄了许多,它并不明确指出我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。
<activity
            android:name=".SecondActivity"
            android:exported="true" >
            <intent-filter>
<!--                指定响应的action-->
                <action android:name="com.example.activitytest2.ACTION_START"/>
<!--                指定响应的category-->
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="com.example.activitytest2.MY_CATEGORY"/>
            </intent-filter>
        </activity>
  // 构建一个Intent对象,传入上下文和目标活动
                Intent intent = new Intent("com.example.activitytest2.ACTION_START");
                intent.addCategory("com.example.activitytest2.MY_CATEGORY");
                // 执行Intent
                startActivity(intent);

2.2.2隐式Intent的更多用法

  1. 使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。
public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        Button button1 = (Button) findViewById(R.id.buttom_1); // 通过id获取按钮,返回一个View对象,转换成Button对象
//        button1.setOnClickListener(v -> Toast.makeText(FirstActivity.this, "You clicked Button_1",
//                Toast.LENGTH_LONG).show());
        button1.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
            @Override
            public void onClick(View v) {
//                Toast.makeText(FirstActivity.this, "You clicked Button_1",
//                        Toast.LENGTH_LONG).show();
//                finish(); // 销毁
                // 构建一个Intent对象,传入上下文和目标活动
//                Intent intent = new Intent("com.example.activitytest2.ACTION_START");
//                intent.addCategory("com.example.activitytest2.MY_CATEGORY");
//                // 执行Intent
//                startActivity(intent);
                // 构建一个浏览器Intent,并设置url
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                // 执行Intent
                startActivity(intent);
            }
        });
    }

  1. 这里我们首先指定了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法,将一个网址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去。

2.2.3活动间传递数据

  1. 比较常用的就是Activity (Service)之间的数据传递。举个简单例子,在当前Activity1使用startActvity(intent)或者startActivityForResult(intent, code)方法跳转到另一个Activity2之前,如果要传递某些String类型数据给Activity2,则会执行intent.putExtra(String str, String Key),将String数据打包到Intent中,并给它一个Key标识。在Activity2当中,getIntent()方法获得这个intent,然后再getStringExtra(Key),就可以获得你之前打包的那个数据了。
 // 传递字符串给SecondActivity
                String data = "Hello SecondActivity";
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                intent.putExtra("extra data", data); //传入数据
                startActivity(intent);

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Intent intent = getIntent(); // 通过getIntent()方法获取到用于启动SecondActivity的Intent
        //然后调用getStringExtra()方法,传入相应的键值,就可以得到传递的数据了
        String data = intent.getStringExtra("extra data");
        Log.d("SecondActivity", data);
    }
}

2.3活动的生命周期及启动模式

在这里插入图片描述

2.3.1 四种生命周期

  1. 运行–>处于栈顶
  2. 暂停–>不处于栈顶–>任然可见
  3. 停止–>不处于栈顶–>完全不可见–>会保留状态和成员变量–>内存吃紧时会被回收
  4. 销毁–>从返回栈中删除–>系统最先回收这部分内存

2.3.2七个函数启动模式

  1. onCreate( )–>创建的时候执行
  2. onStart( )–>由不可见变为可见时执行
  3. onResume( )–>准备好和用户交互的时候执行–>位于返回栈栈顶,处于运行状态
  4. onPause( )–>系统准备启动或者恢复另一个活动时执行–>释放掉一些cpu资源
  5. onStop( )–>当活动完全不可见时执行–>到停止状态前执行
  6. onDestory( )–>销毁状态前执行
  7. onRestart( )–>由停止状态变成运行状态时执行–>重新启动

2.3.3 三种活动生存期

  1. 完整生存期。活动在onCreate()方法和onDestroy()方法之间所经历的,就是完整生存期
  2. 可见生存期。活动在onStart()方法和onStop()方法之间所经历的,就是可见生存期。
  3. 前台生存期。活动在onResume()方法和onPause()方法之间所经历的就是前台生存期。–>这段时间可以和用户交互

2.4活动实践开发技巧

2.4.1知晓当前是哪一个活动

  1. 创建一个BaseActivity
public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity", getClass().getSimpleName());
    }
}
  1. 需要让BaseActivity成为ActivityTest项目中所有活动的父类。修改First-Activity、SecondActivity和ThirdActivity的继承结构,让它们不再继承自AppCompatActivity,而是继承自BaseActivity。
  2. 在这里插入图片描述

2.4.2随时随地退出程序

  1. 在活动管理器中,我们通过一个List来暂存活动,然后提供了一个addActivity()方法用于向List中添加一个活动,提供了一个removeActivity()方法用于从List中移除活动,最后提供了一个finishAll()方法用于将List中存储的活动全部销毁掉。
public class BaseActivity extends AppCompatActivity {

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
        //killProcess()方法用于杀掉一个进程,它接收一个进程id参数,
        // 我们可以通过myPid()方法来获得当前程序的进程id。需要注意的是,
        // killProcess()方法只能用于杀掉当前程序的进程,我们不能使用这个方法去杀掉其他程序。
        android.os.Process.killProcess(android.os.Process.myPid());
    }

}
  1. 在BaseActivity的onCreate()方法中调用了ActivityCollector的addActivity()方法,表明将当前正在创建的活动添加到活动管理器里。然后在BaseActivity中重写onDestroy()方法,并调用了ActivityCollector的removeActivity()方法,表明将一个马上要销毁的活动从活动管理器里移除。从此以后,不管你想在什么地方退出程序,只需要调用ActivityCollector.finishAll()方法就可以了。例如在ThirdActivity界面想通过点击按钮直接退出程序,只需将代码改成如下所示
public class SecondActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
       
        Button button2 = (Button) findViewById(R.id.buttom_2); // 通过id获取按钮,返回一个View对象,转换成Button对象

        button2.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
            @Override
            public void onClick(View v) {
                // 结束所有活动,退出程序
                ActivityCollector.finishAll();
            }
        });
    }
}

2.4.3启动活动的最佳写法

  1. 启动活动的方法相信你已经非常熟悉了,首先通过Intent构建出当前的“意图”,然后调用startActivity()或startActivityForResult()方法将活动启动起来,如果有数据需要从一个活动传递到另一个活动,也可以借助Intent来完成。
  2. 我们在SecondActivity中添加了一个actionStart()方法,在这个方法中完成了Intent的构建,另外所有SecondActivity中需要的数据都是通过actionStart()方法的参数传递过来的,然后把它们存储到Intent中,最后调用startActivity()方法启动SecondActivity。这样写的好处在哪里呢?最重要的一点就是一目了然,SecondActivity所需要的数据在方法参数中全部体现出来了,这样即使不用阅读SecondActivity中的代码,不去询问负责编写SecondActivity的同事,你也可以非常清晰地知道启动SecondActivity需要传递哪些数据。另外,这样写还简化了启动活动的代码,现在只需要一行代码就可以启动SecondActivity,如下所示:
public class SecondActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Intent intent = getIntent(); // 通过getIntent()方法获取到用于启动SecondActivity的Intent
        //然后调用getStringExtra()方法,传入相应的键值,就可以得到传递的数据了
        String data1 = intent.getStringExtra("param1");
        String data2 = intent.getStringExtra("param2");
        Log.d("SecondActivity", data1);
        Log.d("SecondActivity", data2);


        Button button2 = (Button) findViewById(R.id.buttom_2); // 通过id获取按钮,返回一个View对象,转换成Button对象

        button2.setOnClickListener(new View.OnClickListener(){ // 接口可以直接实现,也可以转化成lambda
            @Override
            public void onClick(View v) {
                // 结束所有活动,退出程序
                ActivityCollector.finishAll();
            }
        });
    }
    // 封装信息传递和启动Intent方法
    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的onClick( )中直接调用SecondActivity.actionStart()

   // 直接调用SecondActivity.actionStart()
                SecondActivity.actionStart(FirstActivity.this, "data1", "data2");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值