Android Studio —— Activity

255 阅读8分钟

第一行代码读书笔记

基础

创建活动

  • 包->New->Acitivity->Empty Activity
  • Generate Layout File:自动创建对应的布局文件
    Laucher Activity:自动将该活动设置为当前项目的主活动
    Backwards Compatibility:启用向下兼容的模式
  • 任何活动都应该重写onCreate()方法
  • AppCompatActivity:一种向下兼容的Activity

创建布局

  • res->New->Directory(layout)
    layout->Layout resource file
  • Design/Code
  • 添加按钮
    <Button
          android:id="@+id/button_1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:text="Button 1"
          />
    
    • id:唯一标识符 引用id:@id/id_name 定义id:@+id/id_name
    • layout_width/layout_height:宽度/高度
    • match_patrent:与父元素相同 wrap_content:宽/高刚好包含里面的内容
    • text:元素中显示的文字内容
  • 加载布局:在onCreate()方法中加入
    setContentView(R.layout.first_layout);
    
  • 资源调用:
    R.(string/drawable/mipmap/layout).resource_name @(string/drawable/mipmap/layout)/resource_name

注册活动

  • AndroidManifest文件中注册(新建活动时Android Studio自动添加<activity>标签)
  • 配置主活动:在<activity>标签中加入<intent-filter>标签
    <activity android:name=".FirstActivity"
        android:label="This is FirstActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    
    • label:活动中标签栏的内容/(启动器中)应用显示的名称
    • 主活动:点击桌面应用程序图标时首先打开的活动

在活动中使用Toast

  • 弹出信息通知,一段时间后自动消失,不占用屏幕空间
  • 定义触发点:在onCreate()方法中添加
    Button button1 = (Button) findViewById(R.id.button_1);
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(FirstActivity.this, "You click Button 1",
                    Toast.LENGTH_SHORT).show();
        }
    });
    
    • findViewById():获取在布局文件中定义的元素
      返回View对象,向下转型成Button
    • setOnClickListener:注册监听器
    • 静态方法makeText创建Toast对象
      第一个参数:上下文Context,活动本身Activity.this就是一个Context对象
      第二个参数:Toast显示的文本内容
      第三个参数:Toast显示的时长(内置常量Toast.LENGTH_SHORTToast.LENGTH_LONG

记得Import包或设置自动导入

在活动中使用Menu

  • res->New->Directory(menu)
    menu->Menu resource file
  • main.xml中添加
    <item
        android:id="@+id/add_item"
        android:title="Add" />
    <item
        android:id="@+id/remove_item"
        android:title="Remove" />
    
    • 创建具体的菜单项
    • id:指定标识符
    • title:指定名称
  • activity.java中重写onCreateOptionsMenu()(重写快捷键Ctrl+O
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
    • getMenuInflater():得到MenuInflater对象
    • inflate():为当前活动创建菜单
      第一个参数:通过哪个资源文件创建菜单
      第二个参数:指定创建的菜单项添加到哪一个Menu对象中
      返回true:显示菜单(false不显示)
  • activity.java中重写OnOptionsItemSeletected()
    @Override
    public boolean onOptionsItemSelected(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;
    }
    
    • item.getItemId():判断点击的是哪一个菜单项
      给每一个菜单项加入逻辑处理

销毁活动

  • Back
  • 调用finish()
    button1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            finish();
        }
    });
    

Intent

显式Intent

  • Intel(Context packageContext, Class<?> cls)
    Context:启动活动的上下文
    Classs:启动的活动目标
    构建Intent的意图
  • StartActivity(Intent intent)
  • FirstActivity的基础上SecondActivity
    Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
    StartActivity(intent);
    

隐式Intent

  • 不明确指出启动哪个活动
    指定抽象的action和category等信息
    由系统分析并找到合适的活动去启动
  • 通过配置<action>标签中的<intent-filter> 指定活动可以响应的actioncategory
  • <intent-filter>
        <action android:name="com.example.activitytest.ACTION_START" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    
  • 只有anctioncategory中的内容同时匹配Intent,这个活动才能响应
  • Intent intent = new Intent("com.example.activitytest.ACTION_START");
    StartActivity(intent);
    
  • 每个Intent只能指定一个action
    但能指定多个category
  • Intent增加category
    intent.addCategory("com.example.activitytest.MY_CATEGORY");
    
  • 隐式Intent可以启动其他程序的活动->多个应用程序间的功能共享
    E.g.
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse("http://www.baidu.com"));
    
    • Intent.ACTION_VIEW:Android系统内置动作 常量值为android.intent.action.VIEW
    • Uri.parse():将网址字符串解析成Uri对象
    • setData():用于指定Intent当前操作的数据
  • <intent-filter>中配置<data>标签
    • android:scheme:指定数据的协议部分
    • android:host:指定数据的主机名部分
    • android:port:指定数据的端口部分
    • android:path:指定主机名和端口之后的部分
    • android:mimeType:指定可以处理的数据类型 只有<data>标签中指定的内容和Intent中携带的Data完全一致时,当前活动才能响应该Intent 一般<data>标签中不会指定过多内容
  • 调用tel协议拨号
    Intent intent = new Intent(Intent.ACTION_DIAL);
    intent.setData(Uri.parse("tel:10086"));
    

向下个活动传递数据

  • 重载putExtra()
  • 传递字符串给SecondActivity
    String data = "Hello SecondActivity";
    Intent intent = new Intent("com.example.activitytest.ACTION_START");
    intent.putExtra("extra_data", data);
    startActivity(intent);
    
    • 第一个参数:key,用于取值
    • 第二个参数:传递的值
  • 在SecondActivity中取出数据
    Intent intent = getIntent();
    String data = intent.getStringExtra("extra_data");
    
    • getIntent():获取用于启动当前活动的Intent
    • getStringExtra():获取传递的字符串数据
      getIntExtra():获取传递的整型数据
      getBooleanExtra():获取传递的布尔型数据
      etc.

