前言

最近在研究PreferenceActivity发现是继承自ListActivity的,打开看了下ListActivity的源码,发现也不长,就详细阅读认识一下。

正文

ListActivity简单到只要在onCreate()中调用setListAdapter()方法就可以实现了。
支持空数据显示。

点进去我们看到前两个field很熟悉,就是一个ListView+Adapter
很容易就知道这两个field就是ListActivity的核心,数据存储在Adapter中,展示在ListView中。

    protected ListAdapter mAdapter;
protected ListView mList;
/** 省略部分代码 */
public void setListAdapter(ListAdapter adapter) {
//加上锁,防止多个线程同时调用这个方法
synchronized (this) {
ensureList();//内含setContentView的方法
mAdapter = adapter;
mList.setAdapter(adapter);
}
}

在调用了setListAdapter()之后,对Adapter重新赋值,并重新设置ListViewAdapter,并且调用了ensureList()方法,重新创建布局。
点进ensureList()方法。

    private void ensureList() {
if (mList != null) {
return;
}
setContentView(com.android.internal.R.layout.list_content_simple);
}

哈!原来每次setListAdapter()都会把Adapter替换掉,并且重新setContentView(),怪不得ListActivity不用我们操心布局。
我们再来看看这个布局的内容

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"
/>

也就是说,你可以自己setContentView(),只要你的布局有一个viewIdandroid:id="@android:id/list"的就行。
看到这你可能会无语,就一个简单的ListView就完事了?这么简单我也会啊!
别急,这只是完成了基本的功能而已,还要开放一些接口给子Activity调用。
有了ListView当然要实现各种事件啊。

public void setSelection(int position) {
mList.setSelection(position);
}
public int getSelectedItemPosition() {
return mList.getSelectedItemPosition();
}
public long getSelectedItemId() {
return mList.getSelectedItemId();
}

当然还有点击事件,我们发现有一个点击的监听器mOnClickListener

private AdapterView.OnItemClickListener mOnClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onListItemClick((ListView)parent, v, position, id);
}
};
protected void onListItemClick(ListView l, View v, int position, long id) {
//空方法,交由子类实现
}

既然有监听器,那又是在哪里设置了这个监听器呢?我们发现有一个onContentChanged()方法。

    public void onContentChanged() {
super.onContentChanged(); //Activity中是空方法
View emptyView = findViewById(com.android.internal.R.id.empty); //空数据时显示
mList = (ListView)findViewById(com.android.internal.R.id.list); //绑定ListView
if (mList == null) {
throw new RuntimeException( "Your content must have a ListView whose id attribute is "
+ "'android.R.id.list'");
}
if (emptyView != null) {
mList.setEmptyView(emptyView); //多好啊,recyclerView就没有这个方法
}
mList.setOnItemClickListener(mOnClickListener); //设置点击事件
if (mFinishedStart) {
// 这个if不知道有什么用意
setListAdapter(mAdapter);
}
mHandler.post(mRequestFocus); //待会解释
mFinishedStart = true;
}

可是翻遍源代码也没发现哪里调用了onContentChanged()
从字面上看,onContentChanged()Content改变时的回调接口,等等,Content
我们不是在ensureList()中调用了setContentView()方法吗?
答案是正确的,在调用了setContentView(),会调用onContentChanged()

// Activity的setContentView()调用Window(具体子类是PhoneWindow)的setContentView()方法
// 以下代码出现在PhoneWindow中
@Override
public void setContentView(int layoutResID) {
/** 省略部分代码 */
mLayoutInflater.inflate(layoutResID, mContentParent);
getCallback().onContentChanged(); //注意这里!!!
}

再解释下,上面的mHandler.post(mRequestFocus);

    private Runnable mRequestFocus = new Runnable() {
public void run() {
// 用来使ListView获取焦点。
mList.focusableViewAvailable(mList);
}
};
protected void onDestroy() {
// Activity销毁时移除
mHandler.removeCallbacks(mRequestFocus);
super.onDestroy();
}

至此,ListActivity已经认识的差不多了。有什么讲错了希望能有大牛来提点一下。
有兴趣的可以自己用recyclerView替换listView实现一个RecyclerActivity.

更多相关文章

  1. 由Android架构图所想到的Android开发学习方向方法
  2. SharedPreference.Editor的apply和commit方法异同
  3. Android无法加载第三方so的解决方法
  4. 有没有方法在不root手机的情况下读取Data目录下的文件
  5. Android中横竖屏切换时,onConfigurationChanged方法不被调用
  6. android中保存一个ArrayList到SharedPreferences的方法
  7. Android中Broadcast Receiver的两种注册方法和区别
  8. E/JavaBinder:FAILED BINDER TRANSACTION错误解决+RadioGroup调用
  9. 制作动态表格(最好的方法)

随机推荐

  1. Android(安卓)C++多线程-创建子线程
  2. Android Service组件(1)
  3. Android(安卓)invalidate 与postInvalida
  4. Android学习笔记(11)---关于布局的一些小事
  5. Android 音频简介(转)
  6. Android导入项目时Android jar包丢失的解
  7. Android(安卓)StrictMode使用
  8. Android 中自定义View(四)
  9. 讲给Android程序员看的前端教程(20)——f
  10. android 全局变量 Application