获取签名文件MD5

获取签名文件MD5

1. 获取MD5的一般方式

1.1 有签名文件(.keystore)的情况下:

keytool -list -v -keystore XXX.keystore

1.2 有apk包的情况下:
1
keytool -printcert -jarfile XXX.apk
1.3 解压apk包,拿到META-INF/CERT.RSA文件:
1
keytool -printcert -file CERT.RSA

2. 获取MD5最有效的方式

2.1 点击运行此gradle的Task
2.2 执行gradle命令:
1
./gradlew signingReport
如果没有对应的gradle task任务 需要到AndroidStudio设置中设置。

Android Studio中Setting -> Experimental -> 取消勾选 Gradle栏目下的 Only include test tasks in the Gradle task list generated during Gradle Sync 选项 -> 重新构建项目

android EditText 限定中文个数与英文个数的解决方式

android EditText 限定中文个数与英文个数的解决方式

EditText 限定中文8个英文16个的解决方法。在EditText上控件提供的属性中有限定最大最小长度的方法。可是,对于输入时,限定中文8个英文16个时,怎么办?相当于一个中文的长度是两个英文的长度。原理就不说了。自己看一下android的源代码。以上直接上代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private final int maxLen = 16;
private InputFilter filter = new InputFilter() {@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {int dindex = 0;
int count = 0;
while (count <= maxLen && dindex < dest.length()) {char c = dest.charAt(dindex++);
if (c < 128) {count = count + 1;
} else {count = count + 2;
}}if (count > maxLen) {return dest.subSequence(0, dindex - 1);
}int sindex = 0;
while (count <= maxLen && sindex < source.length()) {char c = source.charAt(sindex++);
if (c < 128) {count = count + 1;
} else {count = count + 2;
}}if (count > maxLen) {sindex--;
}return source.subSequence(0, sindex);
}};

使用例如以下:

1
editText.setFilters(new InputFilter[]{filter});
使用adb导出某个app

使用adb导出某个app

第一步查看app的包名

利用monitor监视要打开的app

1
2
3
PS D:\log> adb shell am monitor
##这时点击运行手机上要看包名的app,就可以看到启动的包名了
** Activity resuming: com.xxx.xxx

第二步 查看包存放路径

第一步可看到打开的app包名是com.xxx.xxx,接下来查看该包存放路径

1
2
PS D:\log> adb shell pm path com.xxx.xxx
package:/data/app/com.xxx.xxx-vgd98TTQzWZTy_qnmQMcIg==/base.apk

第三步 导出到电脑上

将包名 为com.xxx.xxx 的apk导出到电脑

1
PS D:\log> adb pull /data/app/com.xxx.xxx-vgd98TTQzWZTy_qnmQMcIg==/base.apk
查看 Android 手机的 CPU 架构

查看 Android 手机的 CPU 架构

查看 Android 手机的 CPU 架构
Win + R 然后输入 cmd
执行:

  1. adb shell
  2. cat /proc/cpuinfo

PD1938:/ $ cat /proc/cpuinfo
processor : 0
BogoMIPS : 52.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8 (7 表示arm-v7,8表示arm-v8)
CPU variant : 0x1
CPU part : 0xd05
CPU revision : 0

processor : 1
BogoMIPS : 52.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd05
CPU revision : 0

processor : 2
BogoMIPS : 52.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd05
CPU revision : 0

Android 事件分发流程

Android 事件分发流程

前面一篇文章中我们分析了App返回按键的分发流程,从Native层到ViewRootImpl层到DocorView层到Activity层,以及在Activity中的dispatchKeyEvent方法中分发事件,最终调用了Activity的finish方法,即销毁Activity,所以一般情况下假如我们不重写Activity的onBackPress方法或者是onKeyDown方法,当我们按下并抬起返回按键的时候默认都是销毁当前Activity。而本文中我们主要介绍触摸事件的分发流程,从Native层到Activity层触摸事件的分发了流程和按键的分发事件都是类似的,这里我们可以根据异常堆栈信息看一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
at com.example.aaron.helloworld.MainActivity.dispatchTouchEvent(MainActivity.java:103)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2359)
at android.view.View.dispatchPointerEvent(View.java:8698)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4530)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4388)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3924)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3977)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3943)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4053)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3951)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4110)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3924)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3977)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3943)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3951)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3924)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6345)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6301)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6254)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6507)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)

这样经过一系列的方法调用之后最终调用了Activity的dispatchTouchEvent方法,而我们也是从Activiyt的dispatchTouchEvent方法开始对触摸事件的分发进行分析。

在具体查看Activity的dispatchTouchEvent方法之前我们先简单介绍一下触摸事件,触摸事件是由一个触摸按下事件、N个触摸滑动事件和一个触摸抬起事件组成的,通常的一个触摸事件中只能存在一个触摸按下和一个触摸抬起事件,但是触摸滑动事件可以有零个或者多个。好了,知道这个概念以后,下面我们就具体看一下Activity中的dispatchTouchEvent的实现逻辑。

