[toc]
adb
- 权限禁止
su root
- 查看xml文件
cat data.xml
- 权限禁止的情况下进入包目录
run-as com.your.package
webView图片显示不全
webSettings.setJavaScriptEnabled(true); // 设置支持javascript脚本
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
webSettings.setBlockNetworkImage(false);
Pw在7.0或以上显示showAsDropDown有问题
public void showAsDropDown(View anchor) {
if (Build.VERSION.SDK_INT >= 24) {// 只有7.0 的系统有这个问题
int[] location = new int[2];
anchor.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
showAtLocation(anchor, Gravity.NO_GRAVITY, 0, y + anchor.getHeight());
} else {
super.showAsDropDown(anchor);
}
}
ApplicationContext以及ActivityContext区别
Retrofit 备忘录
- 添加拦截器添加公共头
private fun client(): OkHttpClient {
if (TextUtils.isEmpty(url)) {
throw IllegalArgumentException("baseUrl can not be null")
}
val builder = OkHttpClient.Builder()
builder.connectTimeout(connectTimeoutMills, TimeUnit.MILLISECONDS)
builder.readTimeout(readTimeoutMills, TimeUnit.MILLISECONDS)
builder.addInterceptor { chain ->
val request = chain.request()?.newBuilder()?.addHeader("showapi_appid", NetConf.showApiAppId)
?.addHeader("showapi_sign", NetConf.showApiSign)!!.build()
chain.proceed(request)
}
return builder.build()
}
2.添加拦截器添加公共参数
private fun client(): OkHttpClient {
if (TextUtils.isEmpty(url)) {
throw IllegalArgumentException("baseUrl can not be null")
}
val builder = OkHttpClient.Builder()
builder.connectTimeout(connectTimeoutMills, TimeUnit.MILLISECONDS)
builder.readTimeout(readTimeoutMills, TimeUnit.MILLISECONDS)
builder.addInterceptor { chain ->
val httpUrl = chain.request().url().newBuilder().addQueryParameter("showapi_appid", NetConf.showApiAppId)
.addQueryParameter("showapi_sign", NetConf.showApiSign).build()
val request = chain.request().newBuilder().url(httpUrl).build()
chain.proceed(request)
}
return builder.build()
}
知识点备忘录
Activity生命周期
Fragment生命周期
RxJava
部分命名规则
名称 | 缩写 |
---|---|
Button | btn |
CheckBox | cb |
EditText | et |
FrameLayout | fl |
GridView | gv |
ImageButton | ib |
ImageView | iv |
LinearLayout | ll |
ListView | lv |
ProgressBar | pb |
RadioButtion | rb |
RecyclerView | rv |
RelativeLayout | rl |
ScrollView | sv |
SeekBar | sb |
Spinner | spn |
TextView | tv |
ToggleButton | tb |
VideoView | vv |
WebView | wv |
kotlin中还没理解透彻的点:
内部类的作用(好处):
线程问题:
sleep和wait的区别
- Sleep是Thread的方法,wait是Object类的方法
- Thread.sleep不会导致锁行为的改变,如果当前线程是拥有锁的,那么Thread.sleep不会让线程释放锁
- Thread.sleep和Object.wait都会暂停当前的线程,对于CPU资源来说,不管是哪种方式暂停的线程,都表示它暂时不再需要CPU的执行时间,但是wait需要别的线程执行notify/notifyAll才能够重新获得CPU执行时间
线程间的状态转换:
新建(new):新创建了一个线程对象。
可运行(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
- 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
总结:
- sleep方法调用之后,并没有释放锁。使得线程仍然可以同步控制。sleep不会让出系统资源;wait是进入线程等待池中等待,让出系统资源
- 调用wait方法的线程,不会自己唤醒,需要线程调用 notify / notifyAll 方法唤醒等待池中的所有线程,才会进入就绪队列中等待系统分配资源。sleep方法会自动唤醒,如果时间不到,想要唤醒,可以使用interrupt方法强行打断
- Thread.sleep(0) // 触发操作系统立刻重新进行一次CPU竞争。
- sleep可以在任何地方使用。而wait,notify,notifyAll只能在同步控制方法或者同步控制块中使用。
- sleep必须捕获异常,而wait,notify,notifyAll的不需要捕获异常。
数据结构
HashMap和Hashtable的区别?
- 两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全
- HashMap可以使用null作为key,而Hashtable则不允许null作为key
- 两者计算hash的方法不同
- Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模
- HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度取摸
- HashMap和Hashtable的底层实现都是数组+链表结构实现
Hanler Looper Message
Looper主要作用:
- 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
- loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
总结:
- 首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
- Looper.loop()会让当前线程进入一个无限循环,不断从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
- Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue相关联。
- Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
- 在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
Context 以及ApplicationContext 使用场景
大家注意看到有一些NO上添加了一些数字,其实这些从能力上来说是YES,但是为什么说是NO呢?下面一个一个解释:
数字1:启动Activity在这些类中是可以的,但是需要创建一个新的task。一般情况不推荐。
数字2:在这些类中去layout inflate是合法的,但是会使用系统默认的主题样式,如果你自定义了某些样式可能不会被使用。
数字3:在receiver为null时允许,在4.2或以上的版本中,用于获取黏性广播的当前值。(可以无视)
注:ContentProvider、BroadcastReceiver之所以在上述表格中,是因为在其内部方法中都有一个context用于使用。
布局优化
- include
- merge
- viewStub(不可以与merge同时使用,会增加绘制层数,如何取舍看具体业务)
include
- 优点:可以引入重复内容,避免xml重复 复制黏贴
- 缺点:可能会引入额外的布局嵌套
merge
- 优点:是include的辅助补充,可以避免xml布局嵌套
- 缺点:不会引用引入额外的布局嵌套
viewStub
仅在需要时才加载布局
- 优点:仅在需要的时候才会引入布局,可以防止View.GONE导致的性能损耗
- 缺点:比较麻烦(个人觉得)
- 使用方法:
- xml 中使用:
- java代码中使用:
<ViewStub
android:id="@+id/view_stub"
android:layout="@layout/profile_extra"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
if (viewStub != null) {
View inflatedView = viewStub.inflate();
editExtra1 = (EditText) inflatedView.findViewById(R.id.edit_extra1);
editExtra2 = (EditText) inflatedView.findViewById(R.id.edit_extra2);
editExtra3 = (EditText) inflatedView.findViewById(R.id.edit_extra3);
}
Dalvik和ART的区别?
Dalvik与JVM的区别
- Dalvik指令集是基于寄存器的架构,dex字节码更适合于内存和处理器速度有限的系统。
- 而JVM是基于栈的。相对而言,基于寄存器的Dalvik实现虽然牺牲了一些平台无关性,但是它在代码的执行效率上要更胜一筹。
- Dalvik 是Android4.4及以下平台的虚拟机。Art 是在Android4.4以上平台使用的虚拟机。
ART的优点:
- ART 性能高于采用JIT的Dalvik
- 应用启动更快、运行更快、体验更流畅、触感反馈更及时
- 更长的电池续航能力
- 支持更低的硬件
ART的缺点:
- 字节码变为机器码之后,占用的存储空间更大
- 应用的安装时间会变长。
堆内存和栈内存的区别
1、应用程序所有的部分都使用堆内存,然后栈内存通过一个线程运行来使用。
2、不论对象什么时候创建,他都会存储在堆内存中,栈内存包含它的引用。栈内存只包含原始值变量好和堆中对象变量的引用。
3、存储在堆中的对象是全局可以被访问的,然而栈内存不能被其他线程所访问。
4、栈中的内存管理使用LIFO的方式完成,而堆内存的管理要更复杂了,因为它是全局被访问的。堆内存被分为,年轻一代,老一代等等,更多的细节请看,这篇文章
5、栈内存是生命周期很短的,然而堆内存的生命周期从程序的运行开始到运行结束。
6、我们可以使用-Xms和-Xmx JVM选项定义开始的大小和堆内存的最大值,我们可以使用-Xss定义栈的大小
7、当栈内存满的时候,Java抛出java.lang.StackOverFlowError异常而堆内存满的时候抛出java.lang.OutOfMemoryError: Java Heap Space错误
8、和堆内存比,栈内存要小的多,因为明确使用了内存分配规则(LIFO),和堆内存相比栈内存非常快。
HttpClient与HttpUrlConnection的区别
- android 2.3 之前推荐用HttpClient,因为HttpUrlConnection存在较多的、莫名其妙的bug
- android 2.3 以后推荐用HttpUrlConnection,因为更方便,更快捷。
比如Volley
讲解
http与https的区别:
- HTTP 的 URL 以 http:// 开头,而 HTTPS 的 URL 以 https:// 开头
- HTTP 是不安全的,而 HTTPS 是安全的
- HTTP 标准端口是 80 ,而 HTTPS 的标准端口是 443
- 在 OSI 网络模型中,HTTP 工作于应用层,而 HTTPS 工作在传输层
- HTTP 无需加密,而 HTTPS 对传输的数据进行加密
- HTTP 无需证书,而 HTTPS 需要认证证书
讲解
Activity的启动过程:
单例模式
日常bug
-
ViewPager 配合PhotoView 在快递缩放的情况下会报错
这个时候需要自定义ViewPager
/**
* @author Ly
* @date 2017/12/11
*/
public class PhotoViewPager extends ViewPager {
public PhotoViewPager(Context context) {
super(context);
}
public PhotoViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (Exception e) {
// ignore it
}
return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
try {
return super.onTouchEvent(ev);
} catch (IllegalArgumentException ex) {
// ignore it
}
return false;
}
}
- ViewPager 图片刷新,适配器用的是FragmentStatePagerAdapter,其实应该用FragmentPagerAdapter性能更好。
/**
* @author Ly
* @date 2017/12/26
*/
public class BigImageAdapter extends FragmentStatePagerAdapter {
private ArrayList<Fragment> mFragmentList;
public BigImageAdapter(FragmentManager fm, List<String> types) {
super(fm);
updateData(types);
}
public void updateData(List<String> dataList) {
ArrayList<Fragment> fragments = new ArrayList<>();
for (int i = 0, size = dataList.size(); i < size; i++) {
fragments.add(BigImageFragment.newInstance(dataList.get(i)));
}
setFragmentList(fragments);
}
private void setFragmentList(ArrayList<Fragment> fragmentList) {
if (this.mFragmentList != null) {
mFragmentList.clear();
}
this.mFragmentList = fragmentList;
notifyDataSetChanged();
}
@Override
public int getCount() {
return this.mFragmentList.size();
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
}
- EditText 字符输入限制
例如我的游戏区服 只能输入0-300,那么就是:
mEtRepurchaseServed.setFilters(new InputFilter[]{new MaxNumFilter(0, 300, 2)});
/**
* @author Ly
* 最大输入字符限制
* <p>
* <p>
* eg:
* mEtRepurchaseServed.setFilters(new InputFilter[]{new MaxNumFilter(0, 300, 2)});
* mEtRepurchaseLevel.setFilters(new InputFilter[]{new MaxNumFilter(0, 65535, 2)});
* @date 2017/12/25
*/
public class MaxNumFilter implements InputFilter {
private final Pattern pattern;
private final double maxNum;
public MaxNumFilter(int min, double maxNum, int numOfDecimals) {
pattern = Pattern.compile("^" + (min < 0 ? "-?" : "")
+ "[0-9]*\\.?[0-9]" + (numOfDecimals > 0 ? ("{0," + numOfDecimals + "}$") : "*"));
this.maxNum = maxNum;
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (source.equals(".")) {
if (dstart == 0 || !(dest.charAt(dstart - 1) >= '0' && dest.charAt(dstart - 1) <= '9') || dest.charAt(0) == '0') {
return "";
}
}
if (source.equals("0") && (dest.toString()).contains(".") && dstart == 0) {
return "";
}
StringBuilder builder = new StringBuilder(dest);
builder.delete(dstart, dend);
builder.insert(dstart, source);
if (!pattern.matcher(builder.toString()).matches()) {
return "";
}
if (!TextUtils.isEmpty(builder)) {
double num = Double.parseDouble(builder.toString());
if (num > maxNum) {
return "";
}
}
return source;
}
}
- RecyclerView 嵌套RecyclerView 出现滑动冲突
场景:
RecyclerView嵌套了RecyclerView,当手指滑动子RecyclerView的时候,滑动焦点处于子RecyclerView,父RecyclerView滑动不了。
这个时候,我们父RecyclerView不用做处理,子RecyclerView做如下处理:
val discountList = arrayListOf<DiscountBean>()
for (i in 0..1) {
discountList.add(DiscountBean(i, i.toString(), i.toString()))
}
val discountAdapter = DiscountAdapter(discountList, context)
mRlvProductDiscount?.layoutManager = LinearLayoutManager(context)
mRlvProductDiscount?.adapter = discountAdapter
mRlvProductDiscount?.isNestedScrollingEnabled=false
主要是这句:
mRlvProductDiscount?.isNestedScrollingEnabled=false
禁止了该mRlvProductDiscount的滑动事件
redis 启动失败:
window下安装redis报错:
creating server tcp listening socket 127.0.0.1:6379: bind No error
的解决方案如下按顺序输入如下命令就可以连接成功
1. redis-cli.exe
2. shutdown
3. exit
4. redis-server.exe redis.windows.conf