LOCAL_MODULE_TAGS :=user debug eng tests optional
user: 指该模块只在user版本下才编译
debug: 批该模块只在userdebug版本下才编译
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译(但只有在PRODUCT_PACKAGES中定义的模块才会被安装?)
LOCAL_MODULE_TAGS :=user debug eng tests optional
user: 指该模块只在user版本下才编译
debug: 批该模块只在userdebug版本下才编译
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译(但只有在PRODUCT_PACKAGES中定义的模块才会被安装?)
1. gRPC – 远程RPC框架
适用平台:c++、Java、Python、Php、Js等多平台
2. Netty -基于Java NIO client-server的网络应用框架
适用平台:Java
3. thrift – 用于可扩展的跨语言服务开发,简单来说就是RPC远程调用,它是一个完整的 RPC 框架体系。
适用平台:Actionscript 3.0、c_glib、C++、CSharp、D、Dart、Delphi、Go、Graphviz、Haxe Framework、Haskell、Java、Javascript、Node.js、OCaml、Perl、PHP、Python、Ruby
4. SOME/IP(vsomeip) – 用于车载的远程通讯框架,特点:服务发现\带宽预留,符合autosar(汽车开放系统架构)标准.SOME/IP是指协议栈,vsomeip是用c++的实现
适用平台:C/C++
疑问一:如果创建Handler没有为Handler指定Looper,那么Handler用的是哪个Looper?
答:如果没有指定Looper的话,程序会通过Looper.myLooper();来获取当前线程中保存的Looper对象.
扩展:如果一个线程中没有Looper实例,则在创建Handler时即会触发异常
疑问二:如果在程序中建立了多个Handler,都使用同一个Looper(如使用主线程的Looper),那么消息会在每个Handler中都被处理吗?
答:不会,可以看下Handler代码中,enqueueMessage函数里面,将msg.target设置为了Handler本身.而在Looper的loop函数中,是通过msg.target.dispatchMessage(msg);将消息分发出去的,所以不会造成Handler接收消息的错乱.
疑问三:一个线程能不能有多个Looper?
答:不能,Looper的构造函数是私有的,Looper只能通过它的静态方法prepare()函数来创建,这个函数会检查当前线程中是否已有Looper实例,如果已有会报异常,如果没有则创建一个新的.
疑问四:Handler内存泄漏的原理?
Handler内存泄漏是因为,如果创建非静态的内部Handler类,会隐式的持有外部类的实例,所以当Activity销毁时,Handler有未执行的消息时,就会造成内在的泄漏.
并不是有静态内部Handler类就会引起内存泄漏,假如在Activity销毁后,Handler没有继续要执行的工作,也不会造成内存泄漏。
1.adb remount的作用就是重新挂载安卓的系统分区,使系统分区可读写
2.执行该功能其他的方法:
adb shell su #进入安卓命令行
mount -o rw,remount /system #将文件系统remount为读写权限
记得完事后remount回只读: mount -o ro,remount /system
3.另外一种方法
adb shell su #进入安卓命令行
mount -o rw,remount -t ext3 /dev/block/mmcblk1p21 /system
具体请看下面的表格:
1 2 3 4 5 6 7 |
public void overridePendingTransition(int enterAnim, int exitAnim) { try { ActivityManagerNative.getDefault().overridePendingTransition( mToken, getPackageName(), enterAnim, exitAnim); } catch (RemoteException e) { } } |
♠ frameworks/base/core/java/android/app/ActivityManagerNative.java
§ ActivityManagerNative.getDefault() 很简单,获取gDefault | ||
|
||
§ gDefault 一个静态变量,是ActivityManagerService 的代理对象 | ||
|
♠ frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@Override public void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim) { synchronized(this) { ActivityRecord self = ActivityRecord.isInStackLocked(token); if (self == null) { return; } final long origId = Binder.clearCallingIdentity(); if (self.state == ActivityState.RESUMED || self.state == ActivityState.PAUSING) { mWindowManager.overridePendingAppTransition(packageName, enterAnim, exitAnim, null); } Binder.restoreCallingIdentity(origId); } } |
ActivityRecord.isInStackLocked(token); 查询当前Activity是否还在Activity栈中? | ||
|
||
如果还在继续执行Binder.clearCallingIdentity();保存此Activity在Binder中的id,稍候就会使用overridePendingAppTransition执行恢复的操作。 | ||
如果当前Activity的状态是活动状态或者将要暂停状态,执行WindowManagerService的overridePendingAppTransition |
♠ frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
1 2 3 4 5 6 7 8 |
@Override public void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim, IRemoteCallback startedCallback) { synchronized(mWindowMap) { mAppTransition.overridePendingAppTransition(packageName, enterAnim, exitAnim, startedCallback); } } |
调用AppTransition的overridePendingAppTransition方法(将动画的设置信息都放在AppTransition中了) | ||
|
||
然后WindowManagerService在进行Activity切换的时候就会根据AppTransition的动画设置来显示切换动画了。 |
1. 执行overridePendingTransition时的调用顺序ActivityManageService->WindowManageService
2. 最终设置的是WindowManagerService的overridePendingAppTransition
3. 和Windows编程中显示模式窗口不同,执行startActivity时并没有立即暂停当前Activity,而是通过Handler在下一个MessageQueue的处理中暂停的当前Activity
一、问题
通过adb连接android设备时,出现了如下错误:
error: insufficient permissions for device: user in plugdev group; are your udev rules wrong?
See [http://developer.android.com/tools/device.html] for more information
二、解决办法
首先在插上usb设备和拔下设备时各执行一次lsusb命令,可以看到插上设备比拔掉设备时结果多出一行,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
连接设备时 Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 006: ID 0bda:0129 Realtek Semiconductor Corp. RTS5129 Card Reader Controller Bus 001 Device 005: ID 8087:0a2a Intel Corp. Bus 001 Device 004: ID 1bcf:2b8a Sunplus Innovation Technology Inc. Bus 001 Device 007: ID 2207:0010 Bus 001 Device 002: ID 25a7:fa23 Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub 拔掉时 Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 006: ID 0bda:0129 Realtek Semiconductor Corp. RTS5129 Card Reader Controller Bus 001 Device 005: ID 8087:0a2a Intel Corp. Bus 001 Device 004: ID 1bcf:2b8a Sunplus Innovation Technology Inc. Bus 001 Device 002: ID 25a7:fa23 Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub |
可以看到多了一行
Bus 001 Device 007: ID 2207:0010
然后我们编辑/etc/udev/rules.d/下的51-android.rules文件(如果没有则新建一个此文件),执行命令:
1 |
sudo gedit /etc/udev/rules.d/51-android.rules |
然后在文件中增加一行如下内容:
1 |
SUBSYSTEM=="usb", ATTRS{idVendor}=="2207", ATTRS{idProduct}=="0010",MODE="0666" |
保存文件后,给51-android.rules加上权限
1 |
sudo chmod a+x 51-android.rules |
再重新插上usb线就可以了。
这个精度的损失给本人造成了精神损失! :cry:
整数相除,然后用ceil向上取整,本以为多简单个事,但是搞了半天,整数直接相除得到的结果必定是个整数,即使你把这个结果赋值给一个符点型的变量。
后来才想起来需要强制转换其中一个为符点数然后再相除才可以。看下面的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> using std::vector; int main(void){ int i1 = 3; int i2 = 10; double d1 = i2 / i1; double d2 = (double)i2 / i1; std::cout << "d1: " << d1 << "\nd2: " << d2 << std::endl; return 0; } |
输出结果:
1 2 3 |
bash-3.2$ ./a.out d1: 3 d2: 3.33333 |
这个例子很简单,我就不解释啦!
关键是有什么办法可以避免这个问题再发生?不能只凭记忆吧?!
需要对Android中的sdcard目录进行扫描,获取文件列表,而且要对文件进行排序
本文使用了非递归的方式进行扫描,用一个栈保存需要扫描的文件夹,用while循环所有目录和文件
排序分为在内部排序和整体排序:
根据最后的测试,外部排序速度明显优于内部排序,内部排序的时间约是外部排序的1.3倍。
基于此优化使用排序,如果场景不允许可以先内部排序满足某些条件后再改为外部排序。
下面为文件扫描类的代码FileScanner.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
package bcoder.com.androidfunctiontestapplication.utils; import android.util.Log; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Stack; public class FileScanner { public static final String LOG_TAG = "FileScanner"; public ArrayList<String> mFileList = new ArrayList<>(); private boolean mIsRunning = true; public int scanFiles(String path){ mFileList.clear(); File file = new File(path); Stack<File> folderStack = new Stack<>(); folderStack.push(file); long starttime = System.currentTimeMillis(); while (!folderStack.empty()){ if(!mIsRunning){ break; } file = folderStack.pop(); File[] files = file.listFiles(); // 内部排序 Arrays.sort(files, new Comparator<File>() { @Override public int compare(File o1, File o2) { return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); } }); for(int i = 0; i < files.length; i++){ String fullfilepath = files[i].getAbsolutePath(); if(files[i].isDirectory() && !"./".equals(files[i].getName())){ folderStack.push(files[i]); mFileList.add(fullfilepath); } else { mFileList.add(fullfilepath); } } } long timeuse = System.currentTimeMillis() - starttime; Log.d(LOG_TAG, String.format("TimeUse: %d", timeuse)); Arrays.sort(mFileList.toArray()); // 外部排序 mFileList.sort(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }); Log.d(LOG_TAG, String.format("File count: %d", mFileList.size())); // for(int i = 0; i < mFileList.size(); i++){ // Log.d(LOG_TAG, mFileList.get(i)); // } return mFileList.size(); } public void stopScan(){ mIsRunning = false; } } |
github项目地址:https://github.com/wintergoes/AndroidFunctionTestApplication
本文和上一篇文章类似,只是增大了圆角半径的值,所以左右两边看着像椭圆形状,我们先来看看完成后的效果图:
首先,在res/drawable目录下新建一个shape形状,文件名为round_rect_oval_btn_normal.xml,代表按钮正常情况下的样子,代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <gradient android:startColor="#dcdcdc" android:endColor="#dcdcdc" android:centerColor="#f5f5f5" android:angle="90" android:centerX="0.4" android:centerY="0.4" android:type="linear"></gradient> <stroke android:color="#aaaaaa" android:width="1dp"></stroke> <corners android:radius="50dp"></corners> </shape> |
第二步,为按钮按下状态新建一个文件,在res/drawable目录下新建文件名为round_rect_oval_btn_pressed.xml,文件内容为;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <gradient android:startColor="#cccccc" android:endColor="#cccccc" android:centerColor="#f5f5f5" android:angle="90" android:centerX="0.4" android:centerY="0.4" android:type="linear"></gradient> <stroke android:color="#aaaaaa" android:width="1dp"></stroke> <corners android:radius="50dp"></corners> </shape> |
接下来,把两个样式组合起来,使用selector资源,在res/drawable目录下新建文件round_rect_oval_btn_selector.xml,并输入文件的内容:
1 2 3 4 5 |
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/round_rect_oval_btn_pressed"></item> <item android:drawable="@drawable/round_rect_oval_btn_normal"></item> </selector> |
好了,如果你现在想看一下按钮的效果,可以在activity上放一个TextView或者按钮,并设置它的background为@drawable/round_rect_oval_btn_selector。
当然,为了保持代码的简洁和以后方便扩展,我们还是为这类按钮新建一个样式,在res/values/style.xml中新建一个名为round_rect_oval_btn_bkg的样式,并设置如下:
1 2 3 4 5 |
<style name="round_rect_oval_btn_bkg"> <item name="android:background">@drawable/round_rect_oval_btn_selector</item> <item name="android:layout_marginTop">10dp</item> <item name="android:padding">5dp</item> </style> |
现在再回到acitivy中为你的TextView或者按钮设置style属性为style=”@style/round_rect_oval_btn_bkg”就可以了。
在Activity的finish中调用setResult时一定要注意顺序,setResult要在super.finish之前调用,否则返回的结果不正确!如下:
1 2 3 4 5 6 |
@Override public void finish() { setResult(RESULT_OK, intent); super.finish(); } |
如果不按这个顺序调用,在Activity中的onActivityResult中得到的resultCode是0!Android的坑真TM多啊!