网上有很多大神对service已经有了 详细的介绍. 在这里 我只是记录下 我关于service的调试跟理解.
1. service 分为两种开启方法 startService与 bindService.
>startSetvice开启的话 即使应用关闭 它也会正常使用.
并且退出应用->重进应用再开启startService时 如果已经存在该服务, 是不会重启服务的.
最开始开启服务时的顺序是 onCreate > onStartCommand
如果服务已经开启再开启服务时 onStartCommand
2.bindService开启的话 随着应用的关闭而会被关闭. 即使你没有使用 unbinderService.
>所以使用contentService来链接时候只能是单向链接.
>要注意的是 aidlService的 通信见链接Service也是 单次链接.因为他是通过Ibinder链接的(bindService)
3.IntentService是 异步请求.他的服务器启动并不在 main thread 进行.并且他会自动 stopSelf 来停止服务. 所以他也是单次调用. 因为你不能长期挂起.
2016年11月14日星期一
2016年11月3日星期四
注解的使用(Annotation)
此帖用来写 本人对注解使用的理解. 并且考虑了下 什么状态下能使用注解.
考虑场景 1: 在你使用注解的地方. 程序调用此地方的方法(或者接口)时 让系统自动调用此方法.
比如:
ClassA里调用了 注解Anotation时
public class ClassA {
@Anotation(value="kirsong")
public void showA(String name){
System.out.println(name);
}
}
当调用类ClassA的时候 根据方法映射调用 showA方法.
Method methodAnotation=ClassA.class.getDeclaredMethod("showA", new Class[]{String.class});
Anotation an=null;
if(methodAnotation.isAnnotationPrese
//判断该方法是否存在注解
if((an=methodAnotation.getAnnotation(Anotation.class))!=null){
try {
methodAnotation.invoke(mj, an.value());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
考虑场景2: 根据传送的数据, 分析数据中的注解类并调用他
首先声明注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Anotation {
String value() default "val1";
}
创建使用到注解的类
public class ClassA {
@Anotation(value="kirsong")
public void showA(String name){
System.out.println(name);
}
@Anotation
public void showB(String name){
System.out.println(name);
}
public void showC(String name){
System.out.println(name);
}
}
创建根据注解分析器,并调用
public class TargetAnnotation {
public void setPust(Object cls){
try {
Method[] md=cls.getClass().getDeclaredMethods();
Anotation an=null;
for(Method method:md){
if((an=method.getAnnotation(Anotation.class))!=null){
method.invoke(cls, an.value());
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
使用方法
System.out.print("场景3\n");
ClassA ca=new ClassA();
TargetAnnotation target=new TargetAnnotation();
target.setPust(ca);
使用场景3. 使用注解调用接口
定义接口
public interface InterFaceA {
@Anotation(value="intera")
void interA(String value);
}
调用接口中的注解方法
public void setInterfacePust(Object cls){
try {
Class<?>[] interfaces = cls.getClass().getInterfaces();
for(Class<?> interClas:interfaces){
Method[] md=interClas.getDeclaredMethods();
Anotation an=null;
cls.getClass().getInterfaces();
for(Method method:md){
if((an=method.getAnnotation(Anotation.class))!=null){
method.invoke(cls, an.value());
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
调用
InterFaceA intera=new InterFaceA(){
@Override
public void interA(String value) {
System.out.print(value);
}
};
target.setInterfacePust(intera);
2016年10月11日星期二
requestDisallowInterceptTouchEvent的使用
requestDisallowInterceptTouchEvent(true)方法是用来子View告诉父容器不要拦截我们的事件的,但是这个代码放的位置很重要,可能导致失效。首先我们要知道父类肯定能收到Down事件的,因为这个是事件的起源,系统默认在VIewGroup里把requestDisallowInterceptTouchEvent里把子View对于Down事件的拦截权利剥削了,有了这个Down,它才会决定后面的事件是否传给子类,看代码
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- return false;
- case MotionEvent.ACTION_MOVE: //表示父类需要
- if(true) {
- return true;
- }
- else {
- return false;
- }
- case MotionEvent.ACTION_UP:
- return true;
- default:
- break;
- }
- // TODO Auto-generated method stub
- Log.e("TestView","父容器拦截");
- return false; //如果设置拦截,除了down,其他都是父类处理
- }
子类应该这么写
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- // TODO Auto-generated method stub
- getParent().requestDisallowInterceptTouchEvent(true);
- return super.dispatchTouchEvent(event);
- }
- 子类在收到父类的down事件时,去拦截,当然如果父类拦截了down事件,子类就没办法拦截他的其他事件了,
2016年9月22日星期四
Android Studio 设置JNI
下面是两种设置JNI的方法. 推荐使用方法2. 方法1有时候不好用.
方法1
原来是Android Studio的JNI默认路径是这样的
//目录结构一定要改成这个样子
|---src
|---main
|---jniLibs
|---arm64-v8a
|---libhello-jni.so
|---armeabi
|---libhello-jni.so
|---armeabi-v7a
|---libhello-jni.so
|---x86
|---libhello-jni.so
|---x86_64
|---libhello-jni.so
|---mips
|---libhello-jni.so
|---mips64
|---libhello-jni.so
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
目录结构一定要改成上图的样子,详细的修改方法请转移 | Android Studio 添加动态库os文件的方法
方法2[推荐]
直接修改build.gradle文件如下:
android {
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
其实两种方法的原理是一样的。方法1是:直接将so文件放到了Android Studio 的默认路径src > main > jniLibs方法2是:修改jniLibs的默认路径为libs
2016年8月30日星期二
关于GCM的 非常也用的一个帖子
准备工作
翻墙
先翻墙,翻不了墙一切都白搭……
Google账号
- 申请Google账号
- 进入Google开发管理台
- 创建工程(Google管理台上的Project)
- 开启Google Cloud Messaging API。
Demo工程
参考google官方指导文档,在google中搜索GCM,或者直接点击此处打开。本文均以Android为例,打开页面后,点击左上方的”TRY IT ON ANDROID”按钮,进入针对安卓的指导页。以下步骤官方指导写的比较详细的,本文就不赘述,一笔带过,有需要注意的会补充。
- 下载Android示例工程
下载下来是个压缩包,GCM的工程目录为google-services-master/android/gcm,简单介绍下各个类的作用:- MyGcmListenerService.java
GCM接收监听服务类,接收GCM发过来的通知消息,并显示到手机状态栏中。
对应的AndroidManifest.xml配置如下:<!-- [START gcm_receiver] --> <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE"/> <category android:name="gcm.play.android.samples.com.gcmquickstart"/> </intent-filter> </receiver> <!-- [END gcm_receiver] --> <!-- [START gcm_listener] --> <service android:name=".MyGcmListenerService" android:exported="false"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE"/> </intent-filter> </service> <!-- [END gcm_listener] -->- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
GcmReceiver接收,然后发送给GcmListenerService,我们在GcmListenerServcie的实现类中处理收到的gcm消息。Google官方对GcmReceiver的解释(原文链接):WakefulBroadcastReceiver that receives GCM messages and delivers them to an application-specific GcmListenerService subclass.如何将通知消息展示到状态栏:Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_stat_ic_notification) .setContentTitle("GCM Message") .setContentText(message + count) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); int notificationId = Integer.parseInt(("" + System.currentTimeMillis()).substring(10)); notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- RegistrationIntentService.java
向GCM服务器进行设备注册,获取注册token,该token会作为通知消息接收设备的标识,该类中还进行了topics的订购。 - MyInstanceIDListenerService.java
接收token更新通知,收到通知后会重新通过RegistrationIntentService获取新的token。 - GcmSender.java
推送消息发送类,通过该类向GCM发送HTTP消息,GCM再推送给终端设备。该类并不是必需的,下文也提到了,可以通过Postman等工具直接发送HTTP消息。
- MyGcmListenerService.java
- 下载配置文件。
下载过程中会给出API Key和Sender ID。(没记住也没关系,管理台上也可以查到,分别对应API Key和Project number) - 将配置文件放入工程注意,工程下载好后,里面默认代码使用的API Key以及Sender ID需要修改。API Key: GcmSender.java(模拟服务器向Google发送推送消息使用,后面可以不用main函数,直接用浏览器插件发消息的方式,更方便点。)Sender ID:RegistrationIntentService.java(代码默认使用的是”R.string.gcm_defaultSenderId”)。
- 安装并运行示例App
工程打开时会向Google注册,并获取注册Token,logcat日志中会打出来。后面发送消息时以获取到的token作为客户端设备标识。
02-23 10:39:18.709 19735-19763/gcm.play.android.samples.com.gcmquickstart I/RegIntentService: GCM Registration Token:
dnbhEeyYCWg:APA91bH_yYRmgPsuzpC7qMKp86JV3jR5d...Iw6VvPHilRa2d9u7sW4Xs6El2S1nsqtGM4yO2vVjHv-nSs_DkF3-sdn3b...7mxrbdsyl5xb53- 1
- 2
- 1
- 2
发送通知消息
下载下来的工程中GcmSender.java这个类就是专门发消息的,Google的指导中有给出调用其Main函数的命令,本文推荐直接通过浏览器插件或工具发送(反正就是个HTTPS的消息,用什么发都一样,对吧)。
推荐”Postman”,通过Chrome网上应用店安装,有独立的应用版本。
推荐”Postman”,通过Chrome网上应用店安装,有独立的应用版本。
消息内容如下:
其中消息头中的key为API Key(Google管理台上可以查),token为上文第四步中提到的注册token。
其中消息头中的key为API Key(Google管理台上可以查),token为上文第四步中提到的注册token。
- 消息1:发给某一个topic,to为topic的名称(可以实现群发)。
参考链接:https://developers.google.com/cloud-messaging/topic-messaging
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
"to": "/topics/foo-bar",
"data": {
"message": "This is a GCM Topic Message!",
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 消息2:指定发送给一个设备,to即上文提到的注册token。
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
"to": "token",
"data": {
"message": "This is a GCM token Message!",
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 消息3:发送给多个设备,token1、token2即上文提到的注册token。
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
"registration_ids": ["token1","token2"],
"data": {
"message": "This is a GCM token Message!",
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
订阅:
博文 (Atom)