[sms] 01_文件夹-按照日期来分隔

Android 4.0

每一类信箱中的短信,按照日期来分隔

ListView中位置position的变化

两个Map集合
1、datePositionMap<Integer,String> 
key:新的ListView中的position
value:该position对应的日期
2、changePositionMap<Integer,Integer>
key:新的ListView中的position
value:旧的ListView中的position
1、在异步查询框架查询完毕 AsyncQueryHandler的 onQueryComplete时,将数据设置到Map中去
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
    super.onQueryComplete(token, cookie, cursor);
    if (cursor == null) {
        return;
    }
    int count = cursor.getCount();
    if (count > 0) {
        int dateCount = 0;// 日期的个数
        while (cursor.moveToNext()) {
            int position = cursor.getPosition();
            
            // 1、取出当前日期
            long date = cursor.getLong(DATE_COLUMN_INDEX);
            String dateStr = DateFormat.getDateFormat(context).format(date);
            
            // 2、存入数据到map集合中去
            if (!datePositionMap.containsValue(dateStr)) {// 如果当前datePositionMap中没有该日期,那么存入该日期
                datePositionMap.put(position + dateCount, dateStr);
                dateCount++;
            }
            // 新的位置和旧的位置的关系映射,那么存入到changePositionMap集合
            changePositionMap.put(position + dateCount, position);
        }
    }
    // 游标重新归位
    cursor.move(-1);
    mCursor = cursor;
    folderListAdapter.changeCursor(cursor);
} 
2、Cursor中重写getCount()和getView()方法
@Override
public int getCount() {
    return super.getCount() + datePositionMap.size();// 之前的个数+日期的个数
}
原本的getView()
public View getView(int position, View convertView, ViewGroup parent) {
        if (!mDataValid) {
            throw new IllegalStateException("this should only be called when the cursor is valid");
        }
        if (!mCursor.moveToPosition(position)) {
            throw new IllegalStateException("couldn't move cursor to position " + position);
        }
        View v;
        if (convertView == null) {
            v = newView(mContextmCursor, parent);
        } else {
            v = convertView;
        }
        bindView(v, mContextmCursor);
        return v;
    }
重写后的getView()
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    
    // 这里的position是新的position
    if (datePositionMap.containsKey(position)) {
        // 如果datePositionMap包含position,那么该位置显示日期
        TextView tvDate = (TextView) View.inflate(mContext,R.layout.folder_detail_date_itemnull);
        String dateStr = datePositionMap.get(position);
        tvDate.setText(dateStr);
        return tvDate;
    } else {
        // 否则的话,当前位置不在datePositionMap集合中
        // if (!mCursor.moveToPosition(position)) {
        // 这里的position是新的position,而这里用到的是游标position,所以要用原来的position
        if (!mCursor.moveToPosition(changePositionMap.get(position))) {
            throw new IllegalStateException("couldn't move cursor to position " + position);
        }
        View v;
        if (convertView == null || (convertView.getTag() == null)) {// 前面有设置了tvDate,所以convertView不为null,还有判断是否绑定了数据,否则会报空指针异常
            v = newView(mContextmCursor, parent);
        } else {
            v = convertView;
        }
        bindView(v, mContextmCursor);
        return v;
    }
}
3、一些用到原来position的地方,要进行修改
①如,listview中item的点击位置及屏蔽掉点击日期的时候出现的响应
lvFolderDetail.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) {
        if (datePositionMap.containsKey(position)) {
            view.setFocusable(false);
            view.setClickable(false);
            return;
        }
        // 将每条短信的id给传递过去
        Cursor cursor = (Cursor) folderListAdapter.getItem(changePositionMap.get(position));
        String _id = cursor.getString(ID_COLUMN_INDEX);
        Intent intent = new Intent(FolderListActivity.this,SmsDetailActivity.class);
        intent.putExtra("_id", _id);
        FolderListActivity.this.startActivity(intent);
    }
});
②原有的ListView中cursor位置的判断
if (!mCursor.moveToPosition(changePositionMap.get(position))) {}
效果:
完整代码:
文件夹列表: FolderListActivity.java
package cn.zengfansheng.ui;
 
import java.util.HashMap;
 
import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.PhoneLookup;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import cn.zengfansheng.intellectualsms.R;
import cn.zengfansheng.utils.Sms;
 
/**
* 文件夹短信详情Activity
* @author hacket
*/

public class FolderListActivity extends Activity {
 
    private Button btnFolderNewMsg;
    private ListView lvFolderDetail;
 
    private static final int INBOX_COLUMN_INDEX = 0;
    private static final int OUTBOX_COLUMN_INDEX = 1;
    private static final int SENT_COLUMN_INDEX = 2;
    private static final int DRAFT_COLUMN_INDEX = 3;
 
    private String msgType;// 信箱类型
    private int clickPosition;// 点击的位置
    private FolderListAdapter folderListAdapter;
 
    private static final String[] SMS_PROJECTION = new String[] { "_id",
            "address", "date", "type", "body" };
 
    private static final int ID_COLUMN_INDEX = 0;
    private static final int ADDRESS_COLUMN_INDEX = 1;
    private static final int DATE_COLUMN_INDEX = 2;
    private static final int TYPE_COLUMN_INDEX = 3;
    private static final int BODY_COLUMN_INDEX = 4;
 
    private static final String[] CONTACT_PROJECTION = new String[] { PhoneLookup.DISPLAY_NAME };
 
    private static final int DISPLAY_NAME_COLUMN_INDEX = 0;
 
    /**
     * key:新position
     *
     * value:日期
     */

    private HashMap<Integer, String> datePositionMap;
    /**
     * key:新position
     *
     * value:旧position
     */

    private HashMap<Integer, Integer> changePositionMap;
 
    /**
     * 异步查询cursor
     */

    private Cursor mCursor;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_folder_type);
 
        initView();
 
        getIntentData();
 
        setListView();
 
        startQuery();
    }
 
    // NOTES===================4、异步查询数据====================
 
    /**
     * 4、异步数据查询
     */

    private void startQuery() {
 
        MyAsyncQueryHandler queryHandler = new MyAsyncQueryHandler(this);
        Uri uri = null;
        //循环查询
        switch (clickPosition) {
        case INBOX_COLUMN_INDEX://收件箱
            uri = Sms.INBOX.CONTENT_URI;//content://sms/inbox
            break;
        case OUTBOX_COLUMN_INDEX://发件箱
            uri = Sms.OUTBOX.CONTENT_URI;//content://sms/outbox
            break;
        case SENT_COLUMN_INDEX://已发送
            uri = Sms.SENT.CONTENT_URI;//content://sms/sent
            break;
        case DRAFT_COLUMN_INDEX://草稿箱
            uri = Sms.DRAFT.CONTENT_URI;//content://sms/draft
            break;
        }
        queryHandler.startQuery(0, null, uri , SMS_PROJECTION, null, null, " DATE DESC");
 
    }
 
    /**
     * 异步查询框架实现类MyAsyncQueryHandler
     */

    private class MyAsyncQueryHandler extends AsyncQueryHandler {
 
        private final Context context;
 
        public MyAsyncQueryHandler(Context context) {
            super(context.getContentResolver());
            this.context = context;
        }
 
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            super.onQueryComplete(token, cookie, cursor);
 
            if (cursor == null) {
                return;
            }
 
            int count = cursor.getCount();
            if (count > 0) {
 
                int dateCount = 0;// 日期的个数
                while (cursor.moveToNext()) {
                    int position = cursor.getPosition();
 
                    // 1、取出当前日期
                    long date = cursor.getLong(DATE_COLUMN_INDEX);
                    String dateStr = DateFormat.getDateFormat(context).format(
                            date);
 
                    // 2、存入数据到map集合中去
                    if (!datePositionMap.containsValue(dateStr)) {// 如果当前datePositionMap中没有该日期,那么存入该日期
                        datePositionMap.put(position + dateCount, dateStr);
                        dateCount++;
                }
                    // 新的位置和旧的位置的关系映射,那么存入到changePositionMap集合
                    changePositionMap.put(position + dateCount, position);
            }
            }
 
            // 游标重新归位
            cursor.move(-1);
 
            mCursor = cursor;
            folderListAdapter.changeCursor(cursor);
        }
 
    }
    // NOTES=================3、ListView===================
    /**
     * 3、设置ListView
     */

    private void setListView() {
 
        folderListAdapter = new FolderListAdapter(this, null, true);
        lvFolderDetail.setAdapter(folderListAdapter);
 
        lvFolderDetail.setOnItemClickListener(new OnItemClickListener() {
 
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
 
                if (datePositionMap.containsKey(position)) {
                    view.setFocusable(false);
                    view.setClickable(false);
                    return;
                }
 
                // 将每条短信的id给传递过去
                Cursor cursor = (Cursor) folderListAdapter.getItem(changePositionMap.get(position));
                String _id = cursor.getString(ID_COLUMN_INDEX);
                Intent intent = new Intent(FolderListActivity.this,SmsDetailActivity.class);
                intent.putExtra("_id", _id);
                FolderListActivity.this.startActivity(intent);
            }
 
        });
    }
 
    /**
     * 数据适配器CursorAdapter实现类
     */

    private class FolderListAdapter extends CursorAdapter {
 
        private final LayoutInflater inflater;
        private final long firstsecondOfToday;
        private final Context mContext;
 
        public FolderListAdapter(Context context, Cursor c, boolean autoRequery) {
            super(context, c, autoRequery);
 
            mContext = context;
 
            inflater = LayoutInflater.from(context);
 
            Time time = new Time();
            time.setToNow();
            time.hour = 0;
            time.minute = 0;
            time.second = 0;
 
            firstsecondOfToday = time.toMillis(false);
        }
 
        @Override
        public int getCount() {
            return super.getCount() + datePositionMap.size();// 之前的个数+日期的个数
        }
 
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
 
            // 这里的position是新的position
 
            if (datePositionMap.containsKey(position)) {
                // 如果datePositionMap包含position,那么该位置显示日期
                TextView tvDate = (TextView) View.inflate(mContext,R.layout.folder_detail_date_item, null);
                String dateStr = datePositionMap.get(position);
                tvDate.setText(dateStr);
                return tvDate;
            } else {
                // 否则的话,当前位置不在datePositionMap集合中
 
                // if (!mCursor.moveToPosition(position)) {
                // 这里的position是新的position,而这里用到的是游标position,所以要用原来的position
                if (!mCursor.moveToPosition(changePositionMap.get(position))) {
                    throw new IllegalStateException("couldn't move cursor to position " + position);
                }
                View v;
                if (convertView == null || (convertView.getTag() == null)) {// 前面有设置了tvDate,所以convertView不为null,还有判断是否绑定了数据,否则会报空指针异常
                    v = newView(mContext, mCursor, parent);
                } else {
                    v = convertView;
                }
                bindView(v, mContext, mCursor);
                return v;
            }
 
        }
 
        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
 
            ViewHolder holder = null;
 
            View view = inflater.inflate(R.layout.item_folder_type, parent, false);
            holder = new ViewHolder();
            holder.ivFolderItemIcon = (ImageView) view.findViewById(R.id.iv_folder_detail_item_icon);
            holder.tvFolderItemName = (TextView) view.findViewById(R.id.tv_folder_detail_item_name);
            holder.tvFolderItemDate = (TextView) view.findViewById(R.id.tv_folder_detail_item_date);
            holder.tvFolderItemBody = (TextView) view.findViewById(R.id.tv_folder_detail_item_body);
 
            view.setTag(holder);
 
            return view;
        }
 
        @Override
        public void bindView(View view, Context context, Cursor cursor) {
 
            ViewHolder holder = (ViewHolder) view.getTag();
 
            // 得到数据
            String smsAddress = cursor.getString(ADDRESS_COLUMN_INDEX);
            long smsDate = cursor.getLong(DATE_COLUMN_INDEX);
            String smsBody = cursor.getString(BODY_COLUMN_INDEX);
            int smsType = cursor.getInt(TYPE_COLUMN_INDEX);
 
            // 格式化数据
            // 1、根据电话号码,获得联系人的名称(头像)
            String contactName = null;// 联系人姓名
            Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,Uri.encode(smsAddress));
            Cursor contactsCursor = getContentResolver().query(uri,
                    CONTACT_PROJECTION, null, null, null);
            if (contactsCursor != null && contactsCursor.moveToNext()) {
                contactName = contactsCursor.getString(DISPLAY_NAME_COLUMN_INDEX);
            }
 
            if (contactsCursor != null) {
                contactsCursor.close();
            }
            if (contactName == null) {
                // 没有获取到联系人信息
                // ①联系人头像
                holder.ivFolderItemIcon.setImageDrawable(getResources()
                        .getDrawable(R.drawable.ic_unknown_picture_normal));
                // ②联系人姓名
                holder.tvFolderItemName.setText(smsAddress);
            } else {
                // 获取到了联系人信息
                // ①联系人头像
                holder.ivFolderItemIcon.setImageDrawable(getResources()
                        .getDrawable(R.drawable.ic_contact_picture));
                // ②联系人姓名
                holder.tvFolderItemName.setText(contactName);
            }
 
            // 2、最后一条短信内容
            holder.tvFolderItemBody.setText(smsBody);
 
            // 3、最后一条短信时间
            // 如果时间相差一天,显示日期;一天之内,显示当日时间
            long dMillis = smsDate - firstsecondOfToday;
            if (dMillis > 0 && dMillis < DateUtils.DAY_IN_MILLIS) {// 86400000
                // 一天之内,显示时间
                String dateFormat = DateFormat.getTimeFormat(context).format(smsDate);
                holder.tvFolderItemDate.setText(dateFormat);
            } else {
                // 一天之外,显示日期
                String dateFormat = DateFormat.getDateFormat(context).format(smsDate);
                holder.tvFolderItemDate.setText(dateFormat);
            }
 
            //4、处理短信的类型
        }
 
    }
 
    /**
     * ViewHolder类
     */

    private static class ViewHolder {
        private ImageView ivFolderItemIcon;
        private TextView tvFolderItemName;
        private TextView tvFolderItemDate;
        private TextView tvFolderItemBody;
    }
    // NOTES=========================== ===========================
    /**
     * 2、获取传递过来的数据
     */

    private void getIntentData() {
 
        Intent intent = getIntent();
 
        msgType = intent.getStringExtra("msgType");
        clickPosition = intent.getIntExtra("position", INBOX_COLUMN_INDEX);
 
        // 标题
        setTitle(msgType);
    }
 
    /**
     * 1、初始化组件
     */

    private void initView() {
 
        btnFolderNewMsg = (Button) this.findViewById(R.id.btn_folder_detail_new_message);
 
        lvFolderDetail = (ListView) this.findViewById(R.id.lv_folder_detail_list);
 
        datePositionMap = new HashMap<Integer, String>();
        changePositionMap = new HashMap<Integer, Integer>();
    }
}
异常:UnsupportedOperationException
01-25 15:19:34.493: E/AndroidRuntime(1903): java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
代码:
在CursorAdapter的getView()
TextView tvDate = (TextView) View.inflate(mContext,R.layout.folder_detail_date_itemnull);