返回数据给上一个活动

  • startActivityForResult()启动活动并期望活动销毁时返回结果给上一个活动
    第一个参数:Intent
    第二个参数:请求码,用于在之后的回调中判断数据的来源
    • In FirstActivity:
      Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
      startActivityForResult(intent, 1);
      
    • In SecondActivity:
      Button button2 = (Button) findViewById(R.id.button_2);
      button2.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              Intent intent = new Intent();
              intent.putExtra("data_return", "Hello FirstActivity");
              setResult(RESULT_OK, intent);
              finish();
          }
      });
      
      • setResult():向上一个活动返回数据
        第一个参数:返回处理结果,一般只用RESULT_OKRESULT_CANCELED 第二个参数:把带有数据的Intent传回去
    • 使用startActivityForResult()启动的活动,销毁时会回调上一个活动的onActivityResult()
      在FirstAcitivity中重写这个方法来得到返回的数据
      @Override
      protected  void onActivityResult(int requestCode, int resultCode, Intent data) {
          switch (requestCode) {
              case 1:
                  if (resultCode == RESULT_OK) {
                      String returnedData = data.getStringExtra("data_return");
                      Log.d("FirstAcitivity", returnedData);
                  }
                  break;
              default:
          }
      }
      
      • requestCode:启动活动时传入的请求代码
        resultCode:返回数据时传入的处理结果
        data:携带着返回数据的Intent
      • 一个活动中可能调用startActivityForResult()启动很多不同的活动
        每个被启动的活动返回的数据都会回调onActivityResult()
        先检查requestCode判断数据来源
        再检查resultCode判断处理结果是否成功 最后从data中取值
    • 通过Back键返回的活动:重写onBackPressed()
      @Override
      public void onBackPressed() {
          Intent intent = new Intent();
          intent.putExtra("data_return", "Hello FirstActivity");
          setResult(RESULT_OK, intent);
          finish();
      }
      

活动的生命周期

返回栈

  • 一个任务就是一组存放在栈里的活动的集合

活动状态

  1. 运行状态
    • 位于返回栈的栈顶
    • 系统最不愿意回收的
  2. 暂停状态
    • 不再处于栈顶但仍然可见
    • 系统不愿意回收的(只有内存极低时)
  3. 停止状态
    • 不再处于栈顶并完全不可见
    • 系统会为其保存相应的状态和成员变量,但又可能会被回收(其他地方需要内存时)
  4. 销毁状态
    • 从返回栈中移除后
    • 最倾向于回收的

活动的生存期

  • 7个回调方法
    1. onCreate()
    • 在活动第一次被创建时调用
    • 活动初始化(加载布局、绑定事件)
    1. onStart()
    • 由不可见变为可见时调用
    • 资源加载
    1. onResume()
    • 在活动准备好和用户进行交互时调用
    • 此时活动一定位于返回栈的栈顶,并处于运行状态
    1. onPause()
    • 在系统准备启动或恢复另外一个活动时调用
    • 一般在这个方法中释放一些CPU资源,并保存一些关键数据
    • 执行速度一定要快
    • 启动对话框式的活动时会执行
    1. onStop()
    • 在活动完全不可见时调用
    • 启动对话框式的活动时不会执行
    • 释放资源(不占用过多内存)
    1. onDestroy()
    • 在活动被销毁钱调用
    • 释放内存
    1. onRestart()
    • 在活动由停止状态变为运行状态钱被调用(重新启动)
  • 3种生存期
    1. 完整生存期
    • onCreate()onDestroy()之间
    1. 可见生存期
    • onStart()onStop()之间
    • 可见的,又可能无法和用户交互
    1. 前台生存期
    • onResume()onPause()之间
    • 总是处于运行状态,可以和用户交互

将活动设置为对话框:在<activity>标签中添加属性

android:theme="@android:style/Theme.Dialog"

活动被系统回收

  • 在活动A的基础上启动了活动B,活动A被系统回收,用户按Back键返回活动A:
    不执行onRestart()而是执行OnCreate()->临时数据和状态消失
  • onSaveInstanceState()可以保证在活动被回收前一定会被调用
    携带一个Bundle类型的参数可以保存数据
    • putInt(), putString()...
    • 第一个参数是key,用于从Bundle中取值 第二个参数是要保存的内容
  • onCreate()有一个Bundle类型的参数(带有之前保存的数据)
  • Intent也可以用Bundle传递数据

活动的启动模式

standard

  • 默认
  • 每启动一个新的活动,都会在返回栈中入栈并处于栈顶
  • 系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新实例

singleTop

  • 启动活动时如果已经存在于栈顶,则直接使用它
  • 不在栈顶则创建一个新的实例

singleTask

  • 启动活动时检查返回栈中是否存在该活动的实例
  • 如果存在则直接使用该实例(不在栈顶会调用onRestart()),并把这个活动之上的所有活动全部出栈
  • 没有发现存在的实例则创建新实例
  • (如果指定了不同的taskAffinity,也会启动一个新的返回栈)

singleInstance

  • 启用一个新的返回栈来管理这个活动
  • 不管哪个应用程序来访问这个活动,共用同一个返回栈

其他

定位当前界面的活动

  • getCalss().getSimpleNAme()

随时注销/退出程序

  • 用一个专门的集合类(e.g. List)对所有活动进行管理
  • killProcesss():接收一个进程id参数,杀掉一个进程(只能用于杀掉当前程序的进程)
    myPid():获得当前程序的进程id