首页 > 其他分享 >Android-service

Android-service

时间:2023-04-21 11:11:56浏览次数:75  
标签:Service service process Application 进程 Android android

原文地址 zhuanlan.zhihu.com

残枫cps残枫cps

Service 是一种可在后台执行长时间运行操作而不提供界面的应用组件。

Android Service
Android Service是组件,既不能说它是单独的进程也不能说它是单独的线程。
如果非要从通俗的语言层面来理解的话,姑且将其理解为对象。这个Service对象本身作为应用程序的一部分与它的调用者运行在相同的进程,当然如果指定了process则会运行到另外的进程。指定到其他进程的方法参加Service属性的"android:process"。

Android Service可以在后台运行,不需要给用户提供任何的界面。但是Service是默认运行在主线程的,不要以为可以直接把它放在后台作耗时操作,如果要做耗时操作还是需要在Service里另起线程的,否则你懂得,会阻塞主线程造成ANR。
Service是组件:默认运行在当前进程的主线程中的,如果需要执行耗时操作,记得在Service里创建新线程;
Service用来提高优先级:在后台场景下,Service的优先级是高于后台挂起的Activity的,也高于Activity所创建的线程。这样的话,在内存不足时,Service不会被优先杀死。

Android之Service设置android:process作用
在AndroidManifest.xml中定义service时会看到这样的代码android:process=”:remote”,例如:

这个代码是什么意思呢?
我们先来了解一下Service在AndroidManifest.xml中的声明语法,其格式如下:

<service android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:
android:permission="string"
android:process="string" >

. . .
● android:exported:代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。
● android:name:对应Service类名
● android:permission:是权限声明
● android:process:是否需要在单独的进程中运行,当设置为android:process=”:remote”时,代表Service在单独的进程中运行。注意“:”很重要,它的意思是指要在当前进程名称前面附加上当前的包名,所以“remote”和”:remote”不是同一个意思,前者的进程名称为:remote,而后者的进程名称为:App-packageName:remote。
● android:isolatedProcess :设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(bind and start)。
● android:enabled:是否可以被系统实例化,默认为 true因为父标签 也有 enable 属性,所以必须两个都为默认值 true 的情况下服务才会被激活,否则不会激活。
1)默认情况(不指定process属性)
1、一个app只运行在一个进程中,进程名字为包名。
2、一个service(所有组件都一样)只作为一个线程运行在app的进程中,没有自己独立的进程。

2)设置android:process="xxxx"后
1、设置了这行代码,系统就会为service创建新的进程
service将运行在这个新的独立的进程,它所在的apk依旧运行在原来进程。这样就实现了Android使用多进程
2、属性值可以随意定义
xxxx是自定义的,上面代码的remote是随便写的
3、当属性值以冒号开头 :,如 android:process = “ :xxxx ”
表示:将为 app 创建一个私有进程,其他 app 无法访问,进程名称是:包名: xxxx
4、当属性值以小写字母开头,如 android:process = “xxxx”
表示:这个进程是对外公开的,其他app可以访问它,进程名称是:xxxx

注意:a) 和四大组件节点都可设置
b)设置 可以指定app的进程名称
c)若 节点和四大组件都设置了android:process="xxx:xxxx"属性,以组件的属性为准

下面援引官方说明文档:

3)多进程引发的问题
静态成员和单例失效:每个进程保持各自的静态成员和单例,相互独立。
线程同步机制失效:每个进程有自己的线程锁。
SharedPreferences可靠性下降:不支持并发写,会出现脏数据
Application多次创建:不同进程跑在不同虚拟机,每个虚拟机启动会创建自己的Application,自定义Application时生命周期会混乱。
综上,不同进程拥有各自独立的虚拟机,Application,内存空间,由此引发一系列问题,因此在跨进程通信开发时,要注意避开上述问题。

重点来了,因为设置了 android:process 属性将组件运行到另一个进程,相当于另一个应用程序,所以在另一个线程中也将新建一个 Application 的实例。因此,每新建一个进程 Application 的 onCreate 都将被调用一次。 如果在 Application 的 onCreate 中有许多初始化工作并且需要根据进程来区分的,那就需要特别注意了。
让我们到 Framework 中看看新建进程的逻辑,请打开老罗的博客 : Android系统在新进程中启动自定义服务过程(startService)的原理分析
详细介绍了新进程启动的过程,其中我们重点看到 Step 17. ActivityThread.handleCreateService中

public final class ActivityThread {

......

private final void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();

LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo);
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name

  • ": " + e.toString(), e);
    }
    }

try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

ContextImpl context = new ContextImpl();
context.init(packageInfo, null, this);

Application app = packageInfo.makeApplication(false, mInstrumentation);
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 0, 0, 0);
} catch (RemoteException e) {
// nothing to do.
}

} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name

  • ": " + e.toString(), e);
    }
    }
    }

......

}

看到这行 Application app = packageInfo.makeApplication(false, mInstrumentation); 在这里创建了 Application 。
解决方案
获取当前运行进程的名称:
方案1

public static String getProcessName(Context cxt, int pid) {
ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);
List runningApps = am.getRunningAppProcesses();
if (runningApps == null) {
return null;
}
for (RunningAppProcessInfo procInfo : runningApps) {
if (procInfo.pid == pid) {
return procInfo.processName;
}
}
return null;
}

目前网上主流的方法,但效率没有方案2高,感谢由王燚同学提供的方案2

方案2

public static String getProcessName() {
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
String processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
return processName;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

然后在 Application 的 onCreate 中获取进程名称并进行相应的判断,例如:

String processName = getProcessName(this, android.os.Process.myPid());

if (!TextUtils.isEmpty(processName) && processName.equals(this.getPackageName())) {//判断进程名,保证只有主进程运行
//主进程初始化逻辑
....
}

Application 的onCreate方法,竟然执行了好几次
之前在做项目时,遇到一个大坑,就是我的APP 的Application 的onCreate方法,竟然执行了好几次,这就导致我在onCreate里面做了一些初始化的操作被重复执行了,导致奇怪的bug产生。后来冷静下来分析一下,才发现有一些第三方组件,比如百度推送之类的,它们是单独开了一个进程,那么每个进程会自己初始化自己的Application,那自然onCreate方法会多次执行。准确的说就是你的APP里有多少个进程,就会初始化多少次Application 。

但是有的东西就是只需要在Application 的onCreate 里只初始化一次。那怎么解决呢?看代码:

public class MyApplication extends Application {
private final static String PROCESS_NAME = "com.test";
private static MyApplication myApplication = null;

public static MyApplication getApplication() {
return myApplication;
}

/**

  • 判断是不是UI主进程,因为有些东西只能在UI主进程初始化
    */
    public static boolean isAppMainProcess() {
    try {
    int pid = android.os.Process.myPid();
    String process = getAppNameByPID(MyApplication.getApplication(), pid);
    if (TextUtils.isEmpty(process)) {
    return true;
    } else if (PROCESS_NAME.equalsIgnoreCase(process)) {
    return true;
    } else {
    return false;
    }
    } catch (Exception e) {
    e.printStackTrace();
    return true;
    }
    }

/**

  • 根据Pid得到进程名
    */
    public static String getAppNameByPID(Context context, int pid) {
    ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    for (android.app.ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
    if (processInfo.pid == pid) {
    return processInfo.processName;
    }
    }
    return "";
    }

@Override
public void onCreate() {
super.onCreate();

myApplication = this;

if (isAppMainProcess()) {
//do something for init
}
}
}

发布于 2023-04-17 10:46・IP 属地山东开启赞赏赞赏开启后,读者将可以付费支持你的创作。AndroidAndroid 应用Android 开发​赞同​添加评论​分享​喜欢​收藏​设置

标签:Service,service,process,Application,进程,Android,android
From: https://www.cnblogs.com/cps666/p/17339666.html

相关文章

  • 如何通过Android studio 安装卸载apk
    原文地址zhuanlan.zhihu.com残枫cps​目录收起adb配置安装删除apkadb配置自己在安装AndroidStudio的adb时遇到了配置好了环境变量,在cmd中可以执行adb命令行,而在AndroidStudio中的Terminal中却无法执行,显示adb不是内部或外部命令.一、配置环境变量首先要找到adb.exe的......
  • Android事件分发-基础原理和场景分析
    作者:京东零售 郭旭锋1为什么需要事件分发和其他平台类似,Android中View的布局是一个树形结构,各个ViewGroup和View是按树形结构嵌套布局的,从而会出现用户触摸的位置坐标可能会落在多个View的范围内,这样就不知道哪个View来响应这个事件,为了解决这一问题,就出现了事件分发......
  • Android进程间的通信方式
    原文地址juejin.cn前言在日常的开发中,我们可能会接触到多进程,比如向外界提供服务,或者因为某些原因把某个操作分离到独立的进程执行等等。那么进程与进程之间没办法直接进行数据的传输,也就是我们常说的进程间通信,因此需要借助特定的方案,下面我们一起了解一下几种进程间通信的......
  • 深入理解Android进程间通信机制
    原文地址juejin.cnAndroid系统中有大量IPC(进程间通信)的场景,比如我们想要创建一个新的进程,需要通过Socket这种IPC方式去让ZygoteFork新进程;如果我们要杀掉一个进程,需要通过信号这种IPC方式去将SIGNAL_KILL信号传递到系统内核;如果我们想要唤醒主线程处于休眠中的Looper,需要管道......
  • Android进程间通信总结
    原文地址blog.csdn.netIPCIPC为(Inter-ProcessCommunication)缩写,称为进程间通信或跨进程通信,指两个进程间进行数据交换的过程。安卓中主要采用Binder进行进程间通信,当然也支持其他IPC方式,如:管道,Socket,文件共享,信号量等。Binder简介1.为什么使用Binder?性能方面:......
  • android8 rk3399 同时支持多个USB摄像头
    文章目录一、前文二、CameraHal_Module.h三、CameraHal_Module.cpp四、编译&烧录Image五、App验证一、前文Android系统默认支持2个摄像头,一个前置摄像头,一个后置摄像头需要支持数量更多的摄像头,得修改AndroidHal层的代码二、CameraHal_Module.h修改CAMERAS_SUPPORT_MAX三、Camer......
  • Android问题解决:android.os.FileUriExposedException: file:///storage/......Intent.
    文章目录一、遇到问题二、解决问题三、分析问题一、遇到问题---------beginningofcrash2022-12-2720:18:15.01014422-14422/com.lisi.evidence_boxE/AndroidRuntime:FATALEXCEPTION:mainProcess:com.lisi.evidence_box,PID:14422android.os.FileUriExpose......
  • android折线图的实现
    一:配置参考上篇博客二:模板代码MainActivity:publicclassMainActivityextendsAppCompatActivity{privateLineChartmChart;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentVi......
  • Android安全检测 - 发送隐式广播风险
    这章来学习“发送隐式广播风险”,这个风险和动态注册Receiver风险有呼应之处,可以结合起来一起看。一、漏洞原理隐式广播是指未指定接收方(接收的范围),在发送广播的过程中所有的APP均能够接收到这个广播,那么就会存在广播被拦截的风险,若发送的广播携带数据那么就存在数据泄漏的风险,若......
  • Android升级WebView浏览器内核版本
    使用AOSP项目编译的Android系统,会发现在部分APP使用系统自带的浏览器内核来加载网页时会出现报错,加载不出网页的情况,其实这是由于WebView自带的浏览器内核版本太旧所导致的,只要更新成比较新的浏览器内核版本就行了。一、环境准备(1)Android系统源码编译环境(Android9.0)二、下载新......