转自 http://www.dreamingwish.com/dream-2012/gcd-four-the-the-odds-and-ends.html
Dispatch Queue挂起
dispatch queue可以被挂起和恢复。使用 dispatch_suspend函数来挂起,使用 dispatch_resume 函数来恢复。这两个函数的行为是如你所愿的。另外,这两个还是也可以用于dispatch source。
一个要注意的地方是,dispatch queue的挂起是block粒度的。换句话说,挂起一个queue并不会将当前正在执行的block挂起。它会允许当前执行的block执行完毕,然后后续的block不再会被执行,直至queue被恢复。
还有一个注意点:从man页上得来的:如果你挂起了一个queue或者source,那么销毁它之前,必须先对其进行恢复。
Dispatch Queue目标指定
所有的用户队列都有一个目标队列概念。从本质上讲,一个用户队列实际上是不执行任何任务的,但是它会将任务传递给它的目标队列来执行。通常,目标队列是默认优先级的全局队列。
用户队列的目标队列可以用函数 dispatch_set_target_queue来修改。我们可以将任意dispatch queue传递给这个函数,甚至可以是另一个用户队列,只要别构成循环就行。这个函数可以用来设定用户队列的优先级。比如我们可以将用户队列的目标队列设定为低优先级的全局队列,那么我们的用户队列中的任务都会以低优先级执行。高优先级也是一样道理。
有一个用途,是将用户队列的目标定为main queue。这会导致所有提交到该用户队列的block在主线程中执行。这样做来替代直接在主线程中执行代码的好处在于,我们的用户队列可以单独地被挂起和恢复,还可以被重定目标至一个全局队列,然后所有的block会变成在全局队列上执行(只要你确保你的代码离开主线程不会有问题)。
还有一个用途,是将一个用户队列的目标队列指定为另一个用户队列。这样做可以强制多个队列相互协调地串行执行,这样足以构建一组队列,通过挂起和暂停那个目标队列,我们可以挂起和暂停整个组。想象这样一个程序:它扫描一组目录并且加载目录中的内容。为了避免磁盘竞争,我们要确定在同一个物理磁盘上同时只有一个文件加载任务在执行。而希望可以同时从不同的物理磁盘上读取多个文件。要实现这个,我们要做的就是创建一个dispatch queue结构,该结构为磁盘结构的镜像。
首先,我们会扫描系统并找到各个磁盘,为每个磁盘创建一个用户队列。然后扫描文件系统,并为每个文件系统创建一个用户队列,将这些用户队列的目标队列指向合适的磁盘用户队列。最后,每个目录扫描器有自己的队列,其目标队列指向目录所在的文件系统的队列。目录扫描器枚举自己的目录并为每个文件向自己的队列提交一个block。由于整个系统的建立方式,就使得每个物理磁盘被串行访问,而多个物理磁盘被并行访问。除了队列初始化过程,我们根本不需要手动干预什么东西。
信号量
dispatch的信号量是像其他的信号量一样的,如果你熟悉其他多线程系统中的信号量,那么这一节的东西再好理解不过了。
信号量是一个整形值并且具有一个初始计数值,并且支持两个操作:信号通知和等待。当一个信号量被信号通知,其计数会被增加。当一个线程在一个信号量上等待时,线程会被阻塞(如果有必要的话),直至计数器大于零,然后线程会减少这个计数。
我们使用函数 dispatch_semaphore_create 来创建dispatch信号量,使用函数 dispatch_semaphore_signal 来信号通知,使用函数dispatch_semaphore_wait 来等待。这些函数的man页有两个很好的例子,展示了怎样使用信号量来同步任务和有限资源访问控制。
单次初始化
GCD还提供单词初始化支持,这个与pthread中的函数 pthread_once 很相似。GCD提供的方式的优点在于它使用block而非函数指针,这就允许更自然的代码方式:
这个特性的主要用途是惰性单例初始化或者其他的线程安全数据共享。典型的单例初始化技术看起来像这样(线程安全的):
+ (id)sharedWhatever
{
static Whatever *whatever = nil;
@synchronized([Whatever class])
{
if(!whatever)
whatever = [[Whatever alloc] init];
}
return whatever;
}
这挺好的,但是代价比较昂贵;每次调用 +sharedWhatever 函数都会付出取锁的代价,即使这个锁只需要进行一次。确实有更风骚的方式来实现这个,使用类似双向锁或者是原子操作的东西,但是这样挺难弄而且容易出错。
使用GCD,我们可以这样重写上面的方法,使用函数 dispatch_once:
+ (id)sharedWhatever
{
static dispatch_once_t pred;
static Whatever *whatever = nil;
dispatch_once(&pred, ^{
whatever = [[Whatever alloc] init];
});
return whatever;
}
这个稍微比 @synchronized方法简单些,并且GCD确保以更快的方式完成这些检测,它保证block中的代码在任何线程通过 dispatch_once 调用之前被执行,但它不会强制每次调用这个函数都让代码进行同步控制。实际上,如果你去看这个函数所在的头文件,你会发现目前它的实现其实是一个宏,进行了内联的初始化测试,这意味着通常情况下,你不用付出函数调用的负载代价,并且会有更少的同步控制负载。
结论
这一章,我们介绍了dispatch queue的挂起、恢复和目标重定,以及这些功能的一些用途。另外,我们还介绍了如何使用dispatch 信号量和单次初始化功能。到此,我已经完成了GCD如何运作以及如何使用的介绍。
http://www.uml.org.cn/mobiledev/201110121.asp
http://blog.csdn.net/jiahui524/article/details/7785606
感谢这两位的博客:
模仿微信好友列表功能(数据从手机中读取),实现汉首字母排序筛选:
用到了一个pinyin4j-2.5.0.jar这个包
这个包的介绍:http://sourceforge.net/projects/pinyin4j/files/
其中还有一个 ContentResolver的知识点:
http://www.cnblogs.com/ruiyi1987/archive/2011/06/20/2084925.html
这篇文章中用到这样一个查询条件:
String[] proj1=new String[]{ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.HAS_PHONE_NUMBER,
ContactsContract.Contacts.LOOKUP_KEY};
ContactsContract.Contacts已经不推荐使用,现在推荐使用phone
下面是代码:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/llParent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/lvShow"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TextView
android:id="@+id/tvLetter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/show_head_toast_bg"
android:gravity="center"
android:maxWidth="70dip"
android:minWidth="70dip"
android:padding="10dip"
android:textColor="#99FFFFFF"
android:textSize="50sp" >
</TextView>
<mypack.aaron.conact.MySideBar
android:id="@+id/myView"
android:layout_width="30dip"
android:layout_height="fill_parent"
android:layout_gravity="right" >
</mypack.aaron.conact.MySideBar>
</FrameLayout>
</LinearLayout>
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical">
<TextView
android:id="@+id/tv_catalog"
android:layout_height="wrap_content"
android:paddingRight="4.0dip" />
<LinearLayout
android:id="@+id/contactitem_layout"
android:layout_height="56.0dip"
android:background="@drawable/mm_listitem"
android:paddingLeft="8.0dip" >
<ImageView
android:id="@+id/contactitem_avatar_iv"
android:layout_width="40.0dip"
android:layout_height="40.0dip" android:src="/blog_article/@drawable/default_avatar/index.html" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:orientation="vertical"
android:paddingLeft="8.0dip" >
<TextView
android:id="@+id/tv_nick"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true" android:text="姓名" />
<TextView
android:id="@+id/tv_mobile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="13123456789"
android:textColor="#666666" />
</LinearLayout>
<ImageButton
android:id="@+id/imgbtn_nav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="5dip"
android:background="@drawable/nav_left"
android:focusable="false"
android:focusableInTouchMode="false" />
</LinearLayout>
</LinearLayout>
style.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 联系分组样式 -->
<style name="MMListItem">
<item name="android:gravity">center_vertical</item>
<item name="android:orientation">horizontal</item>
<item name="android:paddingLeft">4.0dip</item>
<item name="android:paddingTop">4.0dip</item>
<item name="android:paddingRight">4.0dip</item>
<item name="android:paddingBottom">4.0dip</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="MMFriendListItem">
<item name="android:gravity">center_vertical</item>
<item name="android:orientation">horizontal</item>
<item name="android:paddingLeft">16.0dip</item>
<item name="android:paddingTop">6.0dip</item>
<item name="android:paddingRight">6.0dip</item>
<item name="android:paddingBottom">6.0dip</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="MMListCatalog">
<item name="android:textSize">14.0dip</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">#ff595c61</item>
<item name="android:gravity">center_vertical</item>
<item name="android:orientation">horizontal</item>
<item name="android:background">#ffced2d7</item>
<item name="android:paddingLeft">10.0dip</item>
<item name="android:paddingTop">2.0dip</item>
<item name="android:paddingBottom">2.0dip</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="MMFontTitleInList">
<item name="android:textSize">16.0dip</item>
<item name="android:textColor">#ff595c61</item>
<item name="android:ellipsize">end</item>
<item name="android:gravity">center_vertical</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:singleLine">true</item>
</style>
<style name="MMFontTipInList">
<item name="android:textSize">14.0dip</item>
<item name="android:textColor">#fff</item>
<item name="android:ellipsize">end</item>
<item name="android:gravity">center_vertical</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:singleLine">true</item>
</style>
</resources>
PinyinUtils.java
这个java文件是生成汉字首字母拼音
public class PinyinUtils {
// 获得汉语拼音首字母
public static String getAlpha(String chines) {
String pinyinName = "";
char[] nameChar = chines.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < nameChar.length; i++) {
if (nameChar[i] > 128) {
try {
pinyinName += PinyinHelper.toHanyuPinyinStringArray(
nameChar[i], defaultFormat)[0].charAt(0);
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
pinyinName += nameChar[i];
}
}
return pinyinName;
}
/**
* 将字符串中的中文转化为拼音,其他字符不变
*
* @param inputString
* @return
*/
public static String getPingYin(String inputString) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
format.setVCharType(HanyuPinyinVCharType.WITH_V);
char[] input = inputString.trim().toCharArray();
String output = "";
try {
for (int i = 0; i < input.length; i++) {
if (java.lang.Character.toString(input[i]).matches(
"[\\u4E00-\\u9FA5]+")) {
String[] temp = PinyinHelper.toHanyuPinyinStringArray(
input[i], format);
output += temp[0];
} else
output += java.lang.Character.toString(input[i]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
return output;
}
/**
* 汉字转换位汉语拼音首字母,英文字符不变
*
* @param chines
* 汉字
* @return 拼音
*/
public static String converterToFirstSpell(String chines) {
String pinyinName = "";
char[] nameChar = chines.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.UPPERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < nameChar.length; i++) {
if (nameChar[i] > 128) {
try {
pinyinName += PinyinHelper.toHanyuPinyinStringArray(
nameChar[i], defaultFormat)[0].charAt(0);
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
pinyinName += nameChar[i];
}
}
return pinyinName;
}
}
MySideBar.java
右边拼音
public class MySideBar extends View{
OnTouchingLetterChangedListener onTouchingLetterChangedListener;
// 26个字母
public static String[] b = { "#", "A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
"V", "W", "X", "Y", "Z" };
int choose = -1;
Paint paint = new Paint();
public MySideBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MySideBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MySideBar(Context context) {
super(context);
}
/**
* 重写这个方法
*/
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (showBkg) {
canvas.drawColor(Color.parseColor("#40000000"));
}
int height = getHeight();
int width = getWidth();
int singleHeight = height / b.length;
for (int i = 0; i < b.length; i++) {
paint.setColor(Color.BLACK);
// paint.setColor(Color.WHITE);
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setAntiAlias(true);
paint.setTextSize(20);
if (i == choose) {
paint.setColor(Color.parseColor("#3399ff"));
paint.setFakeBoldText(true);
}
float xPos = width / 2 - paint.measureText(b[i]) / 2;
float yPos = singleHeight * i + singleHeight;
canvas.drawText(b[i], xPos, yPos, paint);
paint.reset();
}
}
private boolean showBkg = false;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float y = event.getY();
final int oldChoose = choose;
final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
final int c = (int) (y / getHeight() * b.length);
switch (action) {
case MotionEvent.ACTION_DOWN:
showBkg = true;
if (oldChoose != c && listener != null) {
if (c > 0 && c < b.length) {
listener.onTouchingLetterChanged(b[c]);
choose = c;
invalidate();
}
}
break;
case MotionEvent.ACTION_MOVE:
if (oldChoose != c && listener != null) {
if (c > 0 && c < b.length) {
listener.onTouchingLetterChanged(b[c]);
choose = c;
invalidate();
}
}
break;
case MotionEvent.ACTION_UP:
showBkg = false;
choose = -1;
invalidate();
break;
}
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
/**
* 向外公开的方法
*
* @param onTouchingLetterChangedListener
*/
public void setOnTouchingLetterChangedListener(
OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
}
/**
* 接口
*
* @author coder
*
*/
public interface OnTouchingLetterChangedListener {
public void onTouchingLetterChanged(String s);
}
}
public class PinyinComparator implements Comparator{
/** 按首字母排序**/
@Override
public int compare(Object o1, Object o2) {
String str1 = PinyinUtils.getPingYin((String) o1);
String str2 = PinyinUtils.getPingYin((String) o2);
return str1.compareTo(str2);
}
//
// @Override
// public int compare(Object o1, Object o2) {
// String str1 = PinyinUtils.getPingYin(((UserInfo) o1).getPy());
// String str2 = PinyinUtils.getPingYin(((UserInfo) o2).getPy());
// return str1.compareTo(str2);
// }
}
最后就是activity:
public class ContactsActivity extends Activity implements OnTouchingLetterChangedListener {
private ListView lv_list;
/**联系人显示名称**/
private static final int PHONES_DISPLAY_NAME_INDEX = 0;
/**电话号码**/
private static final int PHONES_NUMBER_INDEX = 1;
/**头像ID**/
private static final int PHONES_PHOTO_ID_INDEX = 2;
/**联系人的ID**/
private static final int PHONES_CONTACT_ID_INDEX = 3;
/**联系人名称**/
private ArrayList<String> mContactsName = new ArrayList<String>();
/**联系人头像**/
private ArrayList<String> mContactsNumber = new ArrayList<String>();
/**联系人头像**/
private ArrayList<Bitmap> mContactsPhonto = new ArrayList<Bitmap>();
/**拼音**/
private ArrayList<String> mPy=new ArrayList<String>();
/**左侧拼音字母**/
private MySideBar myView;
/**显示到屏幕中间的拼音**/
private TextView overlay;
private OverlayThread overlayThread = new OverlayThread();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lv_list=(ListView)findViewById(R.id.lv_lsit);
overlay=(TextView)findViewById(R.id.tvLetter);
lv_list.setTextFilterEnabled(true);
overlay.setVisibility(View.INVISIBLE);//默认隐藏
myView = (MySideBar) findViewById(R.id.myView);
myView.setOnTouchingLetterChangedListener(this);
ContentResolver resolver = getContentResolver();
String[] proj1=new String[]{Phone.DISPLAY_NAME,
Phone.NUMBER,Phone.PHOTO_ID,Phone.CONTACT_ID,
};
Cursor curContacts=resolver.query(Phone.CONTENT_URI,proj1, null, null, null);
if(curContacts.getCount()>0){
while(curContacts.moveToNext()){
//得到手机号码
String phoneNumber = curContacts.getString(PHONES_NUMBER_INDEX);
//当手机号码为空的或者为空字段 跳过当前循环
if (TextUtils.isEmpty(phoneNumber)){
continue;
}
//得到联系人名称
String contactName = curContacts.getString(PHONES_DISPLAY_NAME_INDEX);
//拼音
String py=PinyinUtils.getAlpha(contactName);
//得到联系人ID
Long contactid = curContacts.getLong(PHONES_CONTACT_ID_INDEX);
//得到联系人头像ID
Long photoid = curContacts.getLong(PHONES_PHOTO_ID_INDEX);
//得到联系人头像Bitamp
Bitmap contactPhoto = null;
//photoid 大于0 表示联系人有头像 如果没有给此人设置头像则给他一个默认的
if(photoid > 0 ) {
Uri uri =ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,contactid);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(resolver, uri);
contactPhoto = BitmapFactory.decodeStream(input);
}else {
contactPhoto = BitmapFactory.decodeResource(getResources(), R.drawable.contact_photo);
}
mContactsName.add(contactName);
mContactsPhonto.add(contactPhoto);
mContactsNumber.add(phoneNumber);
mPy.add(py);
} Collections.sort(mContactsName, new PinyinComparator()); //ArrayList按首字母拼音排序
curContacts.close();
}
ListViewAdapter ltAdapter=new ListViewAdapter();
lv_list.setAdapter(ltAdapter);
}
/**绑定数据**/
public class ListViewAdapter extends BaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return mContactsName.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater =getLayoutInflater();
// 使用View的对象itemView与R.layout.item关联
if(convertView==null){
convertView=inflater.inflate(R.layout.list_item, null);
}
// 通过findViewById()方法实例R.layout.item内各组件
TextView tvName = (TextView) convertView.findViewById(R.id.tv_nick);
TextView tvPhone=(TextView) convertView.findViewById(R.id.tv_mobile);
ImageView iv_pic = (ImageView) convertView.findViewById(R.id.contactitem_avatar_iv);
TextView tv_catalog=(TextView)convertView.findViewById(R.id.tv_catalog);
/*首字拼音*/
String catalog = PinyinUtils.converterToFirstSpell(mContactsName.get(position).substring(0, 1));
if(position==0){
tv_catalog.setVisibility(View.VISIBLE);
tv_catalog.setText(catalog);
}else {
/*下一个汉字首字拼音,如果两个汉字的首字母相等,下一个汉字的tv_catalog隐藏,这里其实就是把相同首字母的汉字叠加在一起*/
String lastCatalog = PinyinUtils.converterToFirstSpell(mContactsName.get(position - 1)).substring(0,1);
if (catalog.equals(lastCatalog)) {
tv_catalog.setVisibility(View.GONE);
} else {
tv_catalog.setVisibility(View.VISIBLE);
tv_catalog.setText(catalog);
}
}
tvName.setText(mContactsName.get(position));
iv_pic.setImageBitmap(mContactsPhonto.get(position));
tvPhone.setText(mContactsNumber.get(position));
return convertView;
}
}
/*下面是触摸左侧拼音*/
private Handler handler = new Handler() {
};
private class OverlayThread implements Runnable {
public void run() {
overlay.setVisibility(View.GONE);
}
}
/**字母触摸事件**/
@Override
public void onTouchingLetterChanged(String s) {
Log.i("coder", "s:" + s);
overlay.setText(s);
overlay.setVisibility(View.VISIBLE);
handler.removeCallbacks(overlayThread);
handler.postDelayed(overlayThread, 1000);
if (alphaIndexer(s) > 0) {
int position = alphaIndexer(s);
Log.i("coder", "position:" + position);
lv_list.setSelection(position);
}
}
//根据 字母的值找到mPy存储的汉字首字母拼音的索引,listView中根据这个索引定位显示
public int alphaIndexer(String s) {
int position = 0;
for (int i = 0; i < mContactsPhonto.size(); i++) {
if (mPy.get(i).startsWith(s)) {
position = i;
break;
}
}
Log.i("coder", "i" + position + mPy.get(position));
return position;
}
}
经过了手机测试成功,代码比较臃肿,还没有实现输入筛选条件查询,正在研究中
在智能手机朝着轻薄型趋势发展的今天,研发一款具有如下特点的厚重型智能手机,不知道有没有市场。
1. 配置超大容量电池
续航能力大大增强,省去了用户每天充电的烦恼。
2. 配置更专业级的摄像头
变焦范围显著扩大,成像质量也大幅提高。
3. 配置更专业级的音频芯片与外置喇叭
音效品质大大提升。