第二篇:http://blog.csdn.net/mapdigit/article/details/7555404
创建好ApiDemos项目以后,首先在模拟器上运行该程序,可以看到主界面是一个列表。单击列表中一个栏目后还有若干级列表,最终是一个Activity,展示了其API的一个特性。API Demos全面展示了系统的功能,包括界面、控件、图像处理和媒体处理等。













然后逐个来分析代码:
首先我们去AndroidManifest.xml文件中查看下app的入口,
1<activity android:name=".app.HelloWorld" android:label="@string/activity_hello_world">
2            <intent-filter>
3                <action android:name="android.intent.action.MAIN" />
4                <category android:name="android.intent.category.SAMPLE_CODE" />
5            </intent-filter>
6        </activity>

可以看到入口是ApiDemos类,并且可以通过
1<manifest xmlns:android="http://schemas.android.com/apk/res/android"  package="com.example.android.apis">
2
3</manifest>

可以知道该类在com.example.android.apis下,同时我们可以看到很多Activity都带有
1<intent-filter>
2                <action android:name="android.intent.action.MAIN" />
3                <category android:name="android.intent.category.SAMPLE_CODE" />
4</intent-filter>
这个过滤器,并且它们都带有label。

然后我们可以找到com.example.android.apis包下的ApiDemos类,



该类继承了ListActivity,主要用来列出ApiDemos中的200多个实例,实例采取分类层次显示。


getData(String) 获取显示的数据
sDisplayNameConparator对名称按照字母顺序进行排序

前三个界面之间跳转使用的是browseIntent,
从第三个界面跳转到第四个界面使用的是activityIntent
addItem():增加数据
onListItemClick:响应某一个ListItem的点击事件,启动一个Activity



ListActivity是一个把列表和列表内容绑定的Activity,在用户单击这些列表时,响应用户操作。这就是说,列表只是一个框架,列表内容是开发者指定的,列表可以和不同的数据源进行绑定。就像这个程序的各级菜单,列表形式都一样,只是每一级菜单的数据源不同。现在我们可以理解APIDemos的主要工作了:在onCreate中获取每一级菜单的列表内容,并和列表绑定;在onListItemClick中实现单击该项目的响应,响应是以Intent方法实现的,通过Intent来启动另外的Activity。

在ApiDemos 的 onCreate()方法
 1@Override
 2    public void onCreate(Bundle savedInstanceState) {
 3        super.onCreate(savedInstanceState);
 4        
 5        Intent intent = getIntent();
 6        String path = intent.getStringExtra("com.example.android.apis.Path");
 7        
 8        if (path == null{
 9            path = "";
10        }

11
12        setListAdapter(new SimpleAdapter(this, getData(path),
13                android.R.layout.simple_list_item_1, new String[] "title" },
14                new int[] { android.R.id.text1 }));
15        getListView().setTextFilterEnabled(true);
16    }


android.R.layout_simple_list_item_1是android系统自带的资源文件,位于/ 
  • frameworks / base / cor
  • e / res / res / layout / simple_list_item_1.xml

  •  1<?xml version="1.0" encoding="utf-8"?>
     2<!-- Copyright (C) 2006 The Android Open Source Project
     3
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8          http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15-->
    16
    17<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    18    android:id="@android:id/text1"
    19    android:layout_width="match_parent"
    20    android:layout_height="wrap_content"
    21    android:textAppearance="?android:attr/textAppearanceListItemSmall"
    22    android:gravity="center_vertical"
    23    android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
    24    android:paddingRight="?android:attr/listPreferredItemPaddingRight"
    25    android:minHeight="?android:attr/listPreferredItemHeightSmall"
    26/>
    可以看到该布局文件仅仅显示一个TextView,它的id为android.R.id.text1 



    1AbsListView.setTextFilterEnabled(true);
  • 这个方法的作用是用来过滤选项的例如在软键盘上打出一个a,则会过滤掉除了a开头的所有选项(在模拟器上可以看到效果,在真机上弹不出软键盘)

     1protected List<Map<String, Object>> getData(String prefix) {
     2        List<Map<String, Object>> myData = new ArrayList<Map<String, Object>>();
     3
     4        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
     5        mainIntent.addCategory(Intent.CATEGORY_SAMPLE_CODE);
     6
     7        PackageManager pm = getPackageManager();
     8        List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
     9
    10        if (null == list)
    11            return myData;
    12
    13        String[] prefixPath;
    14        String prefixWithSlash = prefix;
    15        
    16        if (prefix.equals("")) {
    17            prefixPath = null;
    18        }
     else {
    19            prefixPath = prefix.split("/");
    20            prefixWithSlash = prefix + "/";
    21        }

    22        
    23        int len = list.size();
    24        
    25        Map<String, Boolean> entries = new HashMap<String, Boolean>();
    26
    27        for (int i = 0; i < len; i++{
    28            ResolveInfo info = list.get(i);
    29            CharSequence labelSeq = info.loadLabel(pm);
    30            String label = labelSeq != null
    31                    ? labelSeq.toString()
    32                    : info.activityInfo.name;
    33            
    34            if (prefixWithSlash.length() == 0 || label.startsWith(prefixWithSlash)) {
    35                
    36                String[] labelPath = label.split("/");
    37
    38                String nextLabel = prefixPath == null ? labelPath[0] : labelPath[prefixPath.length];
    39
    40                if ((prefixPath != null ? prefixPath.length : 0== labelPath.length - 1{
    41                    addItem(myData, nextLabel, activityIntent(
    42                            info.activityInfo.applicationInfo.packageName,
    43                            info.activityInfo.name));
    44                }
     else {
    45                    if (entries.get(nextLabel) == null{
    46                        addItem(myData, nextLabel, browseIntent(prefix.equals(""? nextLabel : prefix + "/" + nextLabel));
    47                        entries.put(nextLabel, true);
    48                    }

    49                }

    50            }

    51        }

    52
    53        Collections.sort(myData, sDisplayNameComparator);
    54        
    55        return myData;
    56    }

     

    知道列表的构成和响应后,我们接下来看看列表是如何被获取的,获取列表是在getData方法中,该方法获取的数据作为SimpleAdapter的参数,最终被ListActivity所使用。getData中有若干个重要的对象,如myData是我们需要获取的菜单列表数据;prefix是当前所处的目录,如果为空则为根目录; prefixPath是当前目录的列表,列表中包含了当前的每一级目录的内容;list是当前可以被执行的所有Activity列表。程序是怎么知道当前有哪些可以执行的Activity的呢?请看下面两行代码:

            Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
            mainIntent.addCategory(Intent.CATEGORY_SAMPLE_CODE);

     

  • 在java中,如果要对集合对象或数组对象进行排序,需要实现Comparator接口以达到我们想要的目标。
  •  

    1private final static Comparator<Map<String, Object>> sDisplayNameComparator =
    2        new Comparator<Map<String, Object>>() {
    3        private final Collator   collator = Collator.getInstance();
    4
    5        public int compare(Map<String, Object> map1, Map<String, Object> map2) {
    6            return collator.compare(map1.get("title"), map2.get("title"));
    7        }

    8    }
    ;


    loadLabel() 查找顺序

    1、先找activity的Lable, 如果没有找到则下一步

    2、找application的Lable, 如果没有找到则下一步

    3、找activity的name  名字一定会有的

    它通过PackageManager 从 AndroidManifest.xml中读取所以Intent-Filter含有:Intent.ACTION_MAIN和Intent.CATEGORY_SAMPLE_CODE所有Activity信息。前面说过200多个示例根据其功能分类,比如 Hello World示例它的Label为

    App/Activity/Hello World,

    表示它的分类为分类App下Activity子类。

    getData(String prefix)根据每个Activity的Label属性和当前层次(prefix)来决定当前列表中某项为叶子列表项,还是分类列表项,如果是叶子列表项,则添加为activityIntent,当用户点击改列表项时则会触发该示例。若是分类列表项,则添加为browseIntent,browseIntent还是触发ApiDemos Activity,但Intent带有Extra信息,表示需要显示改分类下的子类:

     

     1protected Intent activityIntent(String pkg, String componentName) {
     2
     3        Intent result = new Intent();
     4
     5        result.setClassName(pkg, componentName);
     6
     7        return result;
     8
     9    }

    10
    11





    此时如果用户点击该节点列表项,则会进入该分类的下级目录。

    1 @Override
    2    @SuppressWarnings("unchecked")
    3    protected void onListItemClick(ListView l, View v, int position, long id) {
    4        Map<String, Object> map = (Map<String, Object>)l.getItemAtPosition(position);
    5
    6        Intent intent = (Intent) map.get("intent");
    7        startActivity(intent);
    8    }


    此外,ApiDemos还定义了ApiDemosApplication,该类继承了Application,如果需要在多个Activity共享一些数据,可以定义在Application中。

     





     1/*
     2 * Copyright (C) 2007 The Android Open Source Project
     3 *
     4 * Licensed under the Apache License, Version 2.0 (the "License");
     5 * you may not use this file except in compliance with the License.
     6 * You may obtain a copy of the License at
     7 *
     8 *      http://www.apache.org/licenses/LICENSE-2.0
     9 *
    10 * Unless required by applicable law or agreed to in writing, software
    11 * distributed under the License is distributed on an "AS IS" BASIS,
    12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13 * See the License for the specific language governing permissions and
    14 * limitations under the License.
    15 */

    16
    17package com.example.android.apis;
    18
    19import android.app.Application;
    20
    21/**
    22 * This is an example of a {@link android.app.Application} class.  This can
    23 * be used as a central repository for per-process information about your app;
    24 * however it is recommended to use singletons for that instead rather than merge
    25 * all of these globals from across your application into one place here.
    26 * 
    27 * In this case, we have not defined any specific work for this Application.
    28 * 
    29 * See samples/ApiDemos/tests/src/com.example.android.apis/ApiDemosApplicationTests for an example
    30 * of how to perform unit tests on an Application object.
    31 */

    32public class ApiDemosApplication extends Application {
    33    @Override
    34    public void onCreate() {
    35    }

    36}

    37



    可以看到该类什么都干。


    如果使用了自定义的Application,别忘了修改AndroidManifest.xml ,如下:

    1<application android:name="ApiDemosApplication"
    2            android:label="@string/activity_sample_code"
    3            android:icon="@drawable/app_sample_code"
    4            android:hardwareAccelerated="true">
    5
    6</application>


    最后我们看下Shakespeare这个常量类,

    该类定义了两个字符串数组,这两个数组在以后会用到。
    至此,com.example.android.apis包下的文件已经全部搞定了。