public class IDCardUtil { public static boolean isValidIdCard(String idCard) { if (idCard == null) { return false; } Pattern p = Pattern.compile("(\\d{17}[0-9a-zA-Z]|\\d{14}[0-9a-zA-Z])"); return p.matcher(idCard).matches(); } public static String getBirthday(String idCard) { if (idCard == null) { return null; } Pattern p1 = Pattern.compile("\\d{6}(\\d{8}).*"); // 用于提取出生日字符串 Pattern p2 = Pattern.compile("(\\d{4})(\\d{2})(\\d{2})");// 用于将生日字符串进行分解为年月日 Matcher matcher = p1.matcher(idCard); if (matcher.find()) { String birthday = matcher.group(1); Matcher matcher2 = p2.matcher(birthday); if (matcher2.find()) { StringBuilder sb = new StringBuilder(); sb.append(matcher2.group(1)); sb.append('-'); sb.append(matcher2.group(2)); sb.append('-'); sb.append(matcher2.group(3)); return sb.toString(); } } return null; } }
管理activity的生命周期
通过实现回调方法来管理activity的生命周期。一个activity的生命周期受与它关联的其它activity,task和back stack的影响。
一个activity存在3种状态:
- resumed(running)-activity运行在前台并且获得用户焦点。
- paused-另一个activity运行在前台并且获得用户焦点,但是当前activity仍然可见,paused状态下的activity仍然存活(保持同window manager的联系),但是当内存不足的时候可能会被系统kill掉。
- stopped-当前activity完全被另一个activity隐藏掉(用户不可见),并且运行在后台。stopped状态下的activity仍然存活(但是失去了与window manager的联系),但是当内存不足的时候可能会被系统kill掉。
当activity处于paused或者stopped状态的时候,系统可以通过调用它的finish方法或者直接kill掉activity。当activity被再次打开的时候,系统需要整个从头创建该activity。
实现生命周期回调
当一个activity的状态发生变化的时候,系统会通过调用各种回调方法来通知activity,你可以覆盖回调方法,在状态变化的时候做你想做的事情(必须先调用父类的回调方法,然后再追加你自己的实现)。
public class ExampleActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // The activity is being created. } @Override protected void onStart() { super.onStart(); // The activity is about to become visible. } @Override protected void onResume() { super.onResume(); // The activity has become visible (it is now "resumed"). } @Override protected void onPause() { super.onPause(); // Another activity is taking focus (this activity is about to be "paused"). } @Override protected void onStop() { super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected void onDestroy() { super.onDestroy(); // The activity is about to be destroyed. } }
这些回调方法包括3个闭环:
- entire lifetime-从onCreate到onDestroy,比如在onCreate里面开始一个线程,然后在onDestroy里面结束该线程。
- visible lifetime-从onStart到onStop,比如在onStart里面注册一个BroadcastReceiver来监视UI的各种变化,然后在onStop里面取消注册(因为此时用户已经看不到该activity)。
- foreground lifetime-从onResume到onPause,onPause一般在屏幕休眠或者弹出对话框的时候被调用。因为foreground lifetime执行比较频繁,所以在onResume和onPause方法中的代码要力求简洁并且保证快速执行,以提高用户的使用体验。
保存activity的状态
activity处于paused或者stopped状态的时候,activity对象仍然被保存在内存中,所以当activity再次进入前台的时候,原来的状态信息仍然存在。但是,为了释放内存,系统销毁掉activity以后,activity的状态信息也不复存在,这时,用户再次进入activity的时候,原来的状态信息将不复存在。为了保存重要的状态信息,可以通过覆盖onSaveInstanceState方法来实现。
当activity处于容易被销毁的状态的情况下,比如:onStop之前或者onPause之前,会调用onSaveInstanceState方法,并传入一个Bundle对象,你可以把要保存的状态信息以key-value pair的方式存入Bundle对象,这样系统销毁activity之后,用户再次进入activity的时候,系统会把之前保存好的Bundle对象传给onCreate方法和onRestoreInstanceState方法,你可以从Bundle对象中取出之前保存的状态信息。
但是,并不能确保activity在销毁前一定会调用onSaveInstanceState方法,因为有些情况下不需要保存状态信息,比如用户明确点击后退按钮退出activity。
即使你不实现onSaveInstanceState,activity的缺省实现也会保存一部分状态信息,它会分别调用layout中的每个view的onSaveInstanceState方法,大部分widget都会保存自己的状态信息,比如EditText会保存用户输入的信息,CheckBox会保存check状态,唯一需要你做的是为每个想保存状态信息的widget提供一个唯一的android:id。
<TextView android:id="@+id/nameTextbox"/>
aapt工具会自动在R.java中生成一个唯一的整型id,在代码中可以像下面这样直接引用。
findViewById(R.id.nameTextbox);
虽然activity的缺省实现会保存UI的一些信息,但是你可能仍然需要覆盖它来保存一些其他的状态信息,为了保留UI的状态信息,在覆盖onSaveInstanceState和onRestoreInstanceState方法的时候要先调用父类的实现,然后在后面追加你自己的实现。
因为onSaveInstanceState不能保证100%调用,所以,你应该只保存一些临时的状态信息,而不能用来保存持久化的数据,持久化的数据应该在onPause方法中进行保存(比如插入数据库,写入文件等)。
测试你的应用恢复状态信息的能力的一个比较好的方法是,旋转你的设备。因为屏幕方向变化的时候,为了应用相应的资源文件,系统会销毁并重建activity。因为用户在使用应用的时候会经常旋转屏幕,所以确保你的activity在旋转屏幕的时候能够完整地恢复状态信息是十分重要的。
处理配置变更
一些设备可以在运行的时候改变设置,比如:屏幕的方向,可用的键盘,语言。此时,android会重新创建所有运行中的activity(onDestroy,然后onCreate)。这种机制为了帮助你的应用自动重新使用你提供的相应的资源,比如:不同的layout,不同的屏幕方向和大小。
协调activities
当一个activity启动了另一个activity,那么这两个activity都发生了状态的变化,第一个activity先onPause再onStop,另一个activity先onCreate,再onStart,onResume。
activity A启动activity B的过程如下:
如果你需要在activity A stop的时候把一些数据写入数据库,然后在activity B中需要使用这些写入的数据,那么你必须在activity A的onPause方法中写入数据库,而不是onStop方法。
//通过UITableViewDelegate方法可以实现删除 tableview中某一行 //滑动删除 -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { NSUInteger row = [indexPath row]; [bookInforemoveObjectAtIndex:row];//bookInfo为当前table中显示的array [tableView deleteRowsAtIndexPaths:[NSArrayarrayWithObject:indexPath]withRowAnimation:UITableViewRowAnimationLeft]; } /*此时删除按钮为Delete,如果想显示为“删除” 中文的话,则需要实现 UITableViewDelegate中的- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath方法*/ - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{ return @"删除"; } //或者,最简单的方式,将plist中的Localization native development region改为China即可 //这只是让默认的Delete按钮显示成了中文的删除按钮而已,如果想将这个删除按钮换成其他图片形式的,怎么办呢? -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *RootViewControllerCell = @"RootViewControllerCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RootViewControllerCell]; if(cell == nil) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:RootViewControllerCell]autorelease]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button setBackgroundImage:[UIImage imageNamed:@"delete.png"] forState:UIControlStateNormal]; [button setFrame:CGRectMake(280, 10, 30, 30)]; [button addTarget:self action:@selector(del:) forControlEvents:UIControlEventTouchUpInside]; [cell.contentView addSubview:button]; } cell.textLabel.text = [array objectAtIndex:[indexPath row]]; cell.tag = [indexPath row]; NSArray *subviews = [cell.contentView subviews]; for(id view in subviews) { if([view isKindOfClass:[UIButton class]]) { [view setTag:[indexPath row]]; [cell.contentView bringSubviewToFront:view]; } } return cell; } -(void)del:(UIButton *)button { NSArray *visiblecells = [self.table visibleCells]; for(UITableViewCell *cell in visiblecells) { if(cell.tag == button.tag) { [array removeObjectAtIndex:[cell tag]]; [table reloadData]; break; } } }