分类 Android 下的文章

原因是 jcenter 在 2021.05 停止服务了。

修改顶层的 build.gradle

在每个 jcenter() 上面增加一行 mavenCentral()

修改 app 目录下的 build.gradle

implementation 'com.gu.android:toolargetool:0.2.1@aar' 改为 implementation 'com.gu.android:toolargetool:0.3.0@aar'

参考:

http://5.9.10.113/67450126/android-project-build-failing-after-bintray-sunset https://www.5axxw.com/questions/content/hm6zjg

这个一般是旧工程在新 android studio 中打开

"No toolchains found in the NDK toolchains folder for ABI" 需要安装ndk

file -> settings -> android sdk -> sdk tools -> ndk(side by side) 勾选进行安装。 file -> project structure -> sdk location -> android ndk location 里面选择 ndk

"NDK does not contain any platforms” 这个需要安装低版本 ndk

file -> settings -> android sdk -> sdk tools -> ndk(side by side) 勾选 右下角的 show package details,选择低版本,比如说 20.0.5594570 ,安装低版本。

file -> project structure -> sdk location -> android ndk location 选择低版本的 ndk.

参考:

https://blog.csdn.net/qq_24118527/article/details/82867864
https://blog.csdn.net/hiphopxiao/article/details/112220228#:~:text=%E5%9C%A8%20Android%20Studio%E4%B8%AD%E9%85%8D%E7%BD%AE%20NDK%20%E6%97%B6%EF%BC%8C%E5%8F%AF%E8%83%BD%20%E5%87%BA%E7%8E%B0NDK%20does%20not,does%20not%20contain%20any%20platforms%20.%20%E6%89%BE%E4%BA%86%E5%BE%88%E5%A4%9A%E8%B5%84%E6%96%99%EF%BC%8C%E4%B8%8D%E7%9F%A5%E9%81%93%E4%BB%80%E4%B9%88%E5%8E%9F%E5%9B%A0%E3%80%82%20%E5%90%8E%E9%9D%A2%E6%98%AF%E9%80%9A%E8%BF%87%E4%B8%8B%E8%BD%BD%E6%97%A9%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E8%A7%A3%E5%86%B3%E4%BA%86%E8%BF%99%E4%B8%AA%E9%97%AE%E9%A2%98%EF%BC%8C%E8%AE%B0%E5%BD%95%E4%B8%8B%3A

android 生成的 kernel config 在 out/target/product/msm8937_32/obj/KERNEL_OBJ/.config 。要想找出到底哪个 config 决定了最后的 config,我们可以选择 CONFIG_TOUCHSCREEN_FT5X06=y 这一项进行测试。

直接在 kernel 目录下面搜索所有的 CONFIG_TOUCHSCREEN_FT5X06=y, 然后修改CONFIG_TOUCHSCREEN_FT5X06=n,再使用 make kernel,然后查看最终的输出 config,查看变化。

最终确定是 msm-4.9/arch/arm/configs/msm8937_defconfig 决定了 out/target/product/msm8937_32/obj/KERNEL_OBJ/.config

参考: https://blog.csdn.net/u013377887/article/details/81328491

去除标题栏有两种方法:

  1. 直接在 MainActivity 中的 onCreate 里面增加

    ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
  2. AndroidManifest.xml 里面 android:theme 指向的 theme 里面 确保 windowNoTitle = true 并且 android:windowNoTitle = true 就可以无标题。
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">true</item>

参考: https://blog.csdn.net/vtming/article/details/52296090

activity

基本用法

  • AndroidManifest.xml文件中,android:label决定了 app 的名称
  • menu

intent

  • 隐式 intent 注意 category 和 action 的名称都要匹配, category 在 xml 文件中可以是多个。
  • 隐式 intent 还能调用系统提供的功能,比如浏览器 view,拨号 dial 等等
  • intent 通过 putExtra 和 get*Extra 来传递数据
  • startActivityResult 可以获得返回值的打开新 activity

life cycle

  • onCreate onDestory, onStart onStop, onResume onPause, onRestart
  • 暂停状态 一般只有在对话框的情况下出现,对话框处于栈顶,原来的 activity 不处于栈顶,但是仍然可见。所以只会调用 onPause 而不会进入 onStop
  • 为了防止 activity 被回收后数据丢失,所以使用 onSaveInstanceState 来储存临时数据。

start mode

  • standard 每次 startActivity 都会创建一个新的。
  • singleTop 每次非栈顶的情况就会创建新的。
  • singleTask 每次栈里面没有才会创建新的。
  • singleInstance 所有标记为这个的都会被放到一个单独的栈里面,这个单独的栈里面的是可以被多个程序进行调用的。

优化

  • BaseActivity 继承 AppCompatActivity,每次 onCreate 的时候, logd 打印当前是哪个 activity
  • AcitvityCollector 里面使用类静态列表,储存 activity,每次创建和删除都在列表中进行操作,额外再用一个 finishAll 来一次性关闭所有 activity 并清空列表,这样可以避免需要多次后退才能退出的问题。
  • 在被调用的 activity 里面增加 actionStart(Content content, String data1, String data2) 这样的函数,是的调用者可以很容易看出需要传入哪些数据,用来启动 activity.

UI

common

  • android:textAllCaps 这个默认是 true 会让 button 上面的文字默认全部大写。
  • editText 属性 android:hint 用来提示文字,android:maxLines 用来设置最多显示几行,多了就滚动显示。
  • imageView 大小属性都选择 wrap_content 比较好,android:srcsetImageResource 分别是 xml 和 java 中设置图片的方法。
  • 旋转等待图标一般是使用 visiable invisiable gone 这三种来控制显示
  • 水平进度条在 xml 中设置 styleandroid:max,然后在 java 中通过 getProgress setProgress 来控制进度条。
  • AlertDialog 用于警告对话框.ProgressDialog 用于长时间加载对话框,如果 setCancelable 设置为 false,那么 后面需要使用 dimiss() 来关闭对话框。

layout

  • layout_gravity 决定是布局时候的位置,当水平布局时,只能选择 top center_vertical bottom,当垂直布局的时候,只能选择 left center_horizontal end. gravity 决定的时内部文字的位置。
  • 如果使用 layout_weight, 那么相应的 layout_width 或者 layout_height 应该设置为 "0dp"。可以部分空间使用 wrap_content 另外一部分使用 layout_weight 来分空间。
  • RelativeLayout 中可以使用 alignParentTop 这样的布置到父界面的边角处的,也可以用 layout_above layout_toLeftOf 这样的布置到其他空间的相对位置的,也可以用 layout_alignTop 这样的和其他空间边缘对其的。
  • FrameLayout 使用场景很少,一般也就用 layout_gravity = "left" 之类的。
  • 可以通过引入 percent 来扩展 FrameLayoutRelativeLayout

custom

  • 可以把复用的部分写入一个 xml 布局文件里面,比如说标题栏。然后再其他布局里面通过 <include layout="@layout/title" 这样的形式引入这个复用的部分。
  • 原来的标题栏可以通过 getSupportActionBarhide 来进行隐藏.
  • 如果复用的还需要响应用户操作,并且在多个 activity 中响应动作时一样的,那么就需要自定义控件,新建类继承自 LinearLayout,然后重写他的构造函数,主要是 LayoutInflater.from(context).inflate(R.layout.title, this)用来动态加载 title.xml。 修改调用的 xml 代码, <com.example.uicustomviews.TitleLayout ...。 然后在子类里面写上响应的代码即可。

ListView

  • 简单的字符串列表,直接使用 ArrayAdapter android.R.layout.simple_list_item_1 即可。
  • 定制创建新的类,包含 list 中 item 需要的内容。然后需要继承 ArrayAdapter写一个相应的 adapter 类专门处理这个 item。还要创建一个新的 xml 专门描述这个 item 内容。最后就可以把这些合起来,使用自定义的 ListView 了。
  • 优化提升效率,使用 convertView 避免每次都要 LayoutInflater,新建一个类保存 findViewById 返回的内容,然后把这个类使用 setTag 保存到 convertView 中。
  • 点击事件,直接使用 setOnItemClickListener 即可。

RecyclerView

  • build.gradledependencies 里面可以不增加 implementation 'androidx.recyclerview:recyclerview:1.1.0'
  • 如果出现一行占据一个屏幕的现象,那就检查 fruit_item.xml 看看里面的 root 节点下的 layout_height 是不是 match_parent。 奇怪的是,这样的设置在 ListView 中就没有问题。
  • 想要横向滚动,只要修改 xml 文件,并且使用 setOrientation(LinearLayoutManager.HORIZONTAL) 即可。
  • 想要瀑布,只要使用 StaggerredGridLayoutManager 即可。
  • 点击事件,针对需要的使用 setOnClickListener 即可。

参考: https://www.cnblogs.com/rustfisher/p/12254732.html

paractise

  • 在 androidstudio 中,右键 png 图片,选择 create 9-patch file,即可创建9图片,然后在需要拉伸的地方用鼠标在边框上描黑,保存即可。然后删除原来的 png 文件就行了。
  • 使用 RecyclerView 时,有新的数据,可以使用 notifyItemInserted 来通知列表插入新数据,使用 scrollToPosition 来让列表滚动到需要的位置。

fragment

usage

  • fragment 直接使用 xml,然后新建类继承 Fragment 即可。
  • 动态加载,那么 xml 里面需要使用 FrameLayout来预先占据 fragment 的位置。使用 getSupportFragmentManager beginTransaction replace commit 来把 fragment 动态加载到这个 frame layout 里面去。
  • 按后退键能够类似 activity 一样,可以使用 addToBackStack 这个方法。
  • activity 调用 fragment 中的方法,首先使用 getSupportFragmentManager().findFragmentById(R.id.right_fragment 这样的方法获取到 fragment 实例,然后就可以调用方法了。
  • fragment 获取 activity 方法,可以使用 getActivity 来获取到 activity 实例,然后就可以调用方法了。

life

  • activity 进入停止状态,fragment 也会自动停止。或者使用 FragmentTranscation 的 remove, replace 方法移除 fragment。
  • fragment 专门的回调函数,onAttach onDetach 是 fragment 和 activity 建立解除关联时调用。 onCreateView onDestoryView 是创建视图加载布局或者相反时调用。 onActivityCreated 和 fragment 相关联的 activity 一定已经创建完毕时调用。
  • 添加 fragment -> onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume + onPause -> onStop -> onDestoryView -> onDestory -> onDetach -> 销毁。
  • onDestoryView -> onCreateView.
  • 如果使用了 addToBackStack ,那么切换 fragment 的时候,可以让当前的 fragment 只执行 onDestoryView 而不执行 onDestory,使用返回键的时候跳过 onCreate 直接进入 onCreateView
  • onSaveInstanceState 可以用来保存临时数据,防止被系统因为内存问题直接回收了。

trick

  • 可以新建文件夹 layout-large,当系统认为当前设备是 large 的时候,就会调用这个文件夹下面的布局文件,否则调用 layout 文件夹下面的布局文件。 具体可以看 P158
  • 还可以手动指定最小宽度,新建 layout-sw600dp,当屏幕宽度大于等于 600dp 的时候,就会加载这个文件夹下面的布局文件。 具体可以看 P159

practice

  • android:ellipsize 文本超过控件宽度,文本从尾部进行缩略。
  • Configurations for activity_main.xml must agree on the root element's ID. 这个报错是因为在多个 layoutactivity_main.xml 中 root 节点的 android:id 必须一致。

转自: https://blog.csdn.net/qq_28193019/article/details/91050915

生成TAG

logt+Tab键:

private static final String TAG = "Extract";

生成Log.d()

logd+Tab键:

Log.d(TAG, "onCreate: ");

生成Log.e()

loge+Tab键:

Log.e(TAG, "onCreate: ",new Throwable());

生成Log.i/w类似

Log.i(TAG, "onCreate: ");
Log.w(TAG, "onCreate: ", );

logm+Tab:打印参数

Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");

logr+Tab:打印返回值

Log.d(TAG, "onCreate() returned: " + );

查看日志输出

在Android Studio Logcat选项卡,中可以选择过滤的级别,来过滤日志输出,比如Verbose、Debug、Error等,上面的选项(如Debug)会包含下面选项(如Error)的日志

当系统中缺少某个特定版本的 libc 的时候,可以在编译的时候,添加 -nostdlib 选项,并在后面附上指定的库即可。类似于

arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platform/android-19/arch-arm/usr/lib/libc.so

当c文件编译的时候,找不到 log 方面的头文件和库的时候,可以手动添加,类似下面这样

arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ -nostdlib /work/android-5.0.2/prebuilts/ndk/9/platform/android-19/arch-arm/usr/lib/libc.so -I /work/android-5.0.2/prebuilts/ndk/9/platform/android-19/arch-arm/usr/include /work/android-5.0.2/prebuilts/ndk/9/platform/android-19/arch-arm/usr/lib/liblog.so

硬件服务中,xxx_service.cpp, hal_xxx.c 的关系

com_android_server_LedService.cpp 这样的文件是 jni 源码,主要做的是向系统注册的事情。hal_led.c 这样的是实际的对硬件进行操作的源码,比如说 read, write, ioctrl 等等。 之所以分开来主要考虑两个原因。

  • com_android_server_LedService.cpp 这样的文件如果有变更,那么需要系统重新编译。hal_led.c这样的正常时编译为 so 库,所以可以不用系统重新编译。
  • 有些厂商为了保密的需要,不提供 hal_led.c 这样的源码,只是提供一个 so 的库文件。
  • onload.cpp 调用 com_android_server_LedService.cpp 中实现的函数
  • SystemServer.java 需要 new LedService 然后再 addService
  • LedService.java 里面调用 native 方法
  • ILedService.java 给 app 来使用。

ILedService.java

  1. 仿照其他的 aidl 文件,比如说 vibr 的 aidl 文件,复制为ILedService.aidl,然后修改一下接口。
  2. 查看 vibr aidl 文件所在的目录,放到类似的目录
  3. 从当前目录开始查看有没有 Android.mk,如果没有,就向上一层继续查找,知道找到为止。
  4. Android.mk 中仿照 vibr aidl,把ILedService.aidl加入进去。
  5. 使用 mmm . 进行编译。
  6. 到 out 目录下找找有没有 ILedService.java 生成
  7. 可以估计 app 中对 led 的用法是
    ILedService iLedService;
    iLedService = ILedService.stub.asInterface(ServiceManager.getService("led"));
    iLedService.ledCtrl(0, 1);

参考 VibratorService.java 来写 LedService.java.

  1. LedService 继承了 ILedService.Stub, 到 ILedService.javaStub 申明实现的接口 android.os.ILedService , android.os.ILedService 这个里面自动生成的需要实现的只有 ledCtrl 这个函数。
  2. LedService.java 中实现 ledCtrl,这个函数中直接调用 native 方法即可。别忘了申明 native 方法
  3. LedService.java 中的构造函数中也需要调用 open 的 native 方法。别忘了申明 native 方法
  4. SystemServer.java 中,找到 vibr 使用 ServiceManager.addService 的地方,仿照写个 led 的添加服务的调用。

com_android_server_LedService.cpp

参考 com_android_server_VibratorService.cpp 来写。

Onload.cpp

找到 register_android_server_VibratorService(env) 这个注册的地方,复制一份,改为 register_android_server_LedService(env). 别忘了添加这个函数相应的申明。

保存 mmm 编译时的指令

mmm frameworks/base show commands >log.txt 2>&1

在 app 中直接 import android.os.ILedService 会找不到

  1. 可以参考: https://stackoverflow.com/questions/7888191/how-do-i-build-the-android-sdk-with-hidden-and-internal-apis-available ,把 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar 这个复制出来,并改个名字。
  2. 可以参考 https://stackoverflow.com/questions/16608135/android-studio-add-jar-as-library 中的在 android studio 中添加 jar 文件。

led_hal.c

参考 hardware/libhardware/modules/vibrator/vibrator.chardware.h 来写 led_hal.c

编译

上面这些修改好了之后,可以使用命令进行编译。

mmm frameworks/base/services
mmm hardware/libhardware/modules/led
make snod

logcat

logcat 在命令行中可以使用类似 logcat LedHal:I *:S 这样的方法来进行过滤。