平时我们所讲的
手机屏幕大小是手机的对角线长度,一般单位为英寸,1英寸为2.54厘米。
像素是想象把屏幕放大出现的一个个小圆点或小方块
分辨率是指屏幕上垂直方向和水平方向上的像素个数 :比如iPhone5S的分辨率是1136*640
dpi指的是每英寸的像素数,也叫做屏幕密度,这个值越大,屏幕越清晰。
使用sp作为字体大小单位,会随着系统的字体大小改变
而dp作为单位则不会.
Android的项目依赖有一种远程库依赖
比如app需要依赖下面这个远程库,
dependencies {
compile 'com.etsy.android.grid:library:1.0.5'
}
这样定义了, 去哪里拿到库工程的代码和资源文件呢,肯定是要从某个源去获取。
jcenter是一个声明仓库的源,之前版本则是mavenCentral(), jcenter可以理解成是一个新的中央远程仓库,兼容maven中心仓库,而且性能更优。
so库
.so文件是Linux系统的可执行文件,相当于windows上的exe执行文件,只可以在Linux系统运行。 so文件就是常说的动态链接库,都是C或C++编译出来的。 与Java比较就是:它通常是用的Class文件(字节码) Linux下的.so文件时不能直接运行的。一般来讲,.so文件称为共享库。
- so机制让开发者最大化利用已有的C和C++代码,达到重用的效果,利用软件世界积累了几十年的优秀代码;
- so是二进制,没有解释编译的开消,用so实现的功能比纯java实现的功能要快;
- so内存分配不受Dalivik/ART的单个应用限制,减少OOM;
- 相对于java代码,二进制代码的反编译难度更大,一些核心代码可以考虑放在so中。
jar文件
JAR 文件就是 Java Archive File,顾名思意,它的应用是与 Java 息息相关的,是 Java 的一种文档格式。JAR 文件非常类似 ZIP 文件——准确的说,它就是 ZIP 文件,所以叫它文件包。JAR 文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,包含了一个 META-INF/MANIFEST.MF 文件,这个文件是在生成 JAR 文件的时候自动创建的。
jar包 里面是别人写好的java代码, 里面的类可能实现了你想要的功能, 这样用别人的jar包就不用自己再写一次相同功能的代码了.
总结
jar相当于静态库,so相当于动态库文件。
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
区别
ABI
每一种CPU架构,都定义了一种ABI(Application Binary Interface,应用二进制接口),ABI定义了其所对应的CPU架构能够执行的二进制文件(如.so文件)的格式规范,决定了二进制文件如何与系统进行交互。每一个Android应用所支持的ABI是由其APK提供的.so文件决定的,这些so文件被打包在apk文件的lib/目录下
android:allowBackup
Android API Level 8及其以上Android系统提供了为应用程序数据的备份和恢复功能,此功能的开关决定于该应用程序中AndroidManifest.xml文件中的allowBackup属性值[1] ,其属性值默认是true。当allowBackup标志为true时,用户即可通过adb backup和adb restore来进行对应用数据的备份和恢复,这可能会带来一定的安全风险。
由于Application类是在APP启动的时候就启动,启动在所有Activity之前,所以可以使用它做资源的初始化操作,如图片资源初始化,WebView的预加载,推送服务的注册等等,注意不要执行耗时操作,会拖慢APP启动速度。
在非UI线程中其实可以更新UI,前提是要有自己的ViewRoot,而ViewRoot是在onResume()方法里的addView()创建的,所以在onResume()中判断是否为UI线程,在onCreate()中可以通过子线程来刷新UI的(试验:如果子线程sleep(2000),就会报在非UI线程中刷新UI的错误了 )。
Android App之间共享SharedPreference
在AndroidManifest.xml中的manifest标签,我们需要设置两个APP的sharedUserId,如下:
<manifest xmlns:
android="http://schemas.android.com/apk/res/android"
package="com.example.xiechen.sourceapp"
android:sharedUserId="xxcc.com">
Activity生命周期:
1、当第一次调用一个Activity就会执行onCreate方法
2、当Activity处于可见状态的时候就会调用onStart方法
3、当Activity可以得到用户焦点的时候就会调用onResume方法
4、当Activity被遮挡住的时候就会调用onPause方法
5、当Activity处于不可见状态的时候就会调用onStop方法
6、当Activity没有被销毁的时候重新调用这个Activity就会调用onRestart方法
7、当Activity被销毁时会调用onDestory方法
onSaveInstanceState方法在onPause方法之后执行在onStop方法之前执行。
屏幕旋转的生命周期:
在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState()一定会被执行,且也一定会执行onRestoreInstanceState()。
在AndroidManifest.xml设置
-
android:screenOrientation="landscape"横屏设置;
-
android:screenOrientation="portrait"竖屏设置;
Activity启动方式:
(在AndroidManifest.xml中修改launchMode属性)
standard(默认):每一次都会创造一个新的Activity实例到返回栈中
singleTop:如果发现返回栈的栈顶已经是该活动,不会再创建新的活动实例。
singleTask:如果返回栈中存在该实例,可以直接使用,并把这个活动之上的所有活动统统出栈。
singleInstance:为该实例创建一个单独的返回栈来管理该实例
Activity与Fragment之间传值:
1.在Activity中创建一个Bundle,将要传的值存入,然后通过fragment的setArguments(bundle)传到fragment,在fragment中用getArguments方法接收。
例:Activity中:
Bundle bundle=new Bundle()
bundle.putString("dad","kkk");//kkk就是要传的值
fragment.setArguments(bundle);
Fragment中:
Bundle bundle=getArguments();
String s=bundle.getString("dad");
2.在Activity中定义一个public的方法,将要传递的值以return返回,在fragment的onAttach()中调用这个方法得到值
例:Activity代码:
public String rr(){
return "lll";
}
Fragment代码:
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.i("fragment_111111111","onAttach");
s=((MainActivity)context).rr();//s为全局变量
}
ANP : Application Not Responsing
不同组件发生ANP的时间不一样,主线程Activity/Service是5秒,broadcast是10秒
解决方案:将所有耗时操作(访问网络,Socket通信,查询大量SQL语句,复杂逻辑计算等)都放到子线程中去,然后通过handler.sendMessage, runonUIThread, AsyncTask等方式更新UI,无论如何要保证用户界面操作的流畅度,如果耗时操作需要让用户等待,那么可以在界面上显示进度条。
RecyclerView:
- notifyItemChanged(int position) 更新列表position位置上的数据可以调用
- notifyItemInserted(int position) 列表position位置添加一条数据时可以调用,伴有动画效果
- notifyItemRemoved(int position) 列表position位置移除一条数据时调用,伴有动画效果
- notifyItemMoved(int fromPosition, int toPosition) 列表fromPosition位置的数据移到toPosition位置时调用,伴有动画效果
- notifyItemRangeChanged(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项进行数据刷新
- notifyItemRangeInserted(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项批量添加数据时调用,伴有动画效果
- notifyItemRangeRemoved(int positionStart, int itemCount) 列表从positionStart位置到itemCount数量的列表项批量删除数据时调用,伴有动画效果
View绘制:
1.MeasureSpec是由父View的MeasureSpec和子View的LayoutParams通过简单的计算得出一个针对子View的测量要求,这个测量要求就是MeasureSpec。
一个MeasureSpec是一个大小跟模式的组合值,MeasureSpec中的值是一个整型(32位)将size和mode打包成一个Int型,其中高两位是mode,后面30位存的是size,是为了减少对象的分配开支。MeasureSpec 类似于下图,只不过这边用的是十进制的数,而MeasureSpec 是二进制存储的。
UPSPECIFIED : 父容器对于子容器没有任何限制,子容器想要多大就多大。
EXACTLY: 父容器已经为子容器设置了尺寸,子容器应当服从这些边界,不论子容器想要多大的空间。-1
AT_MOST:子容器可以是声明大小内的任意大小。 -2
view.measure(int widthMeasureSpec, int heightMeasureSpec) 的两个MeasureSpec是父类传递过来的,但并不是完全是父View的要求,而是父View的MeasureSpec和子View自己的LayoutParams共同决定的,而子View的LayoutParams其实就是我们在xml写的时候设置的layout_width和layout_height 转化而来的。
父View的measure的过程会先测量子View,等子View测量结果出来后,再来测量自己。
2.View的测量过程主要是在onMeasure()方法
3.View的Root是DecorView
每个Activity 均会创建一个 PhoneWindow对象,是Activity和整个View系统交互的接口,每个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,对于Activity来说,ViewRootImpl是连接WindowManager和DecorView的纽带,绘制的入口是由ViewRootImpl的performTraversals方法来发起Measure,Layout,Draw等流程的。
DecorView 测量ViewRoot 的时候把自己的widthMeasureSpec和heightMeasureSpec传进去了,接下来你就要去看measureChildWithMargins的源码了
ViewRoot 是系统的View,它的LayoutParams默认都是match_parent
Bitmap.compress方法确实可以压缩图片,但压缩的是存储大小,即你放到disk上的大小
我尝试过把品质设置为10,decode出来的Bitmap大小没变,但显示照片的质量非常差
BitmapFactory.decodeByteArray方法对压缩后的byte[]解码后,得到的Bitmap大小依然和未压缩过一样
如果你想要显示的Bitmap占用的内存少一点,还是需要去设置加载的像素长度和宽度(变成缩略图)
OOM(内存泄漏):
原因:
1.资源对象没关闭造成内存泄漏
1-1,Cursor :调用SQLiteDatabase的query()会返回一个Cursor对象,查询到的所有数据都将从这个对象中取出。调用它的moveToFirst()方法将数据的指针移动到第一行的位置,然后进入了一个循环当中,去遍历查询到的每一行数据。通过cursor的getColumnIndex()方法获取到某一列在表中对应的位置索引。例:String name=cursor.getString(cursor.getColumnIndex("name"));
1-2,调用registerReceiver后未调用unregisterReceiver()
广播:例:定义内部类继承BroadcastReceiver,重写onReceiver()方法,在Activity类中onCreate()方法中调用registerReceiver(内部类实例,IntentFilter),在onDestory()方法中调用unregisterReceiver()
1-3,未关闭InputStream/OutputStream
1-4,Bitmap使用后未调用recycle()
EventBus的使用与BroadcastReceiver、EventBus优缺点分析:
广播是重量级的,消耗资源较多的方式。他的优势体现在与sdk连接紧密,如果需要同 android 交互的时候,广播的便捷性会抵消掉它过多的资源消耗,但是如果不同android交互,或者说,只做很少的交互,使用广播是一种浪费;
在与Android系统交互,比如,网络的变化、电量的变化,短信发送和接收的状态使用Broadcast较为适宜
EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息.优点是开销小,代码更优雅。以及将发送者和接收者解耦。
EventBus使用:
添加依赖:compile 'org.greenrobot:eventbus:3.0.0'
1.新建一个消息的类或者也可不写,用String对象等
- public class FirstEvent {
- private String mMsg;
- public FirstEvent(String msg) {
- // TODO Auto-generated constructor stub
- mMsg = msg;
- }
- public String getMsg(){
- return mMsg;
- }
- }
2.在要接收消息的页面注册EventBus:比如
在Activity的onCreate()方法中
EventBus.getDefault().register(this),
在onDestroy()方法中
EventBus.getDefault().unregister(this);
3.接收消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(FirstEvent s) {
//类名+方法/事件名
}
4.发送消息
- EventBus.getDefault().post(new FirstEvent("FirstEvent btn clicked"));
RecyclerView使用initList()和initData()顺序使用很重要,initList()先布局,那么开始适配器中是没有数据的
Long l=Long.parseLong(String.valueOf(data.get(position).get("createTime")));
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
intent.putExtra("time",simpleDateFormat.format(date));
addHeadView():待完善
有左滑删除效果的reyclerView
//左滑删除
compile 'com.yanzhenjie:recyclerview-swipe:1.0.2'
Intent传递List<Map<String,Object>>
intent.putExtra("maplist", (Serializable) mapList);
dataList = (ArrayList<HashMap<String, Object>>) getIntent().getSerializableExtra("maplist");
非常好用的提示窗口 PromapDialog
compile 'com.github.limxing:Android-PromptDialog:1.1.3'
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
new PromptDialog(SearchActivity.this).showError("请输入搜索关键词");
}
}, 100);
getColumnIndexOrThrow如果没有找到该列名,会抛出IllegalArgumentException异常
倒计时:
cdt=new CountDownTimer(Integer.parseInt(itemlist.get(0).get("secs").toString())*1000,1000) {
@Override
public void onTick(long millisUntilFinished) {
long day=millisUntilFinished/(24*60*60*1000);
long hour=(millisUntilFinished-day*24*60*60*1000)/(60*60*1000);
long minute=(millisUntilFinished-day*24*60*60*1000-hour*60*60*1000)/(60*1000);
long second=(millisUntilFinished-day*24*60*60*1000-hour*60*60*1000-minute*60*1000)/1000;
if (second>=60){
second=second % 60;
minute+=second/60;
}
if (minute>=60){
minute=minute%60;
hour+=minute/60;
}
if (hour>=24){
hour=hour%24;
day+=hour/24;
}
String Sday="";
String Shour="";
String Sminute="";
String Ssecond="";
if (day<10){
Sday="0"+String.valueOf(day);
}else {
Sday=String.valueOf(day);
}
if (hour<10){
Shour="0"+String.valueOf(hour);
}else {
Shour=String.valueOf(hour);
}
if (minute<10){
Sminute="0"+String.valueOf(minute);
}else {
Sminute=String.valueOf(minute);
}
if (second<10){
Ssecond="0"+String.valueOf(second);
}else {
Ssecond=String.valueOf(second);
}
tv_count_day.setText(Sday);
tv_count_hour.setText(Shour);
tv_count_minute.setText(Sminute);
tv_count_second.setText(Ssecond);
// tv_count_day.setText(millisUntilFinished);
}
@Override
public void onFinish() {
}
}.start();
时间戳转换
Long longtime=Long.parseLong(String.valueOf(data.get(position).get("createTime")));
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date date;
try {
date=sdf.parse(sdf.format(longtime));
tv_time.setText(sdf.format(date));
} catch (ParseException e) {
e.printStackTrace();
}
//排版良好的网页浏览器
compile 'com.just.agentweb:agentweb:2.0.1'
mAgentWeb = AgentWeb.with(this)//传入Activity or Fragment
.setAgentWebParent(ll_full, new LinearLayout.LayoutParams(-1, -1))//传入AgentWeb 的父控件 ,如果父控件为 RelativeLayout , 那么第二参数需要传入 RelativeLayout.LayoutParams ,第一个参数和第二个参数应该对应。
.useDefaultIndicator()// 使用默认进度条
.defaultProgressBarColor() // 使用默认进度条颜色
.setReceivedTitleCallback(new ChromeClientCallbackManager.ReceivedTitleCallback() {
@Override
public void onReceivedTitle(WebView view, String title) {
}
}) //设置 Web 页面的 title 回调
.createAgentWeb()//
.ready()
.go(url1);
XTableLayout与ViewPage用FragmentPagerAdapter适配
viewPage.setCurrentItem(1)表示ViewPage里面与XTableLayout的第二项
Banner点击事件
banner.setOnBannerListener(new OnBannerListener() {
@Override
public void OnBannerClick(int position) {
jump2Activity(String.valueOf(mapList.get(position).get("id")),DetailActivity.class);
}
});
PopWindow遮住状态栏
setClippingEnabled(false);
布局中软键盘自动弹回
InputMethodManager imm = (InputMethodManager) getApplication().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(et_talking_content.getWindowToken() , 0);