Android 实习笔记

⚠️ 杂乱无章链接且极大可能打不开

版本控制

Git 是流行的代码版本控制系统,Gerrit是代码审核系统,实现Web界面上的代码版本控制。

git checkout 撤销修改,让工作区文件回到最近一次 git commit 或 git add 时的状态

JAVA多线程访问同一个可变变量,需增加同步机制

JVM中存在一个主内存(Java Heap Memory),Java 中所有变量都储存在主内存中,对于所有线程都是共享的。

每个线程都有自己的工作内存 (Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行

线程之间无法相互直接访问,变量传递均需要通过主内存完成。

根据上述内存模型的定义,要在多个线程间安全的同步共享数据就必须使用锁机制,将某线程中更新的数据从其工作内存中刷新至主内存,并确保其他线程从主内存获取此数据更新后的值再使用

使用 System.arraycopy() 进行数组复制

在将一个数组对象复制成另外一个数组对象时,不要自己使用循环复制,可以使用JAVA提供的System.arraycopy() 功能来复制数据对象,避免出错,效率更高

.aar库文件和.jar库文件的区别

aar 文件是建立在 jar 文件的基础之上, aar 是 jar 文件的一个变种。本质上没有什么区别,都是压缩包,只是能包含的内容不一样

  • jar 只包含了 class 文件与清单文件。虽然也能包含资源文件,但不过是文本资源和图片资源,不能包含 Android 平台下的 drawable 以及各种 xml 文件.
  • aar 包括的东西更多一些,包含所有资源文件、第三方库文件、so 文件、class 以及 res 资源文件全部包含。

Android接口回调机制

接口回调的意思即,注册之后并不立马执行,而在某个时机触发执行 。

回调方法就是一个通过方法指针来调用的方法(接口),如果我将这个方法的指针(地址,引用)通过形参传递到另一个类的某个方法里(setCallBack 注册),那么当这个类调用该方法里面我所传入的指针时,就能调用我这边的方法。

整个过程就是我传入方法 A 的地址,你接收,并在某个时刻回调我这边的 A 方法。由于 Java 没办法操作指针,于是它用接口来实现。

主要步骤如下:

  • 定义接口 Callback ,包含回调方法 callback();
  • B 类提供注册的方法,并设定在某个条件下会回调接口方法;
  • A 类提供接口的实现方法,并注册到 B 类,把方法地址传进去。

这样,在需要的时候,可用 CamCallback 接口成员调用 callback() 方法,完成回调了。

例子:

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
public class BService {

private OnParserCallBack callBack;
//B类中定义接口定义回调方法
public interface OnParserCallBack {
public void OnParserComplete(List<HoursWeatherBean> list,
PMBean pmBean, WeatherBean weatherBean);
}
//注册用于接收A类传递过来数据
public void setCallBack(OnParserCallBack callback) {
this.callBack = callback;
}

public void removeCallback(){
callBack = null;
}

//dosomething()
public void getCityWeather() {
if(callBack!=null){
//这里使用的是A类传递的数据
callBack.OnParserComplete(list, pmBean, weatherBean);

}

}


public class Amain{
private BService mbService;
//注册
mbService.setCallBack(new OnParserCallBack(){
//回调方法
public void OnParserComplete(List<HoursWeatherBean> list, PMBean pmBean,
WeatherBean weatherBean) {
//接收数据后开始用于显示
setHourViews(list);
setPmViews(pmBean);
setWeather(weatherBean);
}
});
mbService.getCityWeather();
}

另外的网页参考:

http://www.apkbus.com/thread-589290-1-1.html

https://www.jianshu.com/p/f05730ab5d05

EditText 不换行

1
android:singleLine="true"

Java 中 int 转 String 的三种方式

  1. a+”“ 这种效率最低
  2. String.valueOf(a)
  3. Integer.toString(a)

牛逼的 material-dialogs

https://github.com/afollestad/material-dialogs

解决支持库版本兼容问题

如果引用的第三方库的支持库版本低于(或者不一致)app build.gradle 中的支持库版本,可能会出现如下问题:

all com.android.support libraries must use the exact same version specification(mixing versions can lead to runtime crashes)

去改第三方库所用的支持库版本比较麻烦,如果用的库很多的话工作量很大。这个时候我们可以考虑强制让所有模块都用相同的支持库版本。

在 app build.gradle 中添加:

1
2
3
4
5
6
7
8
9
10
11
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '26.0.1'
}
}
}
}

TextView滚动设置

只要在布局的 xml 文件中设置 TextView 的属性:

1
2
3
android:maxLines = "AN_INTEGER"

android:scrollbars = "vertical"

然后在代码中用:

1
yourTextView.setMovementMethod(new ScrollingMovementMethod())

它可以自由的滚动了。

Android 文件下载三种基本方式

1.自己封装 URLConnection 连接请求类

这种方式在 Android 刚兴起的时候,很少下载封装框架,就自己封装了。虽然一般的文件都能下载,但这种方式缺点很多,不稳定或者各种各样的问题会出现。

2.Android 自定的下载管理(会在 notification 显示下载的进度,同时可以暂停、重新连接等)

这种方式其实就是交给了 Android 系统的另一个 app 去下载管理。这样的好处不会消耗该APP 的 CPU 资源。缺点是:控制起来很不灵活。

https://www.jianshu.com/p/46fd1c253701

https://www.cnblogs.com/gooder2-android/p/8966045.html

3.使用第三方 okhttp 网络请求框架

okhttp 是一个很有名气的开源框架,目前已经很多大公司都直接使用它作为网络请求库(七牛云 SDK, 阿里云 SDK)。 且里面集成了很多优势,包括 okio (一个 I/O 框架,优化内存与 CPU)。

综合来看,第三种方案是最佳的,是目前最流行的下载方案。

第三方框架还研究了封装 okhttp 的OKgo

Aria

Android 6.0 以上文件读写权限

除了在清单文件中声明权限,还需要在访问文件时动态申请权限

1、AndroidManifest.xml 文件添加:
1
2
3
4
    </application>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
2、onCreate() 或其他访问文件位置添加授权
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void checkPermission() {
//检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//用户已经拒绝过一次,再次弹出权限申请对话框需要给用户一个解释
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission
.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "请开通相关权限,否则无法正常使用本应用!", Toast.LENGTH_SHORT).show();
}
//申请权限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE);

} else {
Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
Log.e(TAG_SERVICE, "checkPermission: 已经授权!");
}
}

没有第二步的话需要自己去手机的应用程序设置手动允许权限。

Android 7.0 FileProvider 问题

https://blog.csdn.net/growing_tree/article/details/71190741

lambda 表达式

Java的新特性,目的是使得代码更加简洁,只有一个待实现方法的接口,都可以使用 Lambda表达式的写法,例如

1
2
3
4
5
6
// λ
return (new Runnable(){
  @Override
  public void run(){
  }
});

转成 Lanbda 表达式就是

1
return ()->{};

如需为您的项目启用 Java 8 语言功能和 Jack,请在模块层级的 build.gradle 文件中输入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
android {
...
defaultConfig {
...
jackOptions {
enabled true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

Jsoup 安卓端的爬虫

加库后用三行代码,即可获得应用名到应用包名的转换。感谢酷安

1
2
3
Document doc = Jsoup.connect("https://www.coolapk.com/search?q="+pack_name).get();
Elements res =doc.select("#game_left > div > a:nth-child(2)");
String ss = res.attr("href").substring(5);

解决网络请求多线程的骚操作

问题是:如何让主线程等待子线程获得网络数据后再继续运行?

设网络数据为全局变量 x,再设一个全局 flag 变量。设全局变量是为了让变量可访问,但不知会否引起安全和效率问题。

主线程设置 flag 变量的死循环,子线程执行网络请求,成功修改 x 完毕再修改 flag 变量,使得主线程离开死循环继续执行。这时,主线程就能使用到存储了网络数据的 x 变量。(机智)

https://bbs.csdn.net/topics/391838191

AsyncTask 优点缺点

优点:简单快捷

缺点:后台真正只有一个线程,多线程是串行执行的

https://blog.csdn.net/evan123mg/article/details/52960339

Handler学习

https://blog.csdn.net/u010177022/article/details/63278070

https://blog.csdn.net/songmingzhan/article/details/78408383

https://www.cnblogs.com/ryanleee/p/8204450.html

https://www.cnblogs.com/android007/archive/2012/05/10/2494766.html

避免内存泄漏

https://www.cnblogs.com/JohnTsai/p/5259869.html

主线程给子线程传参数

https://blog.csdn.net/choubaoguai/article/details/23671441

  1. 构造函数传递数据

    定义一个线程类,扩展 Thread,增加一个成员变量,用来保存传进来的参数。新加一个拷贝构造函数,拷贝写入到成员变量。

  2. 变量和方法传递数据

  3. 回调函数

ADB 快捷从电脑安装apk到手机

打开 cmd,输入指令,路径可以直接从资源管理器拖过去

1
adb install -r 路径

注解:编译时注解和运行时注解

http://www.mamicode.com/info-detail-1317919.html

http://www.importnew.com/1796.html

动态权限申请

https://github.com/mylhyl/AndroidAcp

Android 存储路径

补充:对于现在市面上很多 Android 设备,自带了一个大的存储空间,一般是 8GB 或 16GB,并且又支持了 sdCard 扩展,对于这样的设备,使用 Enviroment.getExternalStorageDirectory() 方法只能获取到设备自带的存储空间,对于另外扩展的 sdCard 而言,需要修改路径。

保存到应用的内部文件夹——在 “Android/Data/应用包名/…”路径下,卸载应用时也会一并清除

通过 getExternalFilesDir() 方法可以获取到 SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据

通过 getExternalCacheDir() 方法可以获取到 SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据

应用外部的话,可以用 Environment.getExternalStorageDirectory() 来索取到默认内置存储的根路径,即 “/storage/emulated/0”,这种情况下卸载应用时不会清除哦

Handler 理解源码分析

https://blog.csdn.net/lishuangling21/article/details/70767586

获取 Android 手机里所有已安装的APP

https://blog.csdn.net/lishuangling21/article/details/50789715

Eclipse copy 风格的快捷键

ctrl+H 找有没有引用

ctrl+shift+R 进入文件的资源管理器路径

项目恢复

资源管理器中右键模块→ GIT → Revert →找到相应的模块项目恢复即可

工程资源清理

https://blog.csdn.net/caoxiao90/article/details/51057986

打开 AS,点击工具栏的 Analyze-Run Inspection by Name-输入 unused resources-选择要搜索的范围回车-查看搜索结果并删除无用的资源文件

出来运行结果后,展开到最小条目后,双击打开文件,再在资源管理器右上方点击多重圆圈按钮 “Scroll from source”,定位到具体文件夹,注意最好要在 Android 视图方式打开,可以合并同类资源到同一个文件夹下面,然后直接删除文件夹可以一次性删除多个。删除时要选中 Safe search,会进行再次检查有没有 usage,最后才确认是否删除

在 Version Control 中可以找到改动,便于检查

确保效果和不出差错,善于利用 ctrl+H 找有没有引用和 ctrl+shift+R 进入文件的资源管理器路径

【Android 珍藏】推荐10个炫酷的开源库

https://juejin.im/post/5b50898ef265da0fa21a7f0f

ButterKnife@BindView 时报 Required view ID was not found 异常

解决思路:在 @BindView 前面加上 @Nullable 或者 @Optional

BottomNavigationView 的相关网页

https://blog.csdn.net/yihuangol/article/details/74370289

https://blog.csdn.net/xiaoyangsavvy/article/details/70213537

Fragment 使用

https://www.jianshu.com/p/fd71d65f0ec6

开发要点

所有变量声明放在最外面,初始化看情况而定,List,arrarylist 这些可以声明时就初始化,直接 new…

Butterknife 和 reclclerview 的综合用法

https://www.aliyun.com/jiaocheng/15082.html

RecyclerView 点击事件接口回调

https://blog.csdn.net/willba/article/details/72878345

https://blog.csdn.net/weikai_/article/details/78936013

https://blog.csdn.net/xieluoxixi/article/details/61924372

https://blog.csdn.net/dl10210950/article/details/52918019

获取 RecyclerView 的 Item 中的 EditText 的内容

1
2
EditText TmpEditText= (EditText)mRecyclerView.getChildAt(position).findViewById(R.id.app_input);
String app_name= TmpEditText.getText().toString();

透明背景文字图片做法

利用ppt,确定文字效果以后再复制,左上角找到选择性粘贴,选中 “PNG图片”,图片粘贴在PPT上面后再另存为图片保存为 PNG 格式,保存到资源文件管理器中

RecyclerView 复用问题,坑大半天的问题

onBindViewHolder 会有多次调用重绘,if-else 条件必须确保完整。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void onBindViewHolder(ViewHolder holder, int position) {

holder.app_icon.setImageDrawable(app_list.get(position).getImage());
holder.app_name.setText(app_list.get(position).getName());
if (app_list.get(position).getIsHasUpdate()==false){
holder.isHasUpdate.setVisibility(View.GONE);
}
//一定必须要加下面的else
else{
holder.isHasUpdate.setVisibility(View.VISIBLE);
}
}

https://blog.csdn.net/csdn_aiyang/article/details/80094302

https://blog.csdn.net/like_program/article/details/52517119

SwipeRefreshLayout 使用

https://www.jianshu.com/p/d23b42b6360b

https://blog.csdn.net/yl104221034/article/details/50582644

ImageButton 背景透明

xml里面设置 android:background=”@null”

坑爹 RecyclerView 获取子 Item 位置问题

getChildAt 函数只能获取屏幕可见的子 Item

https://blog.csdn.net/binbin960211892/article/details/78662388

https://blog.csdn.net/higson/article/details/52819327

跳转应用市场详情界面查看

https://www.jianshu.com/p/a4a806567368

文件搜索

https://blog.csdn.net/qq_21194621/article/details/51627274

https://blog.csdn.net/zzh12138/article/details/71077909

https://blog.csdn.net/sinat_33585352/article/details/80741648

计算 App 占用空间

https://blog.csdn.net/bingqingsuimeng/article/details/51062300

https://blog.csdn.net/m6711154/article/details/52000041

避免代码复用出现问题

setVisibility 为不可见之后要注意判断后面还有没有复用,添加 if 判断重新设置为可见

文件扫描搜索

https://blog.csdn.net/yuzhiqiang_1993/article/details/78140580

通过媒体库提供方式实现文件扫描搜索

https://www.jianshu.com/p/a6bdbefde77a

https://blog.csdn.net/zocki33250/article/details/48112669

https://blog.csdn.net/yaochangliang159/article/details/51878841

RecyclerView 完美实现拖拽,滑动删除,撤销删除

https://blog.csdn.net/hymanme/article/details/50931082

SurfaceView 用处,用法

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1201/656.html

https://blog.csdn.net/ShanYu1198124123/article/details/52448586

SurfaceView 和 TextureView 对比

https://blog.csdn.net/hejjunlin/article/details/58582919

我的思路是用 MediaPlayer 和 TextureView 来结合实现。(VideoView底层用的也是MediaPlayer,至于为什么不用 SurfaceView 而用 TextureView,是因为 SurfaceView不能放在可滑动的控件中,至于具体原因和缺点如果不清楚可自行百度之,TextureView 正是为了解决这个问题而存在的。

在 Android 总播放视频可以直接使用VideoViewVideoView是通过继承自SurfaceView来实现的。SurfaceView的大概原理就是在现有View的位置上创建一个新的Window,内容的显示和渲染都在新的Window中。这使得SurfaceView的绘制和刷新可以在单独的线程中进行,从而大大提高效率。但是呢,由于SurfaceView的内容没有显示在View中而是显示在新建的Window中, 使得SurfaceView的显示不受View的属性控制,不能进行平移,缩放等变换,也不能放在其它RecyclerViewScrollView中,一些View中的特性也无法使用。

Mediaplayer换成Exoplayer的方法

版本号 2.5版本以前为 r2.x.x,2.5版本以后为 2.x.x

了解两种播放器的状态转换和监听接口回调,多打日志观察回调过程。

学习接口的写法,就像这次项目的更换,在有 Mediaplayer 的地方换成 ExoPlayer 的对应方法即可。VideoPlayerController 的代码完全不用改。

新优化集成问题

第一时间想到能否集成,集成开销,对 APK 包大小的影响,老机器版本兼容性,建立表格,拍摄小视频等确认效果对比。

开源项目推荐的网址

https://www.ctolib.com/android/

“==” 和 “equals” 有什么差别?

equals用于判断对象的内容是否相等,==运算符用于比较对象的引用是否一致

Apk 反编译

https://blog.csdn.net/s13383754499/article/details/78914592

https://www.cnblogs.com/spring87/p/4525647.html

依赖源码不起作用?三大重置方法

  • clean project
  • Invalie Cache and restart
  • 关掉instant run

CMD Markdown编辑器

https://www.zybuluo.com/mdeditor

So 文件兼容 CPU 架构

http://xuchongyang.com/2017/03/12/%E6%8E%A2%E5%AF%BB-Android-so-%E5%BA%93/

Binary XML file line # : Error inflating class

https://blog.csdn.net/huangxiaohu_coder/article/details/8497286

https://blog.csdn.net/xiabing082/article/details/43487159

Complie 和 Provided 区别

Provided只是IDE编译时依赖,但是不打包到APK,也就是说编译时通过,但是不保证手机安装APK后是否能运行。

TextView 优化

http://codethink.me/2015/04/23/improving-comment-rendering-on-android/

视频基础知识

https://blog.csdn.net/zhs4430169/article/details/76502217

Android 性能优化

https://www.jianshu.com/p/307ba8911799

DNS 优化

https://my.oschina.net/sudujuncom/blog/874699

修改第三方库

final 类型的不可继承修改

继承要修改的类,右键新类名可以 generate 构造函数。再 @Override 具体修改的函数,记得要 super 父类函数


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!