校验QQ号码
必须5-15位数字
0不能开头
纯代码式
import java.util.Scanner;
public class RegExpDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
@SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
System.out.println("RegExpDemo.main():请输入您的QQ号码: ");
String qq = scanner.nextLine();
//java代码验证
boolean flag = matchrule(qq);
System.out.println("RegExpDemo.main(): "+flag);
return;
}
private static boolean matchrule(String qq) {
// TODO Auto-generated method stub
boolean flag = false;
if(qq.length()>=5&&qq.length()<=15){
char[] charreg = qq.toCharArray();
if(charreg[0]=='0'){
return flag;
}
for(char c:charreg){
if(!(c>='0'&&c<='9')){
return flag;
}
flag = true;
}
}
return flag;
}
}
加上正则
import java.util.Scanner;
public class RegExpDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
System.out.println("RegExpDemo.main():请输入您的QQ号码: ");
String qq = scanner.nextLine();
//正则代码验证
boolean flag = qq.matches("^[1-9]\\d{4,14}");
System.out.println("RegExpDemo.main(): "+flag);
return;
}
}
demo邮箱
public class RegExpDemo2 {
/*
* 15178006580@qq.com
* liuxiang@163.com
* zhangsanfeng@sina.com
* jinyong@cskaoyan.com
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
System.out.println("RegExpDemo.main():请输入您的邮箱: ");
String email = scanner.nextLine();
//正则代码验证
boolean flag = email.matches("\\w+@\\w{2,}\\.[a-zA-Z{2,}]+");
System.out.println("RegExpDemo.main(): "+flag);
return;
}
}
demo3 替换分割等操作都是基于匹配的
public class RegExpDemo3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//将数字替换成* 替换分割都是在匹配的基础上进行的
String input = "helloqq12344worlddkh634o34ia12java";
String output = input.replaceAll("\\d", "*");
String output2 = input.replaceAll("\\d+", "*");
System.out.println(output);
System.out.println(output2);
}
}
输出
helloqq*****worlddkh***o**ia**java
helloqq*worlddkh*o*ia*java
match方法是逐字符匹配的
本例中 ^表示以什么开头 []看后面 \表示下一个字符 \d表示 0至9的数字 {}表示上一个表达式的出现次数
常用的 \D 非数字 \s 空白字符:空格 制表 回车 换页 换行 \S 非空白 \w单词字符:0-9数字、26个字母、下划线 \W 非单词
关于[] [abc]其中任一字符 [a-f]范围 [^a-f] 非a-f字符
查询
//第一位必须是1,位数必须是11,只要某些号码段135、136、137、139、158、159
String regexp_cmcc = "1[3][5679]\\d{8}";
String regexp_cmcc2 = "1[5][89]\\d{8}";
if(num.matches(regexp_cmcc) || num.matches(regexp_cmcc2)){
num=num.substring(0,7);
本例中只需规定首位和位数
//第一位必须是1,位数必须是11
String regexp = "^1\\d{10}";
if(num.matches(regexp)){
num=num.substring(0,7);
对输入框做优化
输入一个数字后,能够提示满足这个条件的号码
这需要在QueryAddressActivity的editText里注册监听器,addTextChangedListener,他需要一个接口作为参数,TextWatcher,需要重载方法,然后动态显示
et_queryaddr_inputnum.addTextChangedListener(new TextWatcher(){
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
在这里只用的上第一个方法
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// 拼成string
String addr = AdressQueryDao.queryAddr( s.toString());
tv_queryaddr_result.setText(addr);
}
比如符合某个条件的是什么号码,在AdressQueryDao里分个类
if(num.matches(regexp)){
num=num.substring(0,7);
SQLiteDatabase db = SQLiteDatabase.openDatabase(file.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY);
Cursor cursor =db.rawQuery("select location from data2 where id = (select outkey from data1 where id = ?);", new String[]{num});
//默认游标指向了第一行的前一行,需要next
//查询结果只能是一个地方,要么查询到,要么没有,当向下一行读取时,则获取
if (cursor.moveToNext()) {
addr =cursor.getString(0);
}
}else if(num.length()==5){
addr="客服服务电话";
}else {
System.out.println("AdressQueryDao.querryAddr() not match regular express");
//提示位数不足
}
return addr;
}
关于文本框自动提示文本输入
AutoCompleteTextView()
接下来要在来电时显示号码归属地,这里用到自定义toast
需要一个新的service ShowCallLocation manifest里注册
<service android:name="com.rjl.mobilephonemanager.service.LocationService"></service>
<service android:name="com.rjl.mobilephonemanager.service.ShowCallLocation"></service>
public class ShowCallLocation extends Service {
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
}
}
要看第二个方法,他要实现一个TelephonyManager,这个manager需要一个listener,这个listener监听状态的改变,需要onCallStateChanged
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
tm.listen(new MyPhoneCallListener(), PhoneStateListener.LISTEN_CALL_STATE);
return super.onStartCommand(intent, flags, startId);
}
class MyPhoneCallListener extends PhoneStateListener{
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// TODO Auto-generated method stub
super.onCallStateChanged(state, incomingNumber);
}
}
而这个state有3个状态
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
break;
case TelephonyManager.CALL_STATE_RINGING:
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
default:
break;
}
主要是第2个状态,来电
case TelephonyManager.CALL_STATE_RINGING:
String addr = AdressQueryDao.queryAddr(incomingNumber);
System.out.println("ShowCallLocation.MyPhoneCallListener.onCallStateChanged()"+addr);
Toast.makeText(getApplicationContext(), addr, 1).show();
break;
我们要进入APP的时候启动这个service,放到splash里面,这么坑。。。另外监听电话要权限的,不过之前加过
copydb(this);
Intent intent = new Intent(this,ShowCallLocation.class);
startService(intent);
这个时候一打电话,进入管家,service就启动了,但是toast时间很短,用户不一定能看到,所以需要自定义
来看一下toast以及他的makeText方法的机制
源码
public static Toast makeText(Context context, CharSequence text, int duration) {
Toast result = new Toast(context);
LayoutInflater inflate = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
tv.setText(text);
result.mNextView = v;
result.mDuration = duration;
return result;
}
首先可以看到inflate,填充,是一个service,用来填充view,看他的两个参数,第一个参数前面一部分是一个layout,后一部分,transient是根节点,是R文件的一个ID值
这个值可以在SDK文件资源里找到,toast的布局,系统里面R的layout就是resource里的layout,所以R里的drawable就是resource的drawable
这其中有一个transient_notification,打开可以看到
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="?android:attr/toastFrameBackground">
<TextView
android:id="@android:id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.Toast"
android:textColor="@color/bright_foreground_dark"
android:shadowColor="#BB000000"
android:shadowRadius="2.75"
/>
</LinearLayout
里面是一个文本,填充时需要一个ID为message的东西,就是这个textview
然后调用者传一个text进来,setText(text)
然后给result设置显示和时间,这个result就是toast
回到调用者
Toast.makeText(getApplicationContext(), addr, 1).show();
maketext就是一个toast实体,这就相当于一个链式调用,最后调用到show方法
在刚刚的源码中调用outline,ctrl+o;
public void show() {
if (mNextView == null) {
throw new RuntimeException("setView must have been called");
}
INotificationManager service = getService();
String pkg = mContext.getPackageName();
TN tn = mTN;
tn.mNextView = mNextView;
try {
service.enqueueToast(pkg, tn, mDuration);
} catch (RemoteException e) {
// Empty
}
}
可以看到show又是一个新的service
private static INotificationManager sService;
static private INotificationManager getService() {
if (sService != null) {
return sService;
}
sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
return sService;
}
实际上是通过另一个service暴露的方法获取他的类,stub是两个service必须都有一个接口,他可以把接口实例化出来
tn是一个啥?
private static class TN extends ITransientNotification.Stub {
final Runnable mShow = new Runnable() {
@Override
public void run() {
handleShow();
}
};
final Runnable mHide = new Runnable() {
@Override
public void run() {
handleHide();
// Don't do this in handleHide() because it is also invoked by handleShow()
mNextView = null;
}
};
private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
final Handler mHandler = new Handler();
int mGravity;
int mX, mY;
float mHorizontalMargin;
float mVerticalMargin;
View mView;
View mNextView;
WindowManager mWM;
TN() {
// XXX This should be changed to use a Dialog, with a Theme.Toast
// defined that sets up the layout params appropriately.
final WindowManager.LayoutParams params = mParams;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
params.windowAnimations = com.android.internal.R.style.Animation_Toast;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("Toast");
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
}
是一个类,继承于某某,是runnable的一个类,可以放在线程里
他有两个方法,handleShow和handleHide,一个处理显示,一个处理隐藏
public void handleShow() {
if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
+ " mNextView=" + mNextView);
if (mView != mNextView) {
// remove the old view if necessary
handleHide();
mView = mNextView;
Context context = mView.getContext().getApplicationContext();
if (context == null) {
context = mView.getContext();
}
mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// We can resolve the Gravity here by using the Locale for getting
// the layout direction
final Configuration config = mView.getContext().getResources().getConfiguration();
final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());
mParams.gravity = gravity;
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
mParams.horizontalWeight = 1.0f;
}
if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
mParams.verticalWeight = 1.0f;
}
mParams.x = mX;
mParams.y = mY;
mParams.verticalMargin = mVerticalMargin;
mParams.horizontalMargin = mHorizontalMargin;
if (mView.getParent() != null) {
if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
mWM.removeView(mView);
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
mWM.addView(mView, mParams);
trySendAccessibilityEvent();
}
}
新填充的mNextView给了tn,进了handleshow之后才会把nextView给view,之前是不一样的,进来后先隐藏之前的mview,然后在把nextView给view,如此循环
上面这一段是show的核心代码
可以看到其中需要通过上下文获取view,然后使用windowmanager这个service才能将toast加到当前的窗口页面,然后后面就是一些参数的设置
其中TN有一个构造函数,一开始就把把一些参数初始化好,给toast加了一个淡入淡出的动画
比较重要的是参数有一个flags,之前要让textview可点击需要声明可点击可获取焦点,这里toast也可以在layout里用参数设置,即用纯代码来实现而无需XML
最后有一个wm,就是上面的窗口管理器,把mview显示出来
可以总结下:
toast的初始化需要makeText,然后利用handleShow加载到窗体上
现在就可以自定义toast了
模拟一下,显示中国联通
case TelephonyManager.CALL_STATE_RINGING:
String addr = AdressQueryDao.queryAddr(incomingNumber);
System.out.println("ShowCallLocation.MyPhoneCallListener.onCallStateChanged()"+addr);
/*Toast.makeText(getApplicationContext(), addr, 1).show();*/
//显示一个自定义的toast
showMyToast();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
default:
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
private void showMyToast() {
TextView tv = new TextView(this);
tv.setText("中国联通");
WindowManager mWM = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
//params.windowAnimations = com.android.internal.R.style.Animation_Toast;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("Toast");
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
mWM.addView(tv, params);
}
后面还要完善,比如现在这个词一直还显示着,需处理handleHide
case TelephonyManager.CALL_STATE_IDLE:
hideMyToast();
break;
private void hideMyToast(){
if (tv!=null) {
mWM.removeView(tv);
}
tv=null;
}
说白了就是通过将每个新的mNextView给mView,如此循环,来显示toast
关于toast的背景,需要在layout文件夹里加一个XML,比如本例叫做mytoast_showaddr
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@drawable/call_locate_gray">
<TextView
android:id="@+id/tv_mytoast_addr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:drawableLeft="@android:drawable/stat_sys_phone_call"
android:textColor="#000000"
android:shadowColor="#BB000000"
android:shadowRadius="2.75"/>
</LinearLayout>
这样,我们再来显示查询结果,而不是设定的中国联通
需要传一个addr
class MyPhoneCallListener extends PhoneStateListener{
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// TODO Auto-generated method stub
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
hideMyToast();
break;
case TelephonyManager.CALL_STATE_RINGING:
String addr = AdressQueryDao.queryAddr(incomingNumber);
System.out.println("ShowCallLocation.MyPhoneCallListener.onCallStateChanged()"+addr);
Toast.makeText(getApplicationContext(), addr, 1).show();
//显示一个自定义的toast
showMyToast(addr);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
default:
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
private void showMyToast(String addr) {
/*tv = new TextView(this);
tv.setText("中国联通");*/
LayoutInflater inflate = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflate.inflate(R.layout.mytoast_showaddr, null);
TextView tv = (TextView)v.findViewById(R.id.tv_mytoast_addr);
tv.setText(addr);
mWM = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.format = PixelFormat.TRANSLUCENT;
//params.windowAnimations = com.android.internal.R.style.Animation_Toast;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.setTitle("Toast");
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
mWM.addView(v, params);
}
private void hideMyToast(){
if (v!=null) {
mWM.removeView(v);
}
v=null;
}
}
接下来设置一下,让号码归属地这个功能能够被勾选
去settingitem里添加
<com.rjl.mobilephonemanager.ui.SettingItem
android:id="@+id/settingitem_showAddr"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
rjl:itemtitle="显示号码归属地"
rjl:desc_checkbox_on="显示号码归属地开启"
rjl:desc_checkbox_off="显示号码归属地关闭"/>
然后在settingactivity里获取 这类可以把监听这一步抽成方法,方便阅读
局部变量变成成员变量的快捷键 Ctrl+1 在选择,SharedPreferences应该改成全局的,然后就无需通过参数传递了,直接用
public class SettingActivity extends Activity {
private CheckBox cb;
private SettingItem settingItem ;
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
sp = getSharedPreferences("config", MODE_PRIVATE);
initAutoUpdateItem();
}
private void initAutoUpdateItem() {
settingItem = (SettingItem) findViewById(R.id.settingitem_autoupdate);
cb = (CheckBox) settingItem.findViewById(R.id.cb_settingitem);
//默认是true
boolean ischeck= sp.getBoolean("autoupdate", true);
cb.setChecked(ischeck);
if (ischeck) {
settingItem.setdescriptionon();
}
else {
settingItem.setdescriptionoff();
}
settingItem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Editor editor = sp.edit();
if(cb.isChecked()){
//勾上点击后要置成false
cb.setChecked(false);
settingItem.setdescriptionoff();
editor.putBoolean("autoupdate", false);
}else{
cb.setChecked(true);
settingItem.setdescriptionon();
editor.putBoolean("autoupdate", true);
}
editor.commit();
}
});
}
}
由于在settingitem中已经有setcheck方法,我们无需再settingactivity再去找子控件cb,可以注释掉,另外往后有好几个item,给名字区别一下
public class SettingActivity extends Activity {
private SettingItem settingItem_autoupdate ;
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
settingItem_autoupdate = (SettingItem) findViewById(R.id.settingitem_autoupdate);
sp = getSharedPreferences("config", MODE_PRIVATE);
initAutoUpdateItem();
}
private void initAutoUpdateItem() {
/*cb = (CheckBox) settingItem.findViewById(R.id.cb_settingitem);*/
//默认是true
boolean ischeck= sp.getBoolean("autoupdate", true);
/*cb.setChecked(ischeck);*/
settingItem_autoupdate.setCheck(ischeck);
/*if (ischeck) {
settingItem_autoupdate.setdescriptionon();
}
else {
settingItem_autoupdate.setdescriptionoff();
}*/
settingItem_autoupdate.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Editor editor = sp.edit();
if(settingItem_autoupdate.getChecked()){
//勾上点击后要置成false
settingItem_autoupdate.setCheck(false);
settingItem_autoupdate.setdescriptionoff();
editor.putBoolean("autoupdate", false);
}else{
settingItem_autoupdate.setCheck(true);
settingItem_autoupdate.setdescriptionon();
editor.putBoolean("autoupdate", true);
}
editor.commit();
}
});
}
}
现在加上自己需要的方法,监听器走起
sp = getSharedPreferences("config", MODE_PRIVATE);
initAutoUpdateItem();
initShowAddressItem();
}
private void initShowAddressItem() {
// TODO Auto-generated method stub
settingItem_showAddress.setCheck(sp.getBoolean("showaddr", false));
settingItem_showAddress.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
}
监听器:
cb都无需,之前是把组合控件里的子控件cb拿出来用,现在是把他当做整体用
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Editor editor = sp.edit();
if(settingItem_showAddress.getChecked()){
//已勾上的点击后要置成false
settingItem_showAddress.setCheck(false);
settingItem_showAddress.setdescriptionoff();
editor.putBoolean("showaddr", false);
}else{
settingItem_showAddress.setCheck(true);
settingItem_showAddress.setdescriptionon();
editor.putBoolean("showaddr", true);
}
editor.commit();
}
相应的打开关闭同时要操作service的启动关闭,把splash开关拿过来,之前是开启app自动起来,现在是用户点击才开启,那边的就可以注释掉了
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Editor editor = sp.edit();
if(settingItem_showAddress.getChecked()){
//已勾上的点击后要置成false
settingItem_showAddress.setCheck(false);
settingItem_showAddress.setdescriptionoff();
editor.putBoolean("showaddr", false);
Intent intent = new Intent(SettingActivity.this,ShowCallLocation.class);
stopService(intent);
}else{
settingItem_showAddress.setCheck(true);
settingItem_showAddress.setdescriptionon();
editor.putBoolean("showaddr", true);
Intent intent = new Intent(SettingActivity.this,ShowCallLocation.class);
startService(intent);
}
editor.commit();
}
走起,这时候再关闭后service仍然启动了,里面有问题,没有在service,ShowCallLocation里去关闭,类似于之前的mediaplayer,service关了还在播放,mediaplayer是底层硬件相关的,必须释放了才能关闭
@Override
public void onDestroy() {
// TODO Auto-generated method stub
if (tm!=null) {
tm=null;
}
super.onDestroy();
}
但是仅仅这样还不行,listener也要销毁掉,把上面的listener抽成成员变量
public class ShowCallLocation extends Service {
private TelephonyManager tm;
private WindowManager mWM;
private View v;
private MyPhoneCallListener listener;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
listener = new MyPhoneCallListener();
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
System.out.println("ShowCallLocation.onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
tm.listen(listener, PhoneStateListener.LISTEN_NONE);
if (tm!=null) {
tm=null;
}
if (listener!=null) {
listener=null;
}
super.onDestroy();
System.out.println("ShowCallLocation.onDestroy()");
}
还有一个bug,用户在service里关掉之后,APP里任然显示,为毛呢?判断要不要开启是读SharedPreferences的,但是手动关了之后虽然service关了,但是值并没有变化
这里在判断service是否开启的时候,应该让系统告诉你service是否处于运行状态,而不是去sp里获取,很多场合下他的值没有相应变动
去写一个工具类,又需要一个service,getSystemService,他是一个ActivityManager,也可以管理进程,是安卓底层最核心最复杂的一个组件,如果做偏底层,一定要研究他的源码,这里是杀鸡用牛刀,只是用来看service是否在运行,service都需要用到context
public class ServiceUtils {
public static boolean isRunning(Context ctx, String myservice){
boolean flag =false;
//如何判断:
ActivityManager ams = (ActivityManager) ctx.getSystemService(ctx.ACTIVITY_SERVICE);
//返回当前在运行的service,循环查到myservice
List<RunningServiceInfo> list = ams.getRunningServices(100);
for (RunningServiceInfo runningServiceInfo : list) {
String service = runningServiceInfo.service.getClassName();
if (service.equals(myservice)) {
flag=true;
}
}
return flag;
}
}
这时候也无需通过edit去保存了
private void initShowAddressItem() {
// TODO Auto-generated method stub
/*settingItem_showAddress.setCheck(sp.getBoolean("showaddr", false));*/
//让系统告诉你service是否在运行,而不是通过SharedPreferences
settingItem_showAddress.setCheck(ServiceUtils.isRunning(this, "com.rjl.mobilephonemanager.service.ShowCallLocation"));
settingItem_showAddress.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
/*Editor editor = sp.edit();*/
if(settingItem_showAddress.getChecked()){
//已勾上的点击后要置成false
settingItem_showAddress.setCheck(false);
settingItem_showAddress.setdescriptionoff();
/*editor.putBoolean("showaddr", false); */
Intent intent = new Intent(SettingActivity.this,ShowCallLocation.class);
stopService(intent);
}else{
settingItem_showAddress.setCheck(true);
settingItem_showAddress.setdescriptionon();
/*editor.putBoolean("showaddr", true); */
Intent intent = new Intent(SettingActivity.this,ShowCallLocation.class);
startService(intent);
}
/*editor.commit();*/
}
});
}
这时候又来一个bug,点home键没效果,activity并没有销毁,重进的时候没有调用oncreate,而是走了onrestart,初始化动作没有更新,所以初始化应该在onresume里
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
settingItem_autoupdate = (SettingItem) findViewById(R.id.settingitem_autoupdate);
settingItem_showAddress = (SettingItem) findViewById(R.id.settingitem_showAddr);
sp = getSharedPreferences("config", MODE_PRIVATE);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
initAutoUpdateItem( );
initShowAddressItem();
System.out.println("SettingActivity.onResume()");
super.onResume();
}