android:launchMode="singleInstance"/"singleTop"/"singleTask"/"standard"
standard 普通的开启模式:按开启的顺序入栈,出栈
singleTask 整个栈里只能有一个实例 特点: 当再次调用他他会把他上面的activity全部销毁,他到达栈顶。
singleTop 栈里可以有多个实例,但栈顶只能有一个实例
singleInstance 自己开辟一个单独的栈 并且栈里面只有一个实例 整个栈里只有一个activity
如果已经存在了一个栈,并存在相同的实例,那么就不会再继续创建栈了,而是复用这个已经存在的栈和实例。经验证确实是栈里面只有一个activity。
【2】四大组件都不能进行耗时操作,执行耗时操作必须开子线程。
【3】可以为四大组件单独开一个进程
【4】进程的lifecycle
foregound Process 一个activity执行了并处于 onResume状态 broadcastReceiver正在执行
onReceive方法 service正在执行生命周期方法,调用startforeground,绑定的activity正在和用户交互。
visible process
activity执行onpause 处于可见不可操作的状态 如果service单独开启一个process 他绑定的
activity处于onpause状态 该process处于visiable process
service process
应用ui不可见,后台只跑着一个service 后台播放音乐 执行联网下载
background process 后台有activity执行onstop 处于不可见不可操作转态 处于后台进程的应用很多,采用LRU算法决定处于后台进程的那个应用被干掉,最近最少使用最先被杀死
empty process 没有任何组件在运行 下次启动的时候提高启动的时间
【5】activity lifecycle
If an activity is paused or stopped, the system can drop it from memory either by asking it tofinish (calling its finish()
method), or simply killing its
process.
如果一个activity处于onPause或onStop状态 系统回收他两种方式 调用他的finish() 或直接杀掉进程
The visible lifetime of an activity happens between the call toonStart()
and the call toonStop()
.
The foreground lifetime of an activity happens between the call toonResume()
and the call toonPause()
.
onDestoty()
it could be called either because the activity is finishing (someone called finish()
on it), or because the system is temporarily destroying thisinstance of the activity to save space. finish()走的是onDestory().
【6】thread-safe
如果同一时间有多个线程调用同一个对象的方法,就会出现thread-unsafe
【7】UI thread and work thread
应用的进程里 除了 ui thread 其他用于执行耗时操作的线程都是 work thread
【8】activity屏幕方向切换走的生命周期方法
切屏 onDestory() 然后立刻走onCreate()
如何处理重启的问题呢?
方式一:针对数据较少的情况
@override onSavaInstanceSatate() 在他里面做保存工作
切屏走onDetory()之前 系统自动调用 onSavaInstanceState()
重新走onCreate() 在onCreate()或onRestoreInstanceState()里再取出保存的状态
方式二:针对大数据的情况
To retain an object during a runtime configuration change:
- Override the
onRetainNonConfigurationInstance()
method to return the object you would like to retain.重写- When your activity is created again, call
getLastNonConfigurationInstance()
to recover your object.自己手动调用
@override onRetainNonConfigrationInstance() 返回一个object 用于保存状态 不能返回和上下文相关的对象 否则会造成内存泄露
在onStop()和onDestory()之间调用
在onCreate()方法里调用、getLastNonConfigurationInstance() 返回之前保存的对象
handling the configration change by yourself
自己处理屏幕的切换事件,系统就不重启activity了,但系统会发广播,通知你屏幕有变化
重写onConfigrationChanged()处理屏幕的切换事件。
To declare that your activity handles a configuration change, edit the
appropriate <activity>
element in your manifest file to include the
android:configChanges
attribute with a value that represents the configuration you want to handle.
注意:
Note: If your application targets API level 13 or higher (as declared by the
minSdkVersion
andtargetSdkVersion
attributes), then you should also declare the"screenSize"
configuration, because it also changes when a device switches between portrait and landscape orientations.
例如:屏幕虽然切换,但是他走onDestory()和onCreate(),而是维护原来的转态继续运行,
只是当切换屏幕的时候,onConfigrationChanged()会被调用
api level >= 13
orientation|screenSize 必须成对出现
<activity
android:name=".MainActivity" android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
For example, the following manifest code declares an activity that handles both the screen orientation change and keyboard availability change:
api level < 13
<activity android:name=".MyActivity" android:configChanges="orientation|keyboardHidden" android:label="@string/app_name">
不管API level 为啥,都要走onConfigrationChanged().
Now, when one of these configurations change, MyActivity
does not restart.
Instead, theMyActivity
receives a call toonConfigurationChanged()
.
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); // Checks the orientation of the screen if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show(); } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){ Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show(); } }
1.2 startService()和bindService()深入理解
混合开启开启的是同一个service对象,
unbindService(sc);//只是取消service和当前activity的绑定,并没有关闭service stopService(intent);//彻底关闭service下面流程写的非常详细:
- 一个Intent对象最多只能包含一个Action属性,程序可调用Intent的setAction(String str)方法来设置Action属性值
- 一个Intent对象可以包含多个Category属性,程序可调用Intent的addCategory(String str)方法来为Category属性
- 当程序创建Intent时,该Intent默认启动Category属性值为Intent.CATEGORY_DEFAULT常量(常量值为android.intent.category.DEFAULT)的组件
- 对于Service 通过隐式意图开启服务,并不需要category。
不要在广播里添加过多逻辑或者进行任何耗时操作,因为在广播中是不允许开辟线程的,
当onReceiver( )方法运行较长时间(超过10秒)还没有结束的话,那么程序会报错(ANR),
广播更多的时候扮演的是一个打开其他组件的角色,比如启动Service,Notification提示, Activity等!
Android offers a mechanism for interprocess communication (IPC) using remote procedure calls (RPCs), in
android通过rpc来实现ipc
which a method is called by an activity or other application component, but executed remotely (in another
远程的方法被本地activity调用或其他应用的组件调用
process), with any result returned back to the caller. This entails decomposing a method call and its data to a
方法在远程执行 并把执行的结果返回给调用者 这其中涉及到方法是如何调用的,数据是如何传递的
level the operating system can understand,
只有操作系统能够明白
Android provides all the code to perform these IPC transactions, so you can focus on defining and
这其中的代码都有android系统来完成 你的关注点在如何定义接口
implementing the RPC programming interface.
和如何远程调用
To perform IPC, your application must bind to a service, using bindService()
.
为了执行ipc,你的应用必须绑定bindService()
一、谨慎选择包名
案例一
案例二
二、一款应用只应该有一个签名
案例一
案例二
三、使用 xml 配置文件来区分渠道
一般来说,我们在 Android manifest 文件中使用 meta-data 来区分渠道。例如:
1
|
<meta-data android:name=
"CHANNEL"
android:value=
"wandoujia"
/>
|
每次正式打包完成后,修改 android:value,再重新打包即可生成一个新的渠道包,所以:
不要再用签名来区分渠道了!
四、正确填写版本号在 Android 应用中,有两个参数与版本号相关。其中,version Name 表示版本名称,是字符串,version Code 表示版本号,是整型数字。一般来说,用户直观看到的是 version Name,所以这里应该填写形似“4.15.1”这样的版本号。而真正用来判断新版本旧版本的参数是 version Code。在应用发布第一个版本的时候,version Code 应该填 1,然后每次发布的时候都递增,这样才是以规范的格式告诉各大市场你的应用的更新程度。有的开发者在 version Code 上非常随意,这个版本发布的时候碰上结婚纪念日,于是用老婆的生日当 version Code;下个版本发布的时候运气不太好,于是用自己的幸运数字当作 version Code……这样在用户看来的结果就是,明明从官网安装了最新的 2.2.0 版本,可是各大市场却提醒“升级到 2.1.3 版本”,越升级版本号越小了。以上四件小事,虽然都比较琐碎,而且没什么技术含量,但却是很多入门的 Android 开发者容易忽略的问题。希望本文能帮助广大开发者,在写出好应用的同时,避免这些“坑”给应用带来不必要的损失。
<activity android:name=".SecondActivity">
<intent-filter>
<action android:name="com.bilibili.secondActivity"/>
<!--必须指定category-->
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
Thread.currentThread().getName();可以获取任意线程的名称
线程调度 抢占式 getPriority() setPriority(int priority)
线程退出 run()代码执行完毕 手动调用stop()
线程池 jdk5.0 以来使用 Executors 工厂类来产生线程池
ExecutorService 对象表示线程池
线程池 框架
Executors
ExecutorService 线程池
ThreadPoolExecutor
SchedualThreadPoolExecutor
构建线程对象
Runable
Callable
线程池实例(单例)把线程对象提交给线程池submit(thread)/execute(thread) 系统自动执行线程实例
创建线程池对象
创建runnable对象
线程池对象调用submit()或execute()把任务提交到线程池,开始执行线程。
ExecutorService executorService = Executors.newFixedThreadPool(6);
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
executorService.submit(runnable);/executorService.execute(runnable);
9:单位换算8bit = 1byte1024byte = 1 kb1024kb = 1Mb1024Mb = 1G
LogUtil.logi(this.getClass(),File.separator);// "/" LogUtil.logi(this.getClass(),File.pathSeparator);// ":"
如果你的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP,此外OkHttp还处理了代理服务器问题和SSL握手失败问题。
首先介绍下OkHttp的简单使用,主要包含:
- 同步/异步get请求
- 同步/异步post请求
- 基于Http的文件上传
- 文件下载
- 加载图片
- 支持请求回调,直接返回对象、对象集合
- 支持session的保持
http请求方式 : get、post 最常用
其他请求方式 patch、put
其中okHttp除了支持 get/post请求之外还支持其他请求方式
okHttp自带缓存机制,可以对请求的数据进行磁盘缓存 Okhttp已经内置了缓存,默认是不使用的,如果想使用缓存我们需要手动设置
在okHttpClient构造时设置缓存路径
构造Request实例时配置缓存策略
http://blog.youkuaiyun.com/u012702547/article/details/53143322?locationNum=8&fps=1
创建带缓存的okHttp实例 ,构造缓存路径
一般磁盘缓存都是放在和diskLruCache缓存一样的sd卡
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(2000, TimeUnit.MILLISECONDS)
.cache(new Cache(new File(CachePathUtil.externalCacheFile(context)+
File.separator+"net"),
10*1024*1024))//第二个参数表示缓存区的大小为10M,
// 当缓存区的数据大小超过10M的时候会自动删除已缓存的数据
.build();
创建请求Request实例 配合缓存策略get请求
//在request里构建cacheControl
CacheControl cc = new CacheControl.Builder()
// .noCache()//不使用缓存,只走网络
// .noStore()//不使用缓存,但也不保存缓存数据
// .maxAge(5,TimeUnit.SECONDS)//设置最大失效时间,超过这个时间失效,
失效则不用.maxStale(5,TimeUnit.SECONDS)//设置最大失效时间,超过这个时间失效,失效则不用
// .onlyIfCached()//只使用缓存
// .minFresh(5,TimeUnit.SECONDS)//设置最小有效时间,小于5s失效,大于5s有效,失效则不用
.build();
//[01]get请求,请求参数要放在url里
Request request = new Request.Builder()
.addHeader("header1", "value1")
.addHeader("header2", "value2")
.url(url)
.cacheControl(cc)//缓存策略
.tag(NetUtil.class)
.build();
配置缓存策略可以不用单独实例化一个CacheControl对象 可以使用CacheControl的常量来代替创建一个CacheControl实例Request request1 = new Request.Builder()
// .cacheControl(CacheControl.FORCE_CACHE)//强制使用网络
.cacheControl(CacheControl.FORCE_NETWORK)//强制使用缓存
.build();
post请求RequestBody okRequestBody = new FormBody.Builder()
.add("body", getRequestJson(requestParams))
.build();
request = new Request.Builder()
.addHeader("user-agent", "xxxxx")
.addHeader("accept", "yyyy")
.url(url)
.post(okRequestBody)
.build();
同步请求,需要自己开线程
//[1]以同步方式请求网络,需要我们自己开子线
Executors.newSingleThreadExecutor().execute(new Runnable() {
@Override
public void run() {
try {
Response response = okHttpClient.newCall(request).execute();
if (response.isSuccessful()) {
callback.onSuccess(response.body().bytes());
} else {
callback.onFail(response.message());
Toast.makeText(context, "请求失败", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(context, "请求失败", Toast.LENGTH_SHORT).show();
}
}
});
//[2]异步线程请求,okHttp内部开子线程
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Toast.makeText(context, "请求失败", Toast.LENGTH_SHORT).show();
callback.onFail(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
callback.onSuccess(response.body().bytes());
}
});
在构造Request的时候,我们可以配置CacheControl,配置有两种方式,一种是构造CacheControl,还有一种是直接使用CacheControl中的常量,
如果服务器的响应头里没有cache-age字段,我们通过Interceptor拦截响应,并在客户端强行添加一个cache-age字段,并指定值。这时就能达到缓存的目的。
//Retrofit、Picasso等配合OkHttp使用的框架
public static <T> void getDataFromNet(final Context context,
String url,
Map<String, Object> requestParams,
final ReqCallback callback) {
if (okHttpClient == null) {
okHttpClient = new OkHttpClient.Builder()
.connectTimeout(2000, TimeUnit.MILLISECONDS)
.writeTimeout(2,TimeUnit.MINUTES)
.readTimeout(2,TimeUnit.MINUTES)
// .addInterceptor(new MyIntercaptor())//强行修改request和response头
.cache(new Cache(new File(CachePathUtil.externalCacheFile(context) +
File.separator + "net"),
10 * 1024 * 1024))//第二个参数表示缓存区的大小为10M,
// 当缓存区的数据大小超过10M的时候会自动删除已缓存的数据
.build();
}
String requestJson = getRequestJson(requestParams);
// RequestBody requestBody = RequestBody.create(MediaType.parse("json"), requestJson);
//abstract class RequestBody
// FormBody(表单) extends RequestBody
//MultipartBody extends RequestBody
FormBody requestBody = new FormBody.Builder()
.add("data",requestJson)
.build();
// MultipartBody multipartBody = new MultipartBody.Builder()
// .build();
//告诉okHttp缓存的有效期,和响应头的cache-control或者是interceptor的作用是一样的。所以4选一
CacheControl cc = new CacheControl.Builder()
.maxAge(5, TimeUnit.MINUTES)//5分钟之内的有效
.build();
Request request = new Request.Builder()
.url(url)
.tag("tag1")
// .cacheControl(CacheControl.FORCE_NETWORK)
.cacheControl(cc)
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
//响应头里没有cache-control,我们就强行加上;否则,就不需要用Interceptor实例了
private static class MyIntercaptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
return response.newBuilder()
.removeHeader("Pragma")
.removeHeader("Cache-control")
.header("Cache-control","max-age="+3600*24*30)
.build();
}
}
它是用来证明某某东西确实是某某东西的东西(是不是像绕口令?)。通俗地说,证书就好比例子里面的公章。通过公章,可以证明该介绍信确实是对应的公司发出的。
理论上,人人都可以找个证书工具,自己做一个证书。那如何防止坏人自己制作证书出来骗人捏?请看后续 CA 的介绍。
到了1999年,SSL 因为应用广泛,已经成为互联网上的事实标准。IETF 就在那年把 SSL 标准化。标准化之后的名称改为 TLS(是“Transport Layer Security”的缩写),中文叫做“传输层安全协议”。
很多相关的文章都把这两者并列称呼(SSL/TLS),因为这两者可以视作同一个东西的不同阶段。