• Android 节日短信送祝福(功能篇:2-短信历史记录Fragment的编写)


    因为用于展示短信记录的是一个ListView,但是为了方便,可以直接继承自ListFragment,就可以免去写ListView对应的布局了,只需要写其item对应的布局即可。

    item_sended_msg.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/sms_item"
        android:padding="16dp">
    
        <TextView
            android:id="@+id/id_tv_sended_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="8dp"/>
    
        <com.example.just.festival_sms.view.FlowLayout
            android:id="@+id/id_fl_sended_contacts"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </com.example.just.festival_sms.view.FlowLayout>
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:orientation="horizontal">
    
            <TextView
            android:id="@+id/id_tv_fes"
            android:background="@drawable/tag_bg"
            android:layout_marginRight="8dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
            <TextView
                android:id="@+id/id_tv_date"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    
    </LinearLayout>

    还有tag.xml,显示联系人的layout

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#0ffcdd"
        android:background="@drawable/tag_bg"
        android:layout_margin="4dp">
    
    </TextView>

    以及tag_bg.xml,用于显示联系人和节日的TextView的background 
    这里写图片描述

    <shape xmlns:android="http://schemas.android.com/apk/res/android">
    
        <solid android:color="#ffffff"></solid>
    
        <stroke android:width="2dp" android:color="#0ffcdd"></stroke>
    
        <corners android:radius="8dp"></corners>
    
        <padding android:left="8dp" android:right="8dp" android:top="2dp" android:bottom="2dp"></padding>
    </shape>

    关于shape中的属性: 
    http://www.oschina.net/question/166763_34833?fromerr=FBMFjTg7


    SmsHistoryFragment.Java

    需要注意,某些导入的包可能有多种选择,应该都是v4下的

    public class SmsHistoryFragment extends ListFragment {
        private static final int LOADER_ID =1;
    
        private LayoutInflater mInflater;
        private CursorAdapter mCursorAdapter;
    
        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            mInflater=LayoutInflater.from(getActivity());
    
            initLoader();
    
            setupListAdapter();
    
        }
    
        private void setupListAdapter() {
            mCursorAdapter=new CursorAdapter(getActivity(),null,false) {
    
                //并不是每次都被调用的,它只在实例化view的时候调用,数据增加的时候也会调用
                //但是在重绘(比如修改条目里的TextView的内容)的时候不会被调用
                @Override
                public View newView(Context context, Cursor cursor, ViewGroup parent) {
                    View view=mInflater.inflate(R.layout.item_sended_msg,parent,false);//注意是"包名.R"
                    return view;
                }
    
                //在绘制Item之前一定会调用bindView方法,它在重绘的时候也同样被调用
                @Override
                public void bindView(View view, Context context, Cursor cursor) {
                    TextView tvContent= (TextView) view.findViewById(R.id.id_tv_sended_content);
                    FlowLayout flContacts= (FlowLayout) view.findViewById(R.id.id_fl_sended_contacts);
                    TextView tvFes= (TextView) view.findViewById(R.id.id_tv_fes);
                    TextView tvDate= (TextView) view.findViewById(R.id.id_tv_date);
    
                    tvContent.setText(cursor.getString(cursor.getColumnIndex(SendedMsg.COLUMN_CONTENT)));
                    tvFes.setText(cursor.getString(cursor.getColumnIndex(SendedMsg.COLUMN_FESTIVAL_NAME)));
    
                    //注意这里的date为long,int型会溢出
                    long date=cursor.getLong(cursor.getColumnIndex(SendedMsg.COLUMN_DATE));
                    tvDate.setText(parseDate(date));
    
                    String names=cursor.getString(cursor.getColumnIndex(SendedMsg.COLUMN_NAMES));
                    if(TextUtils.isEmpty(names)) {
                        return;
                    }
    
                    //因为ListView的item有复用的可能性,所以每次都要先除去item中的flContacts在上一次使用时添加的view
                    flContacts.removeAllViews();
    
                    for (String name:names.split(",")) {
                        addTag(name, flContacts);
                    }
                }
            };
    
            setListAdapter(mCursorAdapter);
        }
    
        private String parseDate(long date) {
            DateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm");
            return df.format(date);
        }
    
        private void addTag(String name,FlowLayout fl) {
            TextView tv= (TextView) mInflater.inflate(R.layout.tag,fl,false);
            tv.setText(name);
            fl.addView(tv);
        }
    
        private void initLoader() {
            getLoaderManager().initLoader(LOADER_ID,null,new LoaderManager.LoaderCallbacks<Cursor>() {
    
                //onCreateLoader是一个工厂方法,用来返回一个新的Loader
                //LoaderManager将会在它第一次创建Loader的时候调用该方法
                @Override
                public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                    CursorLoader loader=new CursorLoader(getActivity(), SmsProvider.URI_SMS_ALL,null,null,null,null);
                    return loader;
                }
    
                //onLoadFinished方法将在Loader创建完毕的时候自动调用
                //在数据更新的时候也会调用
                @Override
                public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
                        if(loader.getId()==LOADER_ID) {
                        mCursorAdapter.swapCursor(data);//更新mCursorAdapter的Cursor
                    }
                }
    
                @Override
                public void onLoaderReset(Loader<Cursor> loader) {
                    mCursorAdapter.swapCursor(null);
                }
            });
        }
    }

    SmsHistoryFragment中,涉及到了LoaderManager与Loader,而关于这个知识点,推荐一篇优质博文,看完之后肯定会有所收获的。 
    http://blog.csdn.net/murphykwu/article/details/35287303

    还是回到本文中来,因为Android的设计之中,任何耗时的操作都不能放在UI主线程之中。所以类似于网络操作等等耗时的操作都需要使用异步的实现。而在ContentProvider之中,也有可能存在耗时的操作(当查询的数据量很大的时候),这个时候我们也需要使用异步的调用来完成数据的查。当使用异步的query的时候,我们就需要使用LoaderManager了。使用LoaderManager就可以在不阻塞UI主线程的情况下完成数据的加载。

    还记得上一篇文章最后提及的两行代码吗?就是为了实时的更新数据用的,更进一步说,是为了同步ListView中显示数据(历史记录),两行代码缺一不可。(检测数据源是Loader的工作,Loader也会执行实际的同步载入操作,而在这之中,那两句代码就起到了一定的作用

    另外,关于还有关于CursorAdapter,可以去看看这篇博文: 
    http://www.bubuko.com/infodetail-734550.html

    对了,小编在刚开始解读源码的时候有一个疑问,mCursorAdapter是在setupListAdapter中初始化的,但是initLoader中就用到了mCursorAdapter,为什么程序可以运行(因为这里是先initLoader再setupListAdapter)(但是实际中也可以先setupListAdapter再initLoader) 
    后来实际测试了一下,发现部分具体的流程如下: 
    onCreateLoader() -> 初始化mCursorAdapter ->setListAdapter(mCursorAdapter) 
    -> onLoadFinished() 
    这是因为getLoaderManager().initLoader()中传入的第三个参数是一个回调接口。

  • 相关阅读:
    关于JS中变量提升的规则和原理的一点理解(二)
    JS 引擎的执行机制
    关于遍历对象的属性的一点新认识,如何只遍历对象自身的属性
    【转】 CSS十问——好奇心+刨根问底=CSSer
    【转】彻底理解js中this的指向,不必硬背。
    【转】 Git——如何将本地项目提交至远程仓库
    博客园的第一篇文章
    《深度学习之kaggle》:六、没有预训练的YOLO5X训练方式小改,准确率小幅提升
    《深度学习之kaggle》:五、没有预训练的YOLO5X训练完毕
    Webdriver如何解决页面元素过期:org.openqa.selenium.StaleElementReferenceException: Element not found in the cache
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/6053298.html
Copyright © 2020-2023  润新知