每日一点点Android的积攒
一、Broadcast广播的学习
1.Broadcast种类
a.普通广播 : 通过sendBroadcast进行发送,如果注册了Action匹配的接受者则会收到,若发送广播有相应权限,那么广播接收者也需要相应权限
b.系统广播 :
c.有序广播(Ordered Broadcast : 通过sendOrderedBroadcast发送,广播接受者接收广播的顺序规则:Priority大的优先,动态注册的接收者优先,先接收的可以对广播进行截断和修改
d.App应用内广播(本地广播、Local Broadcast): 通过LocalBroadcastManager.getInstance(this).sendBroadcastSync(),App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App
相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高(本地广播只会在APP内传播,安全性高;不允许其他APP对自己的APP发送广播,效率高
e.粘性广播(Sticky Broadcast)
2.广播的注册方式
a.静态注册 : 在AndroidManifest.xml中注册的广播 , 当前应用关闭了,还是可以收到广播的
b.动态注册 : 在Service或者Activity组件中,通过Context.registerReceiver()注册广播接收器,它的生命周期与组件一致
3. localBroadcastManager的实现机制
它内部是通过Handler实现的,那么相比与系统广播通过Binder实现那肯定是更高效了,同时使用Handler来实现,别的应用无法向我们的应用发送该广播,而我们应用内发送的广播也不会离开我们的应用
LocalBroadcastManager内部协作主要是靠这两个Map集合:mReceivers和mActions,当然还有一个List集合mPendingBroadcasts,这个主要就是存储待接收的广播对象.
二、handler的进一步学习
1.为什么在子线程中创建Handler会抛异常?
Handler的工作是依赖于Looper的,而Looper(与消息队列)又是属于某一个线程,其他线程不能访问, 因此Handler就是间接跟线程是绑定在一起了。因此要使用Handler必须要保证Handler所创建的线程中有Looper对象并且启动循环。因为子线程中默认是没有Looper的,所以会报错。 主线程中默认是创建了Looper并且启动了消息的循环的,因此不会报错。
2.为什么不能在子线程更新UI?
UI更新的时候,会对当前线程进行检验,如果不是主线程,则抛出异常.
在三种特殊情况下是可以子线程更新UI的
a.在Activity创建完成后,mThread被赋值为主线程(ViewRootImpl),所以直接在onCreate中创建子线程是可以更新UI的
b.在子线程中添加 Window,并且创建 ViewRootImpl,可以在子线程中更新view
c.SurfaceView可以在其他线程更新
三、Android Framework的源码分析
1.AMS与APP、Activity的启动流程
四、AsyncTask的学习
class GetMeiNvLogoTaskextends AsyncTask<String,Integer,Bitmap> { //继承AsyncTask
/**
* 其中的三个参数
* String:指的是doInBackground()方法中的参数类型 即第一个参数
* Integer:指的是onProgressUpdate()方法中的参数类型 即第二个参数
* Bitmap:指的是onPostExecute()的方法中的参数类型和doInBackground()方法的返回值类型 即第三个参数
*/
//处理后台执行的任务,在后台线程执行,主要用于进行异步操作
@Override
protected Bitmap doInBackground(String... params) {
//用于发布更新消息,每次执行引方法都将会调用onProgressUpdate(Integer... progress)方法
publishProgress(0);
HttpClient hc = new DefaultHttpClient();
//用于发布更新消息,每次执行到此方法都会调用onProgressUpdate(Integer... progress)方法
publishProgress(10);
HttpGet hg = new HttpGet(params[0]);//获取csdn的logo
//定义一个Bitmap
final Bitmap bm;
try {
HttpResponse hr = hc.execute(hg);
bm = BitmapFactory.decodeStream(hr.getEntity().getContent());
} catch (Exception e) {
return null;
}
publishProgress(100);
//mImageView.setImageBitmap(result); 不能在后台线程操作ui
return bm; //返回的值会传入到onPostExecute()方法的参数中
}
//在doInBackground方法中每次执行publishProgress之后此方法都会被调用,在ui线程执行
//用于在执行异步任务的过程中,对用户进行提示,例如:控制进度条等。
protected void onProgressUpdate(Integer... progress) {
mProgressBar.setProgress(progress[0]);//更新进度条的进度
}
//后台任务(doInBackground())执行完之后被调用,在ui线程执行,
//主要用于将异步任务执行的结果返回给客户
protected void onPostExecute(Bitmap result) {
if(result != null) {
Toast.makeText(AsyncTaskActivity.this, "成功获取图片", Toast.LENGTH_LONG).show();
//把下载下来的图片设置在ImageView上
mImageView.setImageBitmap(result);
}else {
Toast.makeText(AsyncTaskActivity.this, "获取图片失败", Toast.LENGTH_LONG).show();
}
}
//在 doInBackground(Params...)之前,execute()方法之后被调用,在ui线程执行,所以可以设置控件大小属性等。
//主要用于异步操作之前的UI的准备工作
protected void onPreExecute () {
mImageView.setImageBitmap(null);
mProgressBar.setProgress(0);//进度条复位
}
protected void onCancelled () {//在ui线程执行
mProgressBar.setProgress(0);//进度条复位
}
}
##### 三个参数
* Params:表示后台任务执行时的参数类型,该参数会传给AysncTask的doInBackground()方法
* Progress:表示后台任务的执行进度的参数类型,该参数会作为onProgressUpdate()方法的参数
* Result:表示后台任务的返回结果的参数类型,该参数会作为onPostExecute()方法的参数
##### 五个方法
* onPreExecute():异步任务开启之前回调,在主线程中执行
* doInBackground():执行异步任务,在线程池中执行
* onProgressUpdate():当doInBackground中调用publishProgress时回调,在主线程中执行
* onPostExecute():在异步任务执行之后回调,在主线程中执行
* onCancelled():在异步任务被取消时回调
五、UI卡顿问题的处理
1.布局优化
a.include复用布局、使用ViewStub延迟加载布局、使用merge减少代码层级、使用RelativeLayout也能大大减少视图的层级、慎重设置整体背景颜色防止过度绘制
b.使用自定义View取代复杂的View
2.在UI线程中做轻微的耗时操作,导致UI线程卡顿:应该把耗时操作放在子线程中进行,UI卡顿最严重的后果是ANR,因此需要在开发中避免和解决ANR问题
3.列表控件滑动卡顿:复用convertView、滑动不进行加载、使用压缩图片、加载缩略图等。
六、Bitmap的理解和学习
1.Bitmap的内存占用大小与三个因素有关:
a.色彩格式,前面我们已经提到,如果是ARGB_8888那么就是一个像素4个字节,如果是RGB_565那就是2个字节
b.原始文件存放的资源目录(分辨率越小,内存占用越小)
c.目标屏幕的密度(屏幕的密度越小,内存占用越小)
2.Bitmap的色彩格式
a.ARGB_8888的内存消耗是RGB_565的2倍
b.ARGB_8888格式比RGB_565多了一个透明通道
c.如果使用RGB_565格式解析ARGB_8888格式的图片(png),可能会导致图片变绿
3.Bitmap的回收
Android8.0之后Bitmap的像素数据是存放Native内存中,我们需要回收Native层和Java层的内存,使用recycle方法进行回收,
该方法也可以不主动调用,因为垃圾回收器会自动收集不可用的Bitmap对象进行回收,recycle方法会判断Bitmap在不可用的情况下,将发送指令到垃圾回收器,让其回收native层和Java层的内存,则Bitmap进入dead状态
二、Fragment的学习
1. fragment的生命周期
onCreate onStart onResume onPaused onStoped onDestory onRestart ---------->上面为Activity的生命周期
onAttach onCreateView onActivityCreated onDestoryView onDetach
2.Fragment创建/加载到Activity的两种方式
a.静态加载的方式
1. 创建Fragment的xml布局文件
2. 在Fragment的onCreateView中inflate布局,返回
3. 在Activity的布局文件中的适当位置添加fragment标签,指定name为Fragment的完整类名(这时候Activity中可以直接通过findViewById找到Fragment中的控件)
b.动态加载
1. 创建Fragment的xml布局文件
2. 在Fragment的onCreateView中inflate布局,返回
```java @Nullable @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
return inflater.inflate(R.layout.activity_main, container, false); }
3. 在Activity中通过获取FragmentManager(SupportFragmentManager),通过beginTransaction()方法开启事务
4. 进行add()/remove()/replace()/attach()/detach()/hide()/addToBackStack()事务操作(都是对Fragment的栈进行操作,其中add()指定的tag参数可以方便以后通过findFragmentByTag()找到这个Fragment)
5. 提交事务:commit()
示例代码: ```java @Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction() .add(R.id.fragment_container, new TestFragment(), "test") .commit();
TestFragment f = (TestFragment) getSupportFragmentManager().findFragmentByTag("test"); -------------------------->通过找标签的形式找到fragment这个对象
}
3.fragment的之间通信
a.Fragment之间直接通信
public void onClick(View v) {
Fragment fragment = CrimeFragment.newInstance(mCrime.getId());
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.beginTransaction() .add(R.id.detail_fragment_container, fragment) .commit();
}
Fragment.getActivity().getSupportFragmentManager()
调用获取到其托管activity的FragmentManager,然后直接通过FragmentManager替换掉右侧的Fragment
缺点 : 复用性太差,不能保证fragment的独立性
b.通过Activity使用Fragment回调接口(推荐)
public class CrimeListFragment extends Fragment {
...
private boolean mSubtitleVisible;
private Callbacks mCallbacks;
/** * Required interface for hosting activities. */
public interface Callbacks {
void onCrimeSelected(Crime crime);
}
...
4.fragment和activity的之间通信方式
a.handler的方案:
public class MainActivity extends FragmentActivity{
//声明一个Handler
public Handler mHandler = new Handler(){
缺点:Fragment对具体的Activity存在耦合,不利于Fragment复用,没法获取Activity的返回数据
b.接口方案 : 这种方案应该是既能达到复用,又能达到很好的可维护性,并且性能也是杠杠的,但是不利于维护大项目的fragment的使用,包括为接口的命名,新定义的接口相应的Activity还得实现,相应的Fragment还得进行强制转换。
posted on 2019-06-19 11:11 zhang11111wei 阅读(170) 评论(0) 编辑 收藏 举报