1
2
3
4
5
6
7
8
9
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
安装apk提示Failure [INSTALL_FAILED_TEST_ONLY/ installPackageL

安装apk提示Failure [INSTALL_FAILED_TEST_ONLY/ installPackageL

Failure [INSTALL_FAILED_TEST_ONLY: installPackageLI]

平台版本是android 7.0,在adb install *.apk 会提示下面的错误:

Failure [INSTALL_FAILED_TEST_ONLY: installPackageLI]

方法1:

修改AndroidManifest.xml 中android:testOnly=”true” 改成 android:testOnly=”false”,或者直接去掉。

方法2:

adb push *.apk /tmp

adb shell pm install -t /tmp/*.apk

方法3:

adb install -t *.apk

方法4:

Android Studio 3.0 and FLAG_TEST_ONLY 一文中,给出了关于Android studio 3.0中出现问题的说明:
Option to indicate this application is only for testing purposes.
For example, it may expose functionality or data outside of itself that would cause a security hole, but is useful for testing.
This kind of application can not be installed without the INSTALL_ALLOW_TEST flag, which means only through adb install.

  1. You cannot install an app with android:testOnly=”true” by conventional means, such as from an Android file manager or from a download off of a Web site
  2. Android Studio 3.0 sets android:testOnly=”true” on APKs that are run from the IDE

解决办法:
在gradle.properties(项目根目录或者gradle全局配置目录 ~/.gradle/)文件中添加:
android.injected.testOnly=false

请转载的朋友表明出处:
http://blog.csdn.net/shift_wwx/article/details/78468397

Gradle编译Build output乱码
CoordinatorLayout 与viewpage 使用 viewpager 内如何空出子布局高度

CoordinatorLayout 与viewpage 使用 viewpager 内如何空出子布局高度

在子布局中使用 添加NestedScrollView
并添加
android:fillViewport=”true”
android:fitsSystemWindows=”true”

<android.support.v4.widget.NestedScrollView
android:id=”@+id/nest_scrollview”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:layout_gravity=”fill_vertical”
android:fillViewport=”true”
android:fitsSystemWindows=”true”
app:layout_behavior=”@string/appbar_scrolling_view_behavior”>

   <your layout>

</android.support.v4.widget.NestedScrollView>

Anroid开发艺术探究

Anroid开发艺术探究

1.onStart 和 onResume、onPause和onStop从描述上来看差不多,对我们来说有什么实质的不同?
onStart 和 onStop是从Activity是否可见这个角度来回调的,而onResume和onPause是从Activity是否位于前台这个角度来回调的,除了这种区别,没有其他区别

2.假设当前Activity为A,如果这时用户打开一个新Activity B,那么 B 的onResume()和 A 的onPaus()哪个先执行呢?
启动Activity的请求会由Instrumentation来处理,然后它通过Binder向AMS发请求,AMS内部维护着一个ActivityStack并负责栈内的Activvity的状态,AMS通过
ActivityThread去同步Activity的状态从而完成生命周期方法的调用。在ActivityStack中的resumeTopActivityInnerLocked方法中,在新Acctivity启动之前,
栈顶的Activity需要先onPause()后,新Activity才能启动。最终在ActivityStackSupervisor中的realStartActivityLocked方法会调用scheduleLaunchActivity,
接着完成新Activity的onCreate、onStart、onResume的调用过程。因此,可以得到结论,是旧Activity先onPause,然后新Activity再启动。

3.Activity被销毁并重建后,我们去获取之前的存储字符串,接受的位置可以是onRestoreInstanceState 或者 onCreate 方法,两者区别是?
onRestoreInstanceState一旦被调用,其参数Bundle savedInstanceState 一定是有值的,我们不用额外的拍断是否为空;
但是onCreate不行,onCreate如果正常启动的话,其参数Bundle savedInstanceState为null, 所以必须要额外判断。

4.onSaveInstanceState和onRestoreInstanceState,在正常流程下会出发么?
系统只在Activity异常种植的时候才会调用onSaveInstanceState和onRestoreInstanceState来存储和恢复数据,其他情况不会出发这个过程。

5.比如目前任务栈S1中的情况为ABC,这个时候Activity D 以singleTask模式请求启动,其所需要的任务栈为 S2,由于S2和D的实例均不存在,所以系统会先创建
任务栈S2,然后在创建D的实例并将其入栈到S2.

6.TaskAffinity任务相关性。
这个参数标识一个Activity所需要的任务栈的名字,默认情况下,所有Activity所需的任务栈的名字为应用的包名。可以为每个Activity都单独制定TaskAffinity属性,
这个属性必须不能和包名相同,否则就相当于没有制定。TaskAffinity属性主要和singleTask启动模式或者allTaskReparenting属性配对使用。当TaskAffinity和singleTask启动模式配对使用的时候,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity回运行在名字和TaskAffinity相同的任务栈中。
当TaskAffinity和allowTaskReparenting结合的时候,会产生特殊的效果。当一个应用A启动了应用B的某个Activity后,如果这个Activity的allTaskReparenting属性为true的话,那么当应用B被启动后,词Activity回直接从应用A的任务栈转移到应用B的任务栈中。

7.SharedPerences是否安全?
SharedPreferences不支持两个进程同时去执行写操作,否则会导致一定几率的数据丢失,因为SharedPreferences底层是通过读/写XML文件来实现的,并发会出问题。
每个应用的SharedPreferences文件都在当前包所在的data目录下查看到,目录位于 /data/data/pacakage name/shared_prefs目录下。
SharedPreferences也属于文件的一种,但是由于系统对他的读/写有一定的缓存策略,即在内存中有一份ShareePreferences文件的缓存,因此在多进程下,系统对它的读写诗不可靠的,当面对高并发的读/写访问,有很大几率丢失文件。

8.Serializable接口的原理及serialVersionUID作用?
想让一个对象实现序列化,只需要这个类实现Serializable接口并声明一个serialVersionUID即可。实际上,甚至连这个serialVersionUID也不是必须的。如何进行对象的序列化和反序列化也很简单,只需要采用ObjectOutputStream和ObjectInputStream,readObject()writeObject()函数。
serialVersionUID是用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID只有和当前累的serialVersionUID相同时才能够正常的被反序列化。
serialVersionUID的详细工作机制时这样的:序列化的时候系统把当前类的serialVersionUID写入序列化文件中,当反序列化时候系统回去检测文件中的serialVersionUID,看它是否和当前类的serialVersionUID一致,如果一致就说明序列化的类的版本和当前类的版本时相同的,这个时候可以成功反序列化;否则就说明当前类和序列化的类相比发生了某些变化,比如成员变量的数量、类型可能发生了改变,这个时候时无法正常反序列化的。

9.Parcelable接口原理?
Parcelable也是一个接口,只要实现这个接口,一个类的对象就可以实现序列化并通过Intent和Binder传递。
Parcel内部包装了可序列化的数据,可以在Binder中自由传输。
序列化的功能由writeToParcel方法来完成,最终时通过Parcel的一系列write方法来完成的;
反序列化功能由CREATOR来完成,其内部表明了如何创建序列化对象和数组,并通过Parcel的一系列read方法来完成反序列化过程。

应用程序返回按键执行流程

应用程序返回按键执行流程

从这篇文章中我们开始分析android系统的事件分发流程,其实网上已经有了很多关于android系统的事件分发流程的文章,奈何看了很多但是印象还不是很深,所以这里总结一番。
android系统的事件分发流程分为很多部分:

  • Native层 –> ViewRootImpl层 –> DecorView层 –> Activity层 –> ViewGroup层 –> View层

所以android系统的事件分发流程是从Native层开始的,然后分发到ViewRootImpl中,然后分发到DecorView层,然后分发到ViewGroup层,最后分发到View层中。下面我们将从Native层开始分析事件的分发流程。

在Native层android系统的事件流程:

  • Android系统是从从底层驱动中获取各种原始的用户消息,包括按键、触摸屏、鼠标、滚迹球等用户事件消息。

  • 在获取用户消息之后,android系统会对最原始的消息进行预处理,包括两个方面:一方面,将消息转化成系统可以处理的消息事件;另一方面,处理一些特殊的事件,比如HOME、MENU、POWER键等处理(前面的几篇文章中我们已经分析了系统按键处理逻辑的执行流程)。

  • 将处理后的消息事件分发到各个应用进程,这个需要使用IPC机制,Android系统使用管道来进行消息的传递。

  • Android系统使用InputManager类来管理消息,而具体的功能则是通过InputReaderThread和InputDispatcherThread两个线程来实现。其中InputReaderThread线程负责消息的读取,而InputDispatcherThread则负责消息的预处理和分发到各个应用进程中。

  • Acitivty系统在SystemServer进程中启动WindowManagerService服务,然后在WindowManagerService服务中启动InputManagerService服务。

可以看到在Native层,主要创建了两个两个线程,其中一个用于读取消息,另一个用于分发消息,消息经过分发最终会上传至App中。

在ViewRootImpl层android系统的事件流程

在Native层的事件分发线程中,经过事件的分发流程,最终会调用InputEventSender的dispatchInputEventFinished方法,可以看一下具体代码的实现:

1
2
3
private void dispatchInputEventFinished(int seq, boolean handled) {
onInputEventFinished(seq, handled);
}

在dispatchInputEventFinished方法中我们最终调用的是onInputEventFinished方法,然后我们查看onInputEventFinished方法的实现,发现其是一个空方法。。。,好吧,经过分析我们发现,Native层最终调用的并不是InputEventSender,而是调用InputEventSender的子类ImeInputEventSender,即ImeInputEventSender的onInputEventFinished方法,该类定义在源文件InputMethodManager中:


:D 一言句子获取中...