`

获取IMEI号耗时10秒导致黑屏的解决

阅读更多

描述:一个应用,首次安装应用黑屏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号

    ### Android获取IMEI号:详解TelephonyManager类与设备识别码 在Android开发中,获取设备的唯一识别码(如IMEI号)是一项常见的需求,主要用于设备标识、数据分析或安全验证等场景。IMEI(International Mobile ...

    android系统中获取imei号.zip_IMEI_android_android系统中获取imei号_安卓获取imei_手机

    在android系统中获取imei号,手机号等。

    android与PC通过USB通信,获取IMEI号

    然而,部分Android设备可能不支持通过ADB直接获取IMEI,为解决这个问题,我们可以创建一个简单的APK(例如`GetIMEI.apk`),其内部包含一个能够获取IMEI并通过USB发送给PC的Service。这个Service可以在后台运行,...

    android获取IMEI号码 手机版本信息

    - 获取Android SDK版本号(如:10,19等): ```java int sdkVersion = Build.VERSION.SDK_INT; ``` - 获取设备制造商(如:Samsung, Google等): ```java String manufacturer = Build.MANUFACTURER; ``` - 获取...

    C# 获取IMEI即获取移动设备手机串号手机编码号源代码

    在C#编程环境中,如果你需要在Windows Phone、Android或iOS等平台上获取IMEI,你需要根据不同的平台实现不同的方法。本篇文章将详细讲解如何在C#中获取IMEI,主要针对Windows Phone和Android平台。 对于Windows ...

    获取手机IMEI号、手机型号等

    IMEI号通常可以在手机的包装盒、设备背面、或者通过拨号盘输入"*#06#"来获取。 IMEI号分为两部分:TAC(Type Allocation Code)和FAC(Final Assembly Code),前者是设备类型代码,由制造商分配,用于区分不同型号...

    Android中获取IMEI码的方法

    核心代码:Imei = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId();1.加入权限在manifest.xml文件中要添加 ”android.permission.READ_PHONE_STATE”&gt;2.代码 代码如下:package ...

    获取手机号和IMEI.rar

    在Android系统中,获取设备的IMEI(International Mobile Equipment Identity)和手机号码是常见的操作,尤其对于开发者来说,这些信息在实现特定功能时至关重要。IMEI是设备的唯一标识符,而手机号码则关联到用户的...

    【Android】获取IMEI码

    在本文中,我们将详细探讨如何在Android应用中获取IMEI码,并通过一个名为“Etzmico_GetIMEIInfo”的示例项目进行演示。 首先,获取IMEI码在Android的不同版本中可能会有所不同,因为出于隐私保护考虑,Google在...

    android平台获取手机IMSI,IMEI ,序列号,和 手机号的方法

    Android 平台获取手机 IMSI、IMEI、序列号和手机号的方法 Android 操作系统提供了多种方法来获取手机的 IMSI、IMEI、序列号和手机号,这些信息对于移动应用程序的开发和维护非常重要。本文将详细介绍 Android 平台...

    不同手机设备 获取IMEI

    ### 不同手机设备获取IMEI方法详解 #### 一、前言 国际移动设备身份(International Mobile Equipment Identity,简称IMEI)是每台移动电话所独有的编号,它可以帮助运营商识别和跟踪每一部设备,用于防盗和其他...

    在JNI中得到手机IMEI号

    ### 在JNI中获取Android设备IMEI号的方法 #### 背景介绍 在移动应用开发过程中,有时...综上所述,通过JNI来获取Android设备的IMEI号是一个实用且高效的解决方案,但同时也需要注意遵循相关的法律法规以及最佳实践。

    不同手机获取IMEI get IMEI

    ### 不同手机获取IMEI的方法 #### 概述 国际移动设备识别码(International Mobile Equipment Identity,简称IMEI)是全球唯一的移动电话识别码,它能够帮助制造商、运营商及用户追踪和识别每台设备的独特性。不同...

    WinCE下100%获取IMEI和IMSI号

    在C++编程中获取IMEI和IMSI号是一项挑战,因为这些信息通常存储在设备的硬件中,并且访问权限受到限制。以下是一些关于如何在WinCE系统中100%正确获取IMEI和IMSI的知识点: 1. **IMEI获取**: - 在WinCE系统中,...

    IMEI号生成器

    IMEI号生成器是一种软件工具,能够生成符合IMEI号码规则的随机序列,通常用于测试、模拟或教学等目的。 IMEI号的结构分为几个部分: 1. **TAC(Type Allocation Code,类型分配代码)**:前6位,由GSM协会分配,...

    c#获取mobile手机的IMEI和IMSI

    在C#中获取IMEI主要针对Windows Phone和使用Xamarin或.NET MAUI的Android平台,而获取IMSI则涉及更高级别的权限和隐私考虑,一般不推荐直接获取。在实际应用中,应遵循最小权限原则,尊重并保护用户隐私。同时,注意...

    获取手机IMEI号,sim卡的IMSI号C#源码

    总之,通过C#获取IMEI号和IMSI号涉及到对移动设备硬件和网络通信的理解,以及对相应平台API的熟悉。在开发过程中,需要遵守隐私法规,确保用户数据的安全。`MobileCore.cs`和`TapiLib.dll`是实现这些功能的关键组件...

    Imei号无效解决方案

    ### Imei号无效解决方案 #### 一、背景与概述 IMEI(International Mobile Equipment Identity)国际移动设备身份码,是全球唯一的识别每台终端设备的序列号,通常用于移动电话等移动通信设备上。IMEI号由15位数字...

    基于Android10.0的MAC地址,IMEI号,手机号,MSISDN号,ICCID号获取的可行性验证

    基于Android10.0的设备上,获取相应的MAC地址,手机IMEI号,手机号,手机MSISDN号,手机ICCID号,进行可行性验证,特别是MAC地址方面,在Android10.0前后的设备均进行相应的接口验证,保证其可用性。适合正在致力于...

Global site tag (gtag.js) - Google Analytics