Android 知识点小结

来源:互联网 发布:随州广电网络 编辑:程序博客网 时间:2024/05/16 17:11


Android专用驱动
Logger 
完全内存操作
适合频繁读写


Binder 
Client/Server模型
进程间一次数据拷贝
进程内直接调用




Ashmem 
使用文件描述符描述
通过Binder在进程间传递




Activity生命周期
由ActivityManagerService管理




Activity堆栈
由ActivityManagerService维护






Activity在堆栈中以Task的形式聚集在一起
Task由一系列相关的Activity组成,
描述用户完成某一个操作所需要的Activity
当我们从Launcher上点击一个应用图标的时候,
就启动一个Task
Task是用Android多任务的一种体现






对于有序广播,按照优先级从高到底的顺序转发,但是对于优先级相等的广播,动态注册的Broadcast Receiver优先于静态注册的Broadcast Receiver










Content Provider
通过URI来描述
数据访问接口
数据更新机制


Content Provider数据访问接口
Insert
Update
Delete
Query
Call -- Hidden




Content Provider数据更新机制
注册内容观察者 -- ContentResolver.ContentObserver
发送数据更新通知 -- ContentResolver.notifyChange








窗口管理框架
Window   
WindowManagerService
   SurfaceFlinger


资源管理框架
AssetManager  
Resources




jvm基于堆栈,android基于寄存器 dex one file many classes


.java---------javac----->.class-------------dx---------->.odex------->dexopt------Dex文件编译和优化




Dalvik虚拟机内存管理




Java Object Heap
大小受限,16M/24M/32M/48M


Bitmap Memory(External Memroy):
大小计入Java Object Heap


Native Heap
大小不受限










在HoneyComb以及更高的版本中,Bitmap Memory就直接是在Java Object Heap中分配了,这样就可以直接接受GC的管理。


垃圾收集(GC)
Mark,使用RootSet标记对象引用
Sweep,回收没有被引用的对象


GingerBread之前
Stop-the-word,也就是垃圾收集线程在执行的时候,其它的线程都停止
?Full heap collection,也就是一次收集完全部的垃圾
一次垃圾收集造成的程序中止时间通常都大于100ms










GingerBread之后
Cocurrent,也就是大多数情况下,垃圾收集线程与其它线程是并发执行的
?Partial collection,也就是一次可能只收集一部分垃圾
一次垃圾收集造成的程序中止时间通常都小于5ms




Dalvik虚拟机在运行过程中要维护一些状态信息,这些信息包括:每个线程所保存的寄存器,Java类中的静态字段,局部和全局的JNI引用,JVM中的所有函数调用会对应一个相应C的栈帧。
每一个栈帧里可能包含对对象的引用,比如包含对象引用的局部变量和参数。所有这些引用信息被加入到一个集合中,叫根集合。然后从根集合开始,递归的查找可以从根集合出发访问的对象。












Android应用程序有两种类型的线程
带有消息队列,用来执行循环性任务
有消息时就处理
没有消息时就睡眠
例子:主线程、android.os.HandlerThread
没有消息队列,用来执行一次性任务
任务一旦执行完成便退出
例子:java.lang.Thread


带有消息队列的线程四要素
Message(消息)
MessageQueue(消息队列)
Looper(消息循环)
Handler(消息发送和处理)






android.os.AyncTask


在进程内维护一个线程池来执行任务
任务在开始执行、执行过程以及结束执行时均可以与主线程进行交互
任务是通过一个Handler向主线程发送消息以达到交互的目的






back键 ondestroy
onpause保存持久化的数据
onSaveInstanceState方法(内存不足或按home键调用,back不会调用,不是生命周期方法)临时 onRestoryInstance考虑这几activity种情况:
1、Home
2、电源键
3】一个acyivity启动另外一个acyivity
、屏幕方向切换(不是用户)显示销毁的都都调用


activity  onstart---->onstop  onpause----->onresume






service生命周期
1、onCreate--》onstartcomand(多次调用)----》ondestroy


2、oncreate----》onbind(一次)----》unonbind----ondestrory
IntentService生命周期:
onCreate()------->onStartCommand()--------->onHandleIntent()--------->onDestroy()




















程序由组件组成 
组件与进程剥离  
组件皆程序入口




程序由组件组成
Activity:前台交互
Service:后台计算
Broadcast Receiver:广播通信
Content Provider:数据封装






组件与进程剥离  
组件关闭时,进程可以继续存在
提高重新启动时的速度
  进程关闭时,组件可以继续存在
保护被杀进程里面的组件




组件皆程序入口
Activity -- onCreate
   Service -- onCreate
   Broadcast Receiver -- onReceive
   Content Provider -- onCreate




由于组件已与进程剥离,因此不再有进程入口的概念,只有组件入口的概念






操作系统级别的组件化支持
Activity Manager Service
     Binder    
Low Memory Killer






Activity Manager Service


启动组件
组件启动时,检查其所要运行在的进程是否已创建。如果已经创建,就直接通知它加载组件。否则,先将该进程创建起来,再通知它加载组件。


关闭组件
组件关闭时,其所运行在的进程无需关闭,这样就可以让组件重新打开时得到快速启动。


维护组件状态
维护组件在运行过程的状态,这样组件就可以在其所运行在的进程被回收的情况下仍然继续生存。


进程管理
在适当的时候主动回收空进程和后台进程,以及通知进程自己进行内存回收






Binder
为组件间通信提供支持
 进程间 
进程内
  高效的IPC机制
进程间的组件通信时,通信数据只需一次拷贝
进程内的组件通信时,跳过IPC进行直接的通信






传统的IPC,通信数据需要执行两次,一次是从源进程的用户空间拷贝到内核空间,二次是从内核空间拷贝到目标进程的用户空间 










Low Memory Killer
内存紧张时回收进程
由于组件与进程是剥离的,因此进程回收不会影响组件的生命周期


从低优先级进程开始回收


Empty Process 


Hidden Process


Perceptible Process


Visible Process


Foreground Process




插入排序算法


template <class T> // 插入元素到有序数组 void Insert(T a[], int n, T x)


{ // 在有序数组a[0:n-1]中插入元素x int i;


for (i = n - 1; i >= 0 && x<a[i]; --i) a[i + 1] = a[i]; a[i + 1] = x; } template <class T> // 插入排序 void InsertionSort(T a[], int n)
{ // 对a[0:n-1]进行排序 for (int i = 1; i<n; ++i) Insert(a, i, a[i]);


}








快速排序:


// Partition.h
#pragma once
template <class T> // 划分程序
int Partition(T a[], int low, int high)
{ // 待划分数组为a[low .. high]。将<key的元素置于key左侧。
int pivot = low; // 划分位置
T key = a[pivot]; // 划分元素
for(int i = low + 1; i <= high; ++i)
if(a[i] < key) a[pivot] = a[i], ++pivot, a[i] = a[pivot];
// 将小于key的元素插入key左侧,大于key的元素向右移。
a[pivot] = key; // 划分位置的元素为key。
return pivot;
}
#include "Partition.h"
#include "Algorithm.hpp"
template <class T> //
void QuickSort(T a[], int low, int high)
{ if(low >= high) return;
int pivot = Partition(a, low, high); // 划分元素的位置
QuickSort(a, low, pivot - 1);
QuickSort(a, pivot + 1, high);
} //




选择排序:


#include "Partition.h"
#include "Algorithm.hpp" m
template <class T> //
T PartSelect(T a[], int n, int k)
{ // 在数组a[0..(n-1)]中找第k(1≤k≤n)小元素,即a[k-1]。
// 其余元素按划分元素为a[k-1]的划分规则存放。
int low = 0, high = n - 1, m; // low为起始下标,high为终止下标
for(--k;;) // 保证0≤k≤n-1
{ m = Partition(a, low, high); // m是第m(0≤m≤n-1)小元素的位置
if(k == m) return a[m];
else if(k < m) high = m - 1; // 新的终止下标为m-1
else low = m + 1; // 新的起始下标为m+1
}
}


冒泡排序:
 public void sort(int[] a)
    {
        int temp = 0;
        for (int i = a.length - 1; i > 0; --i)
        {
            for (int j = 0; j < i; ++j)
            {
                if (a[j + 1] < a[j])
                {
                    temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                }
            }
        }
    }


归并排序:
#include "Algorithm.hpp"


template <class T> // 合并两个有序组到w void Merge(T a[], int low, int mid, int high, T w[])


{ // 将有序组a[low .. mid]和a[mid+1 .. high] 合并到有序组w[low .. high]
int i = low, j = mid + 1, k = low; // low组游标i, high组游标j,结果游标k


for(; i <= mid && j <= high; ++k) // 当两组都 未取尽时


if(a[i] <= a[j]) w[k] = a[i], ++i; else w[k] = a[j], ++j;


//当low组取尽,而high组未取尽时,w[k .. high] = a[j .. high]


if(i > mid) copy(a + j, a + high + 1, w + k);


//当high组取尽,而low组未取尽时,w[k ..


high] = a[i .. mid]


else copy(a + i, a + mid + 1, w + k);
}




折半搜索算法:
template <class T> //
int BinarySearch(T a[], int n, const T &x)
{ // 在升序数组a中搜索x,返回所在位置,-1表示未找到
int left = 0, right = n - 1;
while(left <= right)
{ int middle = (left + right) / 2;
if(x == a[middle]) return middle;
else if(x > a[middle]) left = middle + 1;
else right = middle - 1;
} //
return - 1; // 未找到x
}






//fragement专题




1、fragment 继承 fragment需要实现 onCreate   onCreateView(返回UI) onpause(做数据保存)


2、fragment 在一个activt中添加一个碎片:
利用事务的add方法(activity中添加碎片的容器id,碎片);记住提交事务


3、fragment的生命周期方法:


activity onCreate()-------->对应碎片:onAttach--->onCreate----->onCreateView----->onActivityCreated(先activity后fragment)


activity onStart()--------->对应碎片:onStart()(先activity后fragment)


activity onResume()-------->对应碎片:onResume()(先activity后fragment)


activity onPause---------->对应碎片:onPause();(反)


acyivity onStop()---------->对应碎片:onStop();(反)


activity onDestroy()-------->对应碎片:onDestroyView---->onDestroy()----->onDetach()






4、fragment的管理:
用这个碎片替换掉当前的。
事务.replace(所放容器的id,碎片,自定义标签名)这个自定义标签名名是加入fragment的回退栈标记。
并把该自定义的标签fragment放入回退栈中。


5、通过在activity中添加fragment的时候可以加标签,然后在同一个activity中的fragment可以通过标签来获取
fragment. findFragmentByTag,获得fragment后调用getView()方法获得具体的view.fragment中用bundle传递数据








布局优化
1、布局有共性抽象出来,inlude
2、布局嵌套层次太深,用merge(另外一个文件中,还是用include包含进来)(线性布局嵌套)
3、viewstub惰性加载控件(动态加载)
3.1在布局中指定viewstub include的布局。
3.2获取viewstub控件
viewstub.inflate()动态填充布局
viewstub.setVisible隐藏动态加载的布局














分类:普通广播(同步),有序广播
 
  同步广播:发送方发出后,几乎同时到达多个广播接收者处,
某个接收者不能接收到广播后进行一番处理后传给下一个接收者,并且无法终止广播继续传播;Context.sendBroadcast(intent);


   
 有序广播:广播接收者需要提前设置优先级,优先级高的先接收到广播,优先级数值为-1000~1000,
在AndroidManifest.xml的<intent-filter android:priority="xxx">设置;比如存在3个广播接收者A、B、C,
优先级A>B>C,因此A最先收到广播,当A收到广播后,可以向广播中添加一些数据给下一个接收者(intent.putExtra()),
或者终止广播(abortBroadcast());Context.sendOrderedBroadcast(intent);








使用context.startService()
 启动Service是会会经历:
context.startService()  ->onCreate()- >onStart()->Service running
context.stopService() | ->onDestroy() ->Service stop 














使用使用context.bindService()启动Service会经历:
context.bindService()->onCreate()->onBind()->Service running
onUnbind() -> onDestroy() ->Service stop
onBind将返回给客户端一个IBind接口实例,
IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。 


   
在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。












Content Provider








LinearLayout中


1.android:layout_weight它用于描述该布局中子元素在剩余空间中占有的大小比例。


2.Android:orientation 用来设置字元素的排列顺序
3.android:gravity 对控件内容的设定
4.android:layout_gravity子元素在父布局的位置






RelativeLayout

android:layout_alignParentRight="true"设置距父布局右对齐
2 android:layout_below="@id/re_edit_0"设置该控件在id为re_edit_0控件的下方


3 android:layout_toLeftOf="@id/re_edit_0" 在re_edit_0控件的左边
4 android_layout_alignTop="@id/re_edit_0" 当前控件与re_edit_0上方对齐


5 android:layout_centerHrizontal  水平居中 
6 android:layout_centerVertical   垂直居中 


7 android:layout_centerInparent    相对于父元素完全居中 
8 android:layout_marginBottom              离某元素底边缘的距离










gridview
android:numColumns="3" ,GridView的列数
android:columnWidth="90dp",每列的宽度,即item的宽度 
android:stretchMode="columnWidth",
缩放与列宽大小同步 
android:verticalSpacing="10dp",两行之间的边距
android:horizontalSpacing="10dp",两列之间的边距
 


















Activity的 android:taskAffinity=””属性 姻缘关系
1.配置后 当启动这个activity时就先去找有没有activity的亲和力属性相同 有就加入这个
activity所在的任务中没有就新开任务










应用内存优化
(1)bitmap设置图片大小(优化内存溢出)
BitmapFactory.Option option = new BitmapFactory.Option();
option.inSampleSize = 2; //将视图宽、高都变为原来的1/2
(2)bitmap对象销毁,可以借助recycle()方法让GC回收bitmap对象。
(3)尽量避免static成员变量引用资源消耗过多的实例,如:context
(4)使用Application的context
(5)及时关闭资源,如在查询数据库时需要及时关闭cursor
(6)对经常使用的图片使用软引用保存
(7)线程也是造成内存泄露的一个重要原因,在于线程的生命周期不可控制,解决方法:
1.将线程内部类改为静态内部类
2.用弱引用来保存context引用






.set、List的区别:Set中元素不重复


强引用:内存不足时,不会回收强引用的对象
软引用:内存不足时,会回收软引用的对象
弱引用:垃圾回收每次都会回收弱引用的对象


17.静态内部类
(1)非静态内部类中bunengdingy静态成员变量和方法
(2)外部类和非静态内部类之间可以互相访问自己的私有成员
(3)静态内部类只能访问外部类的静态成员










view是最基础的,必须在UI主线程内更新画面,速度较慢。
SurfaceView是view的子类,类似使用双缓机制,在新的线程中更新画面所以刷新界面速度比view快。
GLSurfaceView是SurfaceView的子类,opengl 专用的。




assets:用于存放需要打包到应用程序的静态文件,以便部署到设备中。与res/raw不同点在于,
assets支持任意深度的子目录。这些文件不会生成任何资源ID,必须使用/assets开始(不包含它)的相对路径名。
res/raw:存放通用的文件,该文件夹内的文件将不会被编译成二进制文件,按原样复制到设备上。








屏幕适配:
尽量用wrap_content 或match_parent


尽量使用相对布局,而不是内嵌的线性布局。










5寸以下小屏幕,以上大屏幕。
在res/布局文件中分别建立文件夹并命名:layout-large文件夹








ViewPager:


1、在布局中


添加viewPager控件以及PagerTitleStrip


 <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center" >


        <android.support.v4.view.PagerTitleStrip
            android:id="@+id/pagertitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="top" >
        </android.support.v4.view.PagerTitleStrip>
    </android.support.v4.view.ViewPager>






2、在activity中获取viewpager控件


3、利用fragment 定义viewpager数据适配器定义:
MyFragmentPagerAdapter extends FragmentPagerAdapter(数据会缓存在内存中)


viewPager = (ViewPager) this.findViewById(R.id.viewpager);
items = new ArrayList<Fragment>();
Fragment1 fragment1 = new Fragment1();
Fragment2 fragment2 = new Fragment2();
items.add(fragment1);
items.add(fragment2);
titles = new ArrayList<String>();
titles.add("第一个页面");
titles.add("第二个页面");
adapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
}


public class MyFragmentPagerAdapter extends FragmentPagerAdapter {


public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
}


@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return items.get(arg0);
}


@Override
public CharSequence getPageTitle(int position) {
// TODO Auto-generated method stub
return titles.get(position);
}


@Override
public int getCount() {
// TODO Auto-generated method stub
return items.size();
}


}




pageAdapter




adapter = new MyPagerAdapter();
viewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
}


public class MyPagerAdapter extends PagerAdapter {


@Override
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
System.out.println("--path-->>" + items[position]);
View view = content.get(position);
final ImageView imageView = (ImageView) view
.findViewById(R.id.imageView1);
// imageView.setImageBitmap(bm);
new ImageDownLoad().loadImage(items[position], new ImageCallBack() {
@Override
public void getImageContent(Bitmap bitmap) {
// TODO Auto-generated method stub
imageView.setImageBitmap(bitmap);
}
});
((ViewPager) container).addView(view);
return view;
}


@Override
public CharSequence getPageTitle(int position) {
// TODO Auto-generated method stub
return title.get(position);
}


@Override
public int getCount() {
// TODO Auto-generated method stub
return content.size();
}


@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return (arg0 == arg1);
}


@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// TODO Auto-generated method stub
// super.destroyItem(container, position, object);
((ViewPager) container).removeView(content.get(position));
}
}






 FragmentStatePagerAdapter大批量的数据缓存








viewPager = (ViewPager) this.findViewById(R.id.pager);
items = new ArrayList<Fragment>();
items.add(new Fragment1());
items.add(new Fragment2());
items.add(new Fragment3());
items.add(new Fragment4());
adapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
}


/**
* 使用FragmentPagerAdapter适配器的时候,他会持久化数据,即使Fragment被系统销毁,数据也是会保存在内存中的
* 所以不能使用它来加载大量的数据

* 使用FragmentStatePagerAdapter适配器的时候,他会销毁Fragment仅仅保存Fragment的引用,适合加载一些大量的数据,
* @author jack

*/
public class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {


public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
}


@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return items.get(arg0);
}


@Override
public int getCount() {
// TODO Auto-generated method stub
return items.size();
}


}






自定义view


class MyView extends View {
Paint mPaint = null;


public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
mPaint = new Paint();
}


// 在自定义的View上画图
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
// 花文字
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(18);// 18dp
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);// 消除锯齿
canvas.drawText("hello world", 0, 120, mPaint);

//设置画布的背景颜色
canvas.drawColor(Color.WHITE);
//画一条直线
mPaint.setColor(Color.BLACK);
mPaint.setStrokeWidth(4);
canvas.drawLine(0, 0, 100, 100, mPaint);

//绘制一个矩形
mPaint.setColor(Color.BLUE);
canvas.drawRect(0, 120, 100, 200, mPaint);

//绘制椭圆
mPaint.setColor(Color.CYAN);
canvas.drawOval(new RectF(300, 370, 120, 100), mPaint);

//绘制一个多边形
mPaint.setColor(Color.RED);
Path path = new Path();
path.moveTo(150+5, 400-50);
path.lineTo(150+45, 400-50);
path.lineTo(150+30, 460-50);
path.lineTo(150+20, 460-50);
path.close();
canvas.drawPath(path,mPaint);
}
}


















 









0 0