建立、配置和使用Activity——Activity

        Activity是Android应用中最重要、最常见的应用组件(此处的组件是粗粒度的系统组成部分,并非指界面控件:widget)。Android应用的一个重要组成部分就是开发Activity,下 面将会详细介绍Activity开发、配置的相关知识。

       Activity

       与开发Web应用时建立Servlet类相似,建立自己的Activity也需要继承Activity基类,当然,在不同应用场景下,有时也要求继承Activity的子类。例如如果应用程序界面只包括列表,则可以让应用程序继承ListActivity;如果应用程序界面需要实现标签页效果,则可以让应用程序继承TabActivity。

      图4.1显示了Android提供的Activity类。

 

       如图4.1所示,Activity类间接或直接地继承了Context、ContextWrapper、ContextThemeWrapper等基类,因此Activity可以直接调用它们的方法。

       与Servlet类似,当一个Activity定义出来之后,这个Activity类何时被实例化、它所包含的方法何时被调用,这些都不是由开发者决定的,都应该由安卓系统来决定。

      为了让Servlet能响应用户请求,开发者需要重写HttpServlet的doRequest(...)、doResponse(...)方法,或重写service(...)方法。Activity与此类相似,创建一个Activity也需要实现一个或多个方法,其中最常见的就是实现onCreate(Bundle status)方法,该方法将会在Activity创建时被回调,该方法调用Activity的setContentView(View view)方法来显示要展示的View。为了管理应用程序中的各种组件,调用Activity的findViewById(int id)方法来获取程序界面中的组价,接下来去修改格组件的属性和方法即可。

      实例:用LauncherActivity开发启动Activity的列表。

     通过前几章的实例介绍了Activity、ListActiviy、TabActivity等基类的用法,接下来开发一个继承LauncherActivity的应用。

      LauncherActivity继承了ListActivty,因此它本质上也是一个开发列表界面的Activity,但它开发出来的列表界面与普通列表界面有所不同。它开发出来的列表界面中的每个列表项都对应一个Intent,因此当用户单击不同的列表项时,应用程序会自动启动对应的Activity。

      使用LauncherActivity的方法并不难,由于依然是一个ListActivity,因此同样需要为它设置Adapter——既可使用简单的ArrayAdapter,也可使用SimpleAdapter,当然也可以扩展BaseAdapter来实现自己的Adapter。与使用普通ListActivity不同的是,继承LauncherActivity时通常应该重写Intent intentForPosition(int position)方法,该方法根据不同列表项返回不同的Intent(用于启动不同的Activity)。

      下面的程序中是一个LauncherActivity的子类。

package com.example.studyactivity;

import android.os.Bundle;
import android.app.Activity;
import android.app.LauncherActivity;
import android.content.Intent;
import android.view.Menu;
import android.widget.ArrayAdapter;

public class OtherActivity extends LauncherActivity {

    //定义两个Activity的名称
    String[] names={"设置程序参数","查看星际兵种"};
    //定义两个Activity对应的实现类
    Class<?>[] clazzs={PreferenceActivityTest.class,ExpandableListActivityTest.class};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1,names);
        //设置该窗口显示列表所需的Adapter
        setListAdapter(adapter);
    }
    @Override
    protected Intent intentForPosition(int position) {
        // TODO Auto-generated method stub
        return new Intent(OtherActivity.this,clazzs[position]);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.other, menu);
        return true;
    }
    
}

上面的程序中第一行粗体字代码为该ListActivity设置了所需的内容Adapter,第二段粗体字代码则根据用户单击的列表项去启动对一个的Activity。

    上面的程序还用到了如下两个Activity。

  •  ExpandableListActivityTest:它是ExpandableListActivityTest的子类,用于显示一个可展开的列表窗口。
  •  PreferenceActiviyTest:它是PreferenceActivity的子类,用于显示一个显示设置选项参数并进行保存的窗口。

    实例:使用ExpandableListActivity实现可展开的Activity  

    ExpandableListActivityTest,它继承了ExpandableListActivty的基类,ExpandableListActivity的用法与前面介绍的ExpandableListView的用法基本相似,只要为该Activity传入一个ExpandableListAdapter对象即可,接下来ExpandableListActivity将会生成一个显示可展开列表的窗口。

    下面是ExpandableListActivityTest的代码。

package com.example.studyactivity;

import android.os.Bundle;
import android.app.Activity;
import android.app.ExpandableListActivity;
import android.database.DataSetObserver;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ExpandableListAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class ExpandableListActivityTest extends ExpandableListActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ExpandableListAdapter adapter=new ExpandableListAdapter(){
            int[] logos=new int[]{R.drawable.p,R.drawable.z,R.drawable.t};
            private String[] armTypes=new String[]{"神族兵种","虫族兵种","人族兵种"};
            private String[][] arms=new String[][]{
                    {"狂战士","龙骑士","黑暗圣堂","电兵"},
                    {"小狗","刺蛇","飞龙","自爆飞机"},
                    {"机枪手","护士MM","幽灵"}
            };
            @Override
            public boolean areAllItemsEnabled() {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public Object getChild(int groupPosition, int childPosition) {
                // TODO Auto-generated method stub
                return arms[groupPosition][childPosition];
            }

            @Override
            public long getChildId(int groupPosition, int childPosition) {
                // TODO Auto-generated method stub
                return childPosition;
            }
            //该方法决定每个子选项的外观   
            @Override
            public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
                    View convertView, ViewGroup parent) {
                // TODO Auto-generated method stub
                TextView textView=getTextView();
                textView.setText(getChild(groupPosition,childPosition).toString());
                return textView;
            }

            @Override
            public int getChildrenCount(int groupPosition) {
                // TODO Auto-generated method stub
                return arms[groupPosition].length;
            }
            
            private TextView getTextView()
            {
                AbsListView.LayoutParams lp=new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,64);
                TextView textView=new TextView(ExpandableListActivityTest.this);
                textView.setLayoutParams(lp);
                textView.setGravity(Gravity.CENTER_VERTICAL|Gravity.LEFT);
                textView.setPadding(36, 0, 0, 9);
                textView.setTextSize(20);
                return textView;
            }
            @Override
            public long getCombinedChildId(long arg0, long arg1) {
                // TODO Auto-generated method stub
                return 0;
            }

            @Override
            public long getCombinedGroupId(long groupId) {
                // TODO Auto-generated method stub
                return 0;
            }

            @Override
            public Object getGroup(int groupPosition) {
                // TODO Auto-generated method stub
                return armTypes[groupPosition];
            }

            @Override
            public int getGroupCount() {
                // TODO Auto-generated method stub
                return armTypes.length;
            }

            @Override
            public long getGroupId(int groupPosition) {
                // TODO Auto-generated method stub
                return groupPosition;
            }

             //该选项决定每个组选项的外观
            @Override
            public View getGroupView(int groupPosition, boolean isExpanded,
                    View convertView, ViewGroup parent) {
                // TODO Auto-generated method stub
                LinearLayout ll=new LinearLayout(ExpandableListActivityTest.this);
                ll.setOrientation(0);
                ImageView logo=new ImageView(ExpandableListActivityTest.this);
                logo.setImageResource(logos[groupPosition]);
                ll.addView(logo);
                TextView textView=getTextView();
                textView.setText(getGroup(groupPosition).toString());
                ll.addView(textView);
                
                return ll;
            }

            @Override
            public boolean hasStableIds() {
                // TODO Auto-generated method stub
                return true;
            }

            @Override
            public boolean isChildSelectable(int groupPosition,
                    int childPosition) {
                // TODO Auto-generated method stub
                return true;
            }

            @Override
            public boolean isEmpty() {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public void onGroupCollapsed(int groupPosition) {
                // TODO Auto-generated method stub
                
            }

            @Override
            public void onGroupExpanded(int groupPosition) {
                // TODO Auto-generated method stub
                
            }

            @Override
            public void registerDataSetObserver(DataSetObserver observer) {
                // TODO Auto-generated method stub
                
            }

            @Override
            public void unregisterDataSetObserver(DataSetObserver observer) {
                // TODO Auto-generated method stub
                
            }};
        //设置该窗口的显示列表
            setListAdapter(adapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.expandable_list_activity_test, menu);
        return true;

    }

}

上面的程序中粗体字代码为ExpandableListActivity设置了一个ExpandableListAdpter对象,即可使得该Activity实现可展开列表的窗口。

    实例:PreferenceActivity结合PreferenceFragment实现参数设置界面

    PreferenceActivity是一个非常有用的基类,当我们开发一个Android应用程序时,不可避免地需要进行选项设置,这些选项设置会以参数的形式保存,习惯上我们会用Preferences进行保存。

    需要指出的是,如果Android应用程序中包含的某个Activity专门用于设置选项参数,那么Android为这种Activity提供了便捷的基类:PreferenceActivity。

    一旦Activity继承了PreferenceActivity,那么该Activity完全不需自己控制Preferences的读写,PreferenceActivity会为我们处理一切。

   PreferenceActivity与普通Activity不同,它不再使用普通的界面布局文件,而是使用选型设置的布局文件。选项设置的布局文件以PreferenceScreen作为根元素——它表明定义一个参数设置的界面布局。

    为了创建一个PreferenceActivity,需要先创建一个对应的界面布局文件。从Android3.0开始,Android不再推荐直接让PreferenceActivity加载选项设置的布局文件。而建议将PreferenceActivity与FreferenceFragment结合使用,其中PreferenceActivity只负责加载选项设置列表的布局文件,PreferenceFragment才负责加载选项设置的布局文件。

   本实例中PreferenceActivity加载的选项设置列表布局文件如下:

   

<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- 指定启动指定PreferenceFragment 的列表项 -->
   <header android:fragment="com.example.studyactivity.PreferenceActivityTest$Prefs1Fragment"
       android:icon="@drawable/ic_settings_applications"
       android:title="程序选项设置"
       android:summary="设置应用的相关选项"
       />
    <!-- 指定启动指定PreferenceFragment的列表项 -->
    <header android:fragment="com.example.studyactivity.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>

    上面的布局文件中指定使用Prefs1Fragment、Prefs2Fragment两个内部类,为此我们将会在PreferenceActivityTest类中定义这两个内部类。下面是PreferenceActivityTest的代码。

package com.example.studyactivity;

import java.util.List;

import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceActivity.Header;
import android.preference.PreferenceFragment;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;

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);
        }
    }
    //重写该方法负责加载页面布局文件
    @Override
    public void onBuildHeaders(List<Header> target) {
        // TODO Auto-generated method stub
        
        //加载选项设置列表的布局文件
        loadHeadersFromResource(R.xml.preference_headers,target);
    }
    public static class Prefs1Fragment extends PreferenceFragment
    {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
        }
    }
    
    public static class Prefs2Fragment extends PreferenceFragment
    {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            // TODO Auto-generated method stub
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.display_prefs);
            //获取传入该Fragment的参数
            String website=getArguments().getString("website");
            Toast.makeText(getActivity(), "网站域名:"+website, Toast.LENGTH_LONG).show();
        }
        
        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.preference_activity_test, menu);
        return true;
    }

}

     上面的Activity重写了PreferenceActivity的public void onBuildHeaders(List<Header> target)方法,重写该方法指定加载前面定义preference_headers.xml布局文件。

     上面的Activity中定义了两个PreferenceFragment,它们需要分别加载preferences.xml、display_prefs.xml两个选项设置的布局文件。
      建立选项设置的布局文件需要创建根元素为PreferenceScreen的xml布局文件,它默认保存在/res/xml路径下。

     preferences.xml布局文件如下:

<?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="选择铃声(测试RingtionePreference)"
        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="您所使用的用户名为:"  ></EditTextPreference>
        <!-- 通过列表框选择性别 -->
        <ListPreference 
            android:key="gender"
            android:title="性别"
            android:summary="选择您的性别(测试ListPreference)"
            android:dialogTitle="ListPreference"
            android:entries="@array/gender_name_list"
            android:entryValues="@array/gender_value_list"
            > </ListPreference >
    </PreferenceCategory>
    <PreferenceCategory  android:title="系统功能设置组">
        <CheckBoxPreference
            android:key="autoSave"
            android:title="自动保存进度"
            android:summaryOn="自动保存:开启"
            android:summaryOff="自动保存:关闭"
            android:defaultValue="true"> </CheckBoxPreference >
    </PreferenceCategory>
    

</PreferenceScreen>

     上面的界面布局文件定义了一个参数设置界面,该参数设置界面中包括两个参数设置组,而且该惨呼设置界面全面应用了各种元素,这样方便读者以后查询。
     一旦定义了参数设置的界面布局文件之后,接下来在PreferenceFragment程序中使用该界面布局文件进行参数设置、保存十分简单,只要如下两步即可。

  1. 让Fragment继承PreferenceFragment
  2. 在onCreate(Bundle saveInstanceState)方法中调用addPreferencesFromRsource(...)方法加载指定的界面布局文件。

       上面的实例中还用到了一个display_prefs.xml选项设置布局文件,该布局文件的创建步骤与preferences.xml文件的创建步骤相同。该文件的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory>
        <!-- 通过列表项选择灯光强度 -->
        <ListPreference android:key="light"
            android:title="灯光强度"
            android:summary="请选择灯光强度(测试ListPreference)"
            android:dialogTitle="请选择灯光强度"
            android:entries="@array/light_strength_list"
            android:entryValues="@array/light_value_list"/>
    </PreferenceCategory>
    <PreferenceCategory>
        <!-- 通过SwitchPreference设置是否自动滚屏 -->
        <SwitchPreference 
            android:key="autoScroll"
            android:title="自动滚屏"
            android:summaryOn="自动滚屏:开启"
            android:summaryOff="自动滚屏:关闭"
            android:defaultValue="true" />
    </PreferenceCategory>
    

</PreferenceScreen>

至此,我们为该应用程序开发了三个Activity类,但这三个Activity还不能使用,还必须在AndroidManifest.xml清单文件中配置Activity才行。

  配置Activity

  Android应用要求所有应用程序组件(Activty、Services、ContentProvider、BroadcastReceiver)都必须显示进行配置。

  只要为<application.../>元素添加<activity...>子元素即可配置Activity。例如下面的配置片段:

<activity
            android:name="com.example.studyactivity.PreferenceActivityTest"
            android:icon="@drawable/ic_settings_applications"
            android:label="@string/title_activity_preference_activity_test" 
            android:exported="true"
            android:launchMode="singleInstance">
       ...                 
</activity>

   从上面的配置片段可以看出,配置Activity时通常指定如下几个属性。

  1. name:指定该Activity的实现类的类名。
  2. icon:指定该Activity对应的图标。
  3. label:指定该Activity的标签。
  4. exported:指定该Activity是否允许被其他应用调用。如果将该属性设为true,那么该Activity将可以被其他应用调用。
  5. launchMode:指定该Activity的加载模式,该属性支持standard、singleTop、singleTask和singleInstance这4种加载模式。

      除此之外,配置Activity时通常还需要指定一个或多个<intent-filter.../>元素,该元素用于指定该Activity可响应的Intent。

 为了在AndroidManifest.xml布局文件中配置、管理上面的三个Activity,可以在清单文件的<application.../>元素中增加如下三个<activity.../>子元素

  <activity
            android:name="com.example.studyactivity.OtherActivity"
            android:label="@string/app_name" >
<!--指定该Activity是程序的入口-->
            <intent-filter>

                <action android:name="android.intent.action.MAIN" />


              <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter>
        </activity>
        <activity
            android:name="com.example.studyactivity.ExpandableListActivityTest"
            android:label="查看星际兵种" >
            
        </activity>
        <activity
            android:name="com.example.studyactivity.PreferenceActivityTest"
            android:icon="@drawable/ic_settings_applications"
            android:label="设置程序参数" 
           >
        </activity>

上面的配置片段配置了三个Activity,其中第一个Activity还配置了一个<intent-filter.../>元素,该元素指定该Activity作为应用程序的入口。

     运行上面的应用程序,将看到如图4.6所示的界面。

 

  在图4.6所示的程序界面中,用户单击任意列表项即可启动对应额Activity,例如单击“设置程序参数”将会启动PreferenceActivityTest。单击“查看星际兵种”将会启动ExpandableListAcivityTest。单击4.6所示列表的第一个列表项将看到如图4.7所示的界面。

 图4.7就是利用PreferenceActivity生成的选项设置列表界面。这个界面只是包含三个列表项,其中前两个列表项用于启动PreferenceFragment,最后一个列表项将会根据Intent启动其他Activity。

  单击图4.7所示界面的第一个列表项,将可以看到如图4.8所示界面。

图4.8所示界面就是利用PreferencesFragment生成的选项设置界面,这个界面非常漂亮,而且系统会自动将设置的参数永久地保存到系统中——这都得益于PreferenceActivity。例如我们单击图4.8所示界面中的“填写用户名”列表项,系统将会显示如图4.9所示的输入框。

如果单击图4.6所示列表框中第二个列表项,将看到如图4.11所示的界面。

posted @ 2013-11-11 19:11  TealerProg  Views(1282)  Comments(0Edit  收藏  举报