zoukankan      html  css  js  c++  java
  • Activity详解

      Activity是android应用的重要组成单元之一(另外3个是Service,BroadcastReceiver和ContentProvider)。实际应用包含了多个Activity,不同的Activity向用户呈现不同的操作界面。Android应用的多个Activity组成Activity栈,当前活动的Activity位于栈顶。对于Android应用而言,Activity主要负责与用户交互,并向用户呈现应用状态。

    1 建立、配置和使用Activity

    1.1 Activity类简介

    • 当一个Activity定义出来后,该Activity类何时被实例化、它所包含的方法何时被调用,这些都不是由开发者来决定,而是Android系统决定
    • 创建Activity需要重写一个或者多个方法。其中最常见的就是onCreate方法
    •  Activity相关类关系视图

      

    • AccountAuthenticatorActivity:实现账户管理界面的Activity
    • TabActivity实现Tab界面的Activity
    • ListActivity实现列表界面的Activity
    • AliasActivity:别名Activity的基类,启动其他Activity时结束自己
    • ExpandableListActivity实现可扩展列表界面的Activity
    • LauncherActivity:实现Activity列表界面的Activity,当单击列表时,所对应的Activity启动
    • PreferenceActivity:实现程序多参数设置,存储界面的Activity

      对于Activity的具体子类如ListActivity,LauncherActivity,ExpandableActivity等无需实现具体的布局文件,会自动调用默认布局文件。

    示例:PreferenceActivity的使用

    Activity文件

    import android.preference.PreferenceActivity;
    import android.preference.PreferenceFragment;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.Button;
    import android.widget.Toast;
    
    import java.util.List;
    
    public class PreferenceActivityTest extends PreferenceActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
    
            super.onCreate(savedInstanceState);
            if(hasHeaders()){
                Button button = new Button(this);
                button.setText("设置操作");
                setListFooter(button);
            }
        }
    
        public void onBuildHeaders(List<Header> target){
            loadHeadersFromResource(R.xml.preference_headers, target);
        }
    
         public boolean isValidFragment(String fragmentName){
             return   true;//super.isValidFragment(fragmentName);
             //return StockPreferenceFragment.class.getName().equals(fragmentName);
         }
    
        public static class Prefs1Fragment extends PreferenceFragment{
           @Override
            public void onCreate(Bundle savedInstanceState){
               super.onCreate(savedInstanceState);
               addPreferencesFromResource(R.xml.preferences);
           }
        }
    
        public static class Prefs2Fragment extends PreferenceFragment{
            public void onCreate(Bundle savedInstanceState){
                super.onCreate(savedInstanceState);
                addPreferencesFromResource(R.xml.display_prefs);
                String website = getArguments().getString("website");
                Toast.makeText(getActivity(),"网站域名是:" +  website, Toast.LENGTH_SHORT).show();
            }
        }
    }
    View Code

    Preference主页布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <preference-headers
        xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 指定启动指定PreferenceFragment的列表项 -->
        <header android:fragment=
            "com.example.penghuster.exampletest.PreferenceActivityTest$Prefs1Fragment"
            android:icon="@drawable/ic_settings_applications"
            android:title="程序选项设置"
            android:summary="设置应用的相关选项" />
        <!-- 指定启动指定PreferenceFragment的列表项 -->
        <header android:fragment=
            "com.example.penghuster.exampletest.PreferenceActivityTest$Prefs2Fragment"
            android:icon="@drawable/ic_settings_display"
            android:title="界面选项设置 "
            android:summary="设置显示界面的相关选项">
            <!-- 使用extra可向Activity传入额外的数据 -->
            <extra android:name="website"
                android:value="www.crazyit.org" />
        </header>
        <!-- 使用Intent启动指定Activity的列表项 -->
        <header
            android:icon="@drawable/ic_settings_display"
            android:title="使用Intent"
            android:summary="使用Intent启动某个Activity">
            <intent    android:action="android.intent.action.VIEW"
                android:data="http://www.crazyit.org" />
        </header>
    </preference-headers>
    View Code

    Fragment1布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 设置系统铃声 -->
        <RingtonePreference
            android:ringtoneType="all"
            android:title="设置铃声"
            android:summary="选择铃声(测试RingtonePreference)"
            android:showDefault="true"
            android:key="ring_key"
            android:showSilent="true">
        </RingtonePreference>
        <PreferenceCategory android:title="个人信息设置组">
            <!-- 通过输入框填写用户名 -->
            <EditTextPreference
                android:key="name"
                android:title="填写用户名"
                android:summary="填写您的用户名(测试EditTextPreference)"
                android:dialogTitle="您所使用的用户名为:" />
            <!-- 通过列表框选择性别 -->
            <ListPreference
                android:key="gender"
                android:title="性别"
                android:summary="选择您的性别(测试ListPreference)"
                android:dialogTitle="ListPreference"
                android:entries="@array/gender_name_list"
                android:entryValues="@array/gender_value_list" />
        </PreferenceCategory>
        <PreferenceCategory android:title="系统功能设置组 ">
            <CheckBoxPreference
                android:key="autoSave"
                android:title="自动保存进度"
                android:summaryOn="自动保存: 开启"
                android:summaryOff="自动保存: 关闭"
                android:defaultValue="true" />
        </PreferenceCategory>
    </PreferenceScreen>
    View Code

    Fragment2布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 设置系统铃声 -->
        <RingtonePreference
            android:ringtoneType="all"
            android:title="设置铃声"
            android:summary="选择铃声(测试RingtonePreference)"
            android:showDefault="true"
            android:key="ring_key"
            android:showSilent="true">
        </RingtonePreference>
        <PreferenceCategory android:title="个人信息设置组">
            <!-- 通过输入框填写用户名 -->
            <EditTextPreference
                android:key="name"
                android:title="填写用户名"
                android:summary="填写您的用户名(测试EditTextPreference)"
                android:dialogTitle="您所使用的用户名为:" />
            <!-- 通过列表框选择性别 -->
            <ListPreference
                android:key="gender"
                android:title="性别"
                android:summary="选择您的性别(测试ListPreference)"
                android:dialogTitle="ListPreference"
                android:entries="@array/gender_name_list"
                android:entryValues="@array/gender_value_list" />
        </PreferenceCategory>
        <PreferenceCategory android:title="系统功能设置组 ">
            <CheckBoxPreference
                android:key="autoSave"
                android:title="自动保存进度"
                android:summaryOn="自动保存: 开启"
                android:summaryOff="自动保存: 关闭"
                android:defaultValue="true" />
        </PreferenceCategory>
    </PreferenceScreen>
    View Code

    注意:需要重写PreferenceActivity的isValidFragment方法

    1.2 配置Activity

    • Android应用要求多有应用程序组件(Activity、Service、ContentProvider、BroadcastReceiver)都必须显式进行配置
    • 只需为<application/>元素添加<Activity />子元素即可,另外需要为Activity元素指定一个或者多个intent-filter,该元素用于指定该Activity可以响应的Intent
    • 从DDMS查看PreferenceActivity输出的配置文件

    1.3 启动关闭Activity

    1.3.1 一个Android应用通常会包含多个Activity,但只有一个Activity会作为程序入口-----但Android应用运行时将会自动启动并执行该Activity。其他Activity一般都由入口Activity启动,或者由入口启动的Activity启动,启动Activity的方法有如下两种:

    • startActivity(Intent intent):启动其他Activity
    • startActivityForResult(Intent intent,int requestCode):以指定的请求码(requestCode)启动Activity,而且程序将会等到新启动Activity的结果(通过重写onActivityResult()方法来获取)

    1.3.2 Activity关闭有两个方法:

    finish(),结束当前Activity

    • finishActivity(int requestCode):结束一startActivityForResult的Activity

    1.4 使用Bundle在Activity之间交换数据

      当一个Activity启动另一个Activity时,常常会有一些数据需要传过去,Activity之间的数据交换是通过Intent来完成,Intent提供了多个重载的方法来携带额外的数据,主要接口如下:

    操作对象 Intent Bundle
    发送

    putExtras( Bundle data)  /  putExtras(String name, Xxx value)

    putXxx(String key, Xxx data)  /  putSerializable(String key, Serializable data)
    接收

    Bundle getextras()         / Xxx getXxxExtras(String name)

    Xxx getXxx(String key)          /   Serializable getSerializable(String key)

    注意:Intent的putExtras方法是智能的,会根据Intent对象内是否存在Bundle对象而自动决定是否需要创建Bundle对象

    总结来说,一个有两种方法进行传输数据:

    • 利用Intent + 内置Bundle 传输数据方法

        发送:Intent intent = new Intent(BundleTest.this,ResultActivity.class);   intent.putExtra("person", (Serializable) p);

        接收:Intent intent = getIntent(); Person p = (Person)intent.getSerializableExtra("person");

    • 利用Intent + 自建Bungle 传输数据方法

        发送:Intent intent = new Intent(BundleTest.this,ResultActivity.class);  Bundle data = new Bundle(); 

                       data.putSerializable("person", p);    intent.putExtras(data);

        接收:Intent intent = getIntent();    Bundle data = intent.getExtras();    Person p = (Person)data.getSerializable("person");

    示例:

     发送Activity代码

    import org.crazyt.model.Person;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.RadioButton;
    
    import java.io.Serializable;
    
    public class BundleTest extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            Button bn = (Button) findViewById(R.id.bn);
            bn.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    EditText name = (EditText) findViewById(R.id.name);
                    EditText passwd = (EditText) findViewById(R.id.passwd);
                    RadioButton male = (RadioButton) findViewById(R.id.male);
                    String gender = male.isChecked() ? "男 " : "女";
                    Person p = new Person(name.getText().toString(), passwd
                            .getText().toString(), gender);
    
                    //创建一个Bundle对象
                    Intent intent = new Intent(BundleTest.this,
                            ResultActivity.class);
    
                    //1、利用Intent + 内置Bundle 传输数据方法
    //                intent.putExtra("person", (Serializable) p);
    
                    //2 、利用Intent + 自建Bungle 传输数据方法
                    Bundle data = new Bundle();
                    data.putSerializable("person", p);
                    intent.putExtras(data);
    
                    //启动intent对应的Activity
                    startActivity(intent);
                }
            });
        }
    }
    View Code

    接收Activity代码

    import org.crazyt.model.Person;
    
    public class ResultActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.result);
    
            TextView name = (TextView) findViewById(R.id.name);
            TextView passwd = (TextView) findViewById(R.id.passwd);
            TextView gender = (TextView) findViewById(R.id.gender);
    
            // 获取启动该Result的Inten
            Intent intent = getIntent();
    
            //直接利用Intent传输数据方法1
    //        Person p = (Person) intent.getSerializableExtra("person");
    
            //直接利用Intent传输数据方法2
            Bundle data = intent.getExtras();
            Person p = (Person) data.getSerializable("person");
    
            name.setText("您的用户名为:" + p.getName());
            passwd.setText("您的密码为:" + p.getPass());
            gender.setText("您的性别为:" + p.getGender());
    
        }
    }
    View Code

    效果图

    点击注册->

    1.5 启动其他Activity并返回结果

      简单地讲,就是当前Activity1启动另一个Activity2,Activity1需要获得Activity2的运行结果;而这也是通过Bundle进行数据交换的,为了获取被启动的Activity所返回的结果,需要从两方面入手:

    • 当前Activity需要重写onActivityResult(int requestCode, int resultCode, Intent intent),当被启动的Activity返回结果时,该方法将会被触发
    • 被启动的Activity需要调用setResult()方法设置处理结果

    示例:

    启动Activity代码

    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    
    import org.crazyt.model.Person;
    
    public class ResultActivity extends Activity
    {
        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.result);
        }
    
        public void click(View view){
            Intent intent = new Intent(ResultActivity.this,
                    BundleTest.class);
            startActivityForResult(intent,0);
        }
    
        public void onActivityResult(int requestCode, int resultCode, Intent intent){
            if (requestCode == resultCode){
                Bundle data  = intent.getExtras();
                Person result = (Person)data.getSerializable("person");
                TextView name = (TextView) findViewById(R.id.name);
                TextView passwd = (TextView) findViewById(R.id.passwd);
                TextView gender = (TextView) findViewById(R.id.gender);
                name.setText("您的用户名为:" + result.getName());
                passwd.setText("您的密码为:" + result.getPass());
                gender.setText("您的性别为:" + result.getGender());
            }
        }
    }
    View Code

    操作Activity代码

    import org.crazyt.model.Person;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.RadioButton;
    
    import java.io.Serializable;
    
    public class BundleTest extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            Button bn = (Button) findViewById(R.id.bn);
            bn.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    EditText name = (EditText) findViewById(R.id.name);
                    EditText passwd = (EditText) findViewById(R.id.passwd);
                    RadioButton male = (RadioButton) findViewById(R.id.male);
                    String gender = male.isChecked() ? "男 " : "女";
                    Person p = new Person(name.getText().toString(), passwd
                            .getText().toString(), gender);
    
                    Intent intent = getIntent();
                    Bundle data = new Bundle();
                    data.putSerializable("person", p);
                    intent.putExtras(data);
                    BundleTest.this.setResult(0, intent);
                    BundleTest.this.finish();
                }
            });
        }
    }
    View Code

    效果图

    -->-->

    2 Acitvity的回调机制

    2.1 定义

      所谓回调,对于一个具有通用性质的程序架构来说,程序架构完成整个应用的通用功能、流程,但在某个特定的点上,需要一段业务相关的代码-----而通用程序架构中无法实现这段代码,那么程序架构会在这个点上留一个空。

    2.2 对于java程序来说,程序架构在某点上留的空,可以以两种方式存在:

    • 以接口的形式存在,该接口由开发者实现,实现该接口时将会实现该接口的方法,那么通用程序架构就会按需回调该方法完成对应业务
    • 以抽象方法(也可以是非抽象方法)的形式存在,这些特定点的方法已经被定义,开发者可以选择性重写这些方法后,通用程序架构就会按需回调该方法完成对应业务

    3 Activity的生命周期

      当Activity处于Android应用中运行时,它的活动状态有android以Activity栈的形式管理,当前活动的Activity位于栈顶。随着不同应用的运行,每个Activity都可能从活动状态转入非活动状态,也可能从非活动状态转入活动状态。

    3.1 Activity生命周期的4个状态

    • 活动状态:当前Activity位于前台,用户可见,可以获取焦点
    • 暂停状态:其他Activity位于前台,该Activity仍然可见(处于全透明或非全屏状态),只是不能获取焦点
    • 停止状态:该Activity不可见,失去焦点
    • 销毁状态:该Activity结束,或Activity所在的dalvik进程被结束

    3.2 activity生命周期示意图

    4 Activity的四种加载模式

    4.1 Task管理方法

    • Android采用Task来管理多个Activity,当启动一个应用时,android就会为之创建一个Task,然后启动这个应用的入口Activity
    • Task是以Activity栈的方式来管理Activity的,先启动的放在Task栈底,后启动的放在Task栈顶。
    • Android没有提供Task的API,Task无法访问,只能调用Activity的getTaskId()方法获取当前Activity所在的Task
    • Activity的加载模式就是负责管理和控制Activity实例化、加载方式、以及与Task之间的加载关系

    4.2 standard:标准模式,这是默认加载模式

      每次通过standard模式来启动Activity时,Android总会为目标Activity创建一个新的Activity实例,并将该实例添加到当前的Task栈中。

    4.3 singleTop:Task顶单例模式

      此模式与standard模式基本类似,唯一不同:当将要被启动的目标Activity已经位于Task栈顶时,系统不会重新创建目标Activity实例,而是直接复用栈顶已有Activity实例

    4.4 singleTask:Task内单例模式

      采用singleTask模式的Activity在同一个Task内只有一个实例,当系统采用singleTask模式启动目标Activity时,分为以下三种情况:

    • 如果启动的目标Activity不存在,系统将会创建目标Activity实例,并置于栈顶
    • 如果启动的目标Activity已经位于Task栈顶,则复用该Activity实例,与singleTop模式相同
    • 如果启动的目前Activity已经存在,但不位于Task栈顶,系统将会把位于该Activity上面的所有Activity实例移出Task栈,从而使得目标Activity转入栈顶

    • 4.5 singleInstance:全局单例模式

      采用singleInstance模式,系统保证无论哪个Task中启动目标Activity,只会创建一个目标Activity实例,并会使用一个全新的Task栈来装载该实例。当系统采用singleInstance模式启动目标Activity时,可以分为以下两种情况:

    • 如果将要启动的目标Activity不存在,系统将会先创建一个全新的Task,在创建目标Activity的实例,并将其加入新的Task的栈顶
    • 如果将要启动的目标Activity已经存在,无论位于哪个应用程序中,无论位于哪个Task中,系统将会把该Activity转到前台,从而使该Activity显示出来
    • 采用该模式加载的Activity总是位于task栈顶,且加载该Activity的Task栈中只有该Activity
  • 相关阅读:
    【Android】【踩坑日记】RecyclerView获取子View的正确姿势
    【Thinking in Java】编写构造器时应注意:尽量避免调用其他非private方法
    为什么匿名内部类只能访问final变量【转】
    【Thinking in Java】类和对象的初始化过程
    【Thinking in Java】Java Callable的使用
    【算法与数据结构】二叉搜索树的Java实现
    【Thinking in Java】组合、继承和代理的区别
    【面试经历】腾讯一二面分享与总结
    【面试经历】腾讯、网易有道和阿里的笔试分享及自我总结
    《Unity預計算即時GI》笔记:三、Clusters和总结
  • 原文地址:https://www.cnblogs.com/penghuster/p/4892359.html
Copyright © 2011-2022 走看看