描述:一个应用,首次安装应用黑屏5秒左右后才开始显示正常界面。在做桌面应用的时候,由于桌面一直被用所以也没怎么发现,而且该问题是只有每次卸载(或者之前没有该应用)之后再次安装首次启动才会出现黑屏。后来经过打印时间才定位到是因为初始化的时候获取IMEI耗时了10s多(在界面设置要显示的View之前).
获取IMEI(设备ID):Requires Permission: READ_PHONE_STATE
TelephonyManager tm = (TelephonyManager) mContext .getSystemService(Service.TELEPHONY_SERVICE); String deviceId = tm.getDeviceId();
查看源码:
622 public String More ...getDeviceId() { 623 try { 624 return getITelephony().getDeviceId(); 625 } catch (RemoteException ex) { 626 return null; 627 } catch (NullPointerException ex) { 628 return null; 629 } 630 }
2369 private ITelephony More ...getITelephony() { 2370 return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); 2371 }
好吧,AIDL实现的,比较底层,木有去看,不过也猜出了个一二了,因为初始化的时候直接在主线程里去获取IMEI,而获取IMEI是需要权限的,这个时候系统会弹出个框让你选择是否授权,一般当用户点击的时候已经过了系统判断的时间了,于是又等10秒再去判断(当然这只是结合以为大神和我自己的看法),这就导致了主线程需要10s才获得IMEI,获取到IMEI之后才去设置要显示的View,所以之前就出现了黑屏。
解决:在初始化的时候开启一个线程去获取,当获取到值的时候再回调给需要IMEI的地方。但是这里获取IMEI的时间不一,可能要几毫秒,也可能是10多秒。再者就是不同的时间去获取,等待的时间不一,可能先获取的地方等待的时间更长,所以,干脆每次需要获取的时候都去开启一个线程获取,于是便有了以下设计
(为什么不是直接用一个子线程去获取然后赋值?耗时长,多次请求可以加大概率,而且可能不同的地方需要获得该值),如果是只有一个地方需要初始化的话,可以只要单独一个线程去获取就好。
public class MainActivity extends Activity { private Context mContext; private String mImei; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; // 初始化获取IMEI IMEIUtils.getInstance().init(mContext); // 其他事情 // 其他事情 // 在需要的地方获取IMEI; mImei = IMEIUtils.getInstance().getImei(); if (IMEIUtils.getInstance().isImeiGetting(mImei)) {// 如果是正在获取当中 mImei = IMEIUtils.getInstance().getNullImei();// 先给他初始化一个空值的 // 添加监听 IMEIUtils.getInstance().addOnImeiGetListener(new ImeiGetListener() { @Override public void onGetIMEIOk(String imei) {// 得到之后将回调其值给需要的地方 mImei = imei; } }); } } }
public class IMEIUtils { private static final String TAG = "IMEIUtils"; private static final String IMEI_RESULT_GETTING = "imei_result_getting"; private String mIMEI = ""; private ArrayList<ImeiGetListener> mEncodeImeiListenerList = new ArrayList<ImeiGetListener>(); private static IMEIUtils mEncodeImeiUtils = null; private Context mContext; private IMEIUtils() { } public synchronized static IMEIUtils getInstance() { if (mEncodeImeiUtils == null) { mEncodeImeiUtils = new IMEIUtils(); } return mEncodeImeiUtils; } /** * 初始化 * * @param context */ public void init(Context context) { Log.d(TAG, "initImei"); mContext = context; initImei(); } /** * 开启一个线程去获取IMEI */ private void initImei() { new Thread(new Runnable() { @Override public void run() { if (isImeiGot()) {// 已经获取到该ID了,就不用再去获取了 Log.d(TAG, "initImei is not null, no need to get IMEI " + mIMEI); return; } mIMEI = IMEI_RESULT_GETTING;// 设置该值为获取中 long beginTime = System.currentTimeMillis(); Log.d(TAG, "initEncodeImei begin TelephonyManager.getDeviceId"); TelephonyManager tm = (TelephonyManager) mContext .getSystemService(Service.TELEPHONY_SERVICE); String deviceId = tm.getDeviceId(); if (isImeiGot()) {// 已经获取到该ID了 Log.d(TAG, "sEncodeIMEI is not null ,no need to get value " + mIMEI); } else { mIMEI = deviceId == null ? "test" : deviceId;// ID为空对象则返回一个test(自定义,通常不管获得一个什么字符串,最好都要进行加密) Log.d(TAG, "mIMEI get a value =" + mIMEI); // 通知所有的监听器,将所有结果都回调 for (ImeiGetListener listener : mEncodeImeiListenerList) { listener.onGetIMEIOk(mIMEI); } mEncodeImeiListenerList.clear(); } // 打印一下具体的耗时 long deltaIMEITime = System.currentTimeMillis() - beginTime; Log.d(TAG, "deltaIMEITime=" + deltaIMEITime); } }).start(); } /** * 如果不是空对象,而且不是正在获取中,则说明已经获得了结果了 * * @return */ private boolean isImeiGot() { return mIMEI != null && !IMEI_RESULT_GETTING.equals(mIMEI); } /** * * @return */ public String getImei() { // 空对象,则返回没有空值加密数据 if (null == mIMEI) { Log.d(TAG, "getImei mIMEI==null"); return getNullImei(); } // 正在获取,则再开启一个线程去获取, // 返回IMEI_RESULT_GETTING,获取的地方需要判断,如果是该值则要做一些处理 if (IMEI_RESULT_GETTING.equals(mIMEI) || "".equals(mIMEI)) {// getting Log.d(TAG, "getImei mIMEI is getting"); initImei(); return IMEI_RESULT_GETTING; } // 否则就是已经获取到了,直接返回所需要的 Log.d(TAG, "getImei mIMEI=" + mIMEI); return mIMEI; } public String getNullImei() { return "test";// 自己处理加密 } public boolean isImeiGetting(String encodeImei) { if (encodeImei.equals(IMEI_RESULT_GETTING)) { Log.d(TAG, "isImeiGetting=true"); return true; } return false; } public void addOnImeiGetListener(ImeiGetListener encodeImeiListener) { if (encodeImeiListener == null) { return; } if (isImeiGot()) {// 已经获得了,无需再添加监听器 encodeImeiListener.onGetIMEIOk(mIMEI); return; } if (!mEncodeImeiListenerList.contains(encodeImeiListener)) {// 已经有该监听器了 mEncodeImeiListenerList.add(encodeImeiListener); } } // 监听,回调 public interface ImeiGetListener { public void onGetIMEIOk(String imei); } }
相关推荐
### Android获取IMEI号:详解TelephonyManager类与设备识别码 在Android开发中,获取设备的唯一识别码(如IMEI号)是一项常见的需求,主要用于设备标识、数据分析或安全验证等场景。IMEI(International Mobile ...
在android系统中获取imei号,手机号等。
- 获取Android SDK版本号(如:10,19等): ```java int sdkVersion = Build.VERSION.SDK_INT; ``` - 获取设备制造商(如:Samsung, Google等): ```java String manufacturer = Build.MANUFACTURER; ``` - 获取...
然而,部分Android设备可能不支持通过ADB直接获取IMEI,为解决这个问题,我们可以创建一个简单的APK(例如`GetIMEI.apk`),其内部包含一个能够获取IMEI并通过USB发送给PC的Service。这个Service可以在后台运行,...
在C#编程环境中,如果你需要在Windows Phone、Android或iOS等平台上获取IMEI,你需要根据不同的平台实现不同的方法。本篇文章将详细讲解如何在C#中获取IMEI,主要针对Windows Phone和Android平台。 对于Windows ...
IMEI号通常可以在手机的包装盒、设备背面、或者通过拨号盘输入"*#06#"来获取。 IMEI号分为两部分:TAC(Type Allocation Code)和FAC(Final Assembly Code),前者是设备类型代码,由制造商分配,用于区分不同型号...
核心代码:Imei = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId();1.加入权限在manifest.xml文件中要添加 ”android.permission.READ_PHONE_STATE”>2.代码 代码如下:package ...
在Android系统中,获取设备的IMEI(International Mobile Equipment Identity)和手机号码是常见的操作,尤其对于开发者来说,这些信息在实现特定功能时至关重要。IMEI是设备的唯一标识符,而手机号码则关联到用户的...
在本文中,我们将详细探讨如何在Android应用中获取IMEI码,并通过一个名为“Etzmico_GetIMEIInfo”的示例项目进行演示。 首先,获取IMEI码在Android的不同版本中可能会有所不同,因为出于隐私保护考虑,Google在...
Android 平台获取手机 IMSI、IMEI、序列号和手机号的方法 Android 操作系统提供了多种方法来获取手机的 IMSI、IMEI、序列号和手机号,这些信息对于移动应用程序的开发和维护非常重要。本文将详细介绍 Android 平台...
### 不同手机设备获取IMEI方法详解 #### 一、前言 国际移动设备身份(International Mobile Equipment Identity,简称IMEI)是每台移动电话所独有的编号,它可以帮助运营商识别和跟踪每一部设备,用于防盗和其他...
### 在JNI中获取Android设备IMEI号的方法 #### 背景介绍 在移动应用开发过程中,有时...综上所述,通过JNI来获取Android设备的IMEI号是一个实用且高效的解决方案,但同时也需要注意遵循相关的法律法规以及最佳实践。
### 不同手机获取IMEI的方法 #### 概述 国际移动设备识别码(International Mobile Equipment Identity,简称IMEI)是全球唯一的移动电话识别码,它能够帮助制造商、运营商及用户追踪和识别每台设备的独特性。不同...
在C++编程中获取IMEI和IMSI号是一项挑战,因为这些信息通常存储在设备的硬件中,并且访问权限受到限制。以下是一些关于如何在WinCE系统中100%正确获取IMEI和IMSI的知识点: 1. **IMEI获取**: - 在WinCE系统中,...
IMEI号生成器是一种软件工具,能够生成符合IMEI号码规则的随机序列,通常用于测试、模拟或教学等目的。 IMEI号的结构分为几个部分: 1. **TAC(Type Allocation Code,类型分配代码)**:前6位,由GSM协会分配,...
在C#中获取IMEI主要针对Windows Phone和使用Xamarin或.NET MAUI的Android平台,而获取IMSI则涉及更高级别的权限和隐私考虑,一般不推荐直接获取。在实际应用中,应遵循最小权限原则,尊重并保护用户隐私。同时,注意...
总之,通过C#获取IMEI号和IMSI号涉及到对移动设备硬件和网络通信的理解,以及对相应平台API的熟悉。在开发过程中,需要遵守隐私法规,确保用户数据的安全。`MobileCore.cs`和`TapiLib.dll`是实现这些功能的关键组件...
### Imei号无效解决方案 #### 一、背景与概述 IMEI(International Mobile Equipment Identity)国际移动设备身份码,是全球唯一的识别每台终端设备的序列号,通常用于移动电话等移动通信设备上。IMEI号由15位数字...
基于Android10.0的设备上,获取相应的MAC地址,手机IMEI号,手机号,手机MSISDN号,手机ICCID号,进行可行性验证,特别是MAC地址方面,在Android10.0前后的设备均进行相应的接口验证,保证其可用性。适合正在致力于...