安卓知识点_安卓开发知识点 - CSDN
  • 之前写的博客都是细枝末节的简单实用代码,没有一个完整的总结,没有完整的总结,就感觉博客也没有多少分量,这里就依照下面的安卓图谱(Android)来对安卓做一个全面的总结吧,也算对自己也是一个交代。 图谱 ...

    前言

    写博客已经5个年头了,从小白到现在,摸摸索索基本上对安卓整体开发和设计有了比较多的了解了。

    之前写的博客都是细枝末节的简单实用代码,没有一个完整的总结,没有完整的总结,就感觉博客也没有多少分量,这里就依照下面的安卓图谱(Android)来对安卓做一个全面的总结吧,也算对自己也是一个交代。

    图谱

    解析

    一个安卓App的完善,大体上需要开发这几个方向:基础、UI、数据、通信、安全、性能、适配、调试、NDK、手机功能、第三方扩展、等

     

    基础

    UI

    • Layout
    • View
    • Anim
    • Resource
    • OpenGL

    数据

    • Sqlite
    • File
    • ShardPreferences

    通信

    安全

    性能

    • UI优化
    • 内存优化
    • 电量优化
    • 流量优化

    适配

    • Screen Size
    • Screen Px
    • OS Version

    调试

    • Logcat
    • Heap
    • Lint

    NDK

    手机功能

    • 电话
    • 短信
    • 相机
    • Audio
    • 感应器

    第三方扩展

    • 地图
    • 语音识别
    • 支付

     

    ฅ՞•ﻌ•՞ฅ ~ 如果对你有帮助可以给个赞赏哈 ~ ฅ՞•ﻌ•՞ฅ

    展开全文
  • 基础知识 – 四大组件(生命周期,使用场景,如何启动) java基础 – 数据结构,线程,mvc框架 通信 – 网络连接(HttpClient,HttpUrlConnetion),Socket 数据持久化 – SQLite,SharedPreferences,...

    下面是一些面试官基本必问的问题,请一定要去了解!

    • 基础知识 – 四大组件(生命周期,使用场景,如何启动)

    • java基础 – 数据结构,线程,mvc框架 通信 – 网络连接(HttpClient,HttpUrlConnetion),Socket

    • 数据持久化 – SQLite,SharedPreferences,ContentProvider

    • 性能优化 – 布局优化,内存优化,电量优化 安全 – 数据加密,代码混淆,WebView/Js调用,https

    • UI– 动画

    • 其他 – JNI,AIDL,Handler,Intent等

    • 开源框架 – Volley,Gilde,RxJava等(简历上写你会的,用过的) 拓展 – Android6.0/7.0/8.0特性,kotlin语言,I/O大会

    展开全文
  • 安卓复习 第一章:安卓概述 windows7不属于移动操作系统 java虚拟机JVM不属于安卓平台的技术架构 activity通常就是一个单独的屏幕 第二章:活动(activity) Activity具有生命周期: 1. 激活或运行状态:...

    安卓复习

    第一章:安卓概述
    • windows7不属于移动操作系统
    • java虚拟机JVM不属于安卓平台的技术架构
    • activity通常就是一个单独的屏幕
    第二章:活动(activity)

    Activity具有生命周期:
    1. 激活或运行状态:此时的activity运行在屏幕的前台。
    2. 暂停状态:此时activity失去焦点但仍对用户可见。
    3. 停止状态:此时activity被其它activity完全覆盖。
    4. 终止状态:此时activity将会被系统清理出内存。

    Activity的7个方法定义了activity的生命周期:

    方法 功能描述 下一个方法
    onCreate() activity初次被创建的时候使用 onStart()、onRestart()
    onStart() 当activity即将对用户可见的时候被调用 onRestart()、onResume()
    onRestart() 当activity从停止状态重启的时候被调用 onResume()
    onResume() 当activity即将与用户进行交互时被调用 onPause()
    onPause() 当系统要启动其他的activity的时候被调用 onResume()、onStop()
    onStop() 当另外一个activity恢复并遮挡住当前activity时被调用 onStart()、onDestroy()
    onDestroy() activity被销毁前调用的最后一个方法

    Activity的生命周期还可以根据不同的标准划分为完整生命周期、可见生命周期、前台生命周期。

    • 完整生命周期:onCreate()到onDestroy()
    • 可见生命周期:onStart()到onStop()
    • 前台生命周期:onResume()到onPause()

    使用图片资源设置activity的背景:

    新建Android项目,复制图片到res/drawable-mdpi目录,编辑res/layout/activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"    
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@drawable/td">
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello"/>  
    </LinearLayout>
    

    暂停下的Activity失去了焦点但是仍然对用户可见

    android中的界面元素有一下三个部分构成:
    - 视图组件
    - 视图容器
    - 布局选项管理

    事件处理机制:

    安卓系统采用java的时间处理机制,包括事件,事件源,事件监听器
    事件:描述事件源状态改变的对象,由用户触发。
    事件源:产生事件的对象,通常指UI组件。
    事件监听器:对事件进行响应和处理。

    事件包括:单击事件、按键事件、创建上下文菜单事件、焦点事件、触碰事件、选项事件

    实现事件处理的步骤:

    1.创建事件监听器
    2.事件响应代码
    3.在相应的组件上注册监听器

    对话框提示信息Toast

    public class ToastActivity extends Activity{
        private Button b1;
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            b1 = (Button)findViewById(R.id.Button01);
            b1.setOnClickListener(new OnClickListener(){
                public void onClick(view v){
                    Toast t1 = Toast.makeText(getApplicationContext(),"我多显示一会儿",Toast.LENGTH_LONG);
                    t1.show();
                }
            })
        }
    }
    

    menu 选项菜单(OptionsMenu)

    public class OptionMenuActivity extends Activity{
        private final static int ITEM = Menu.FIRST;
    
        protected void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.option_menu_act);
        }
    
        public boolean onCreateOptionsMenu(Menu menu){
            menu.add(0,ITEM,0,"开始游戏");
            menu.add(0, ITEM + 1, 0, "结束游戏");
            return true;
        }
    
        public boolean onOptionsItemSelected(MenuItem item){
            switch(item.getItemId()){
            case ITEM:
                setTitle("开始游戏");
                break;
            case ITEM + 1:
                setTitle("游戏退出");
                break;
            }
            return true;
        }
    }
    

    上下文菜单

    1. 重写 onCreateContextMenu(),调用add方法,添加菜单项
    2. 重写onContextItemSelected(), 响应菜单点击事件
    3. 在onCreate()方法中调用registerForContextMenu(),为视图注册上下文菜单
    public class ContextMenuAtivity extends Activity{
        private static final int ITEM1 = Menu.FIRST;
        private static final int ITEM2 = Menu.FIRST + 1;
        private static final int ITEM3 = Menu.FIRST + 2;
        private static final int ITEM4 = Menu.FIRST + 3;
        private static final int ITEM5 = Menu.FIRST + 4;
    
        private TextView myTv;
    
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstaneState);
            setContentView(R.id.layout.main);
    
            myTv = (TextView)findViewById(R.id.textView01);
            registerForContextMenu(myTv);
        }
    
        public boolean onCreateOptionsMenu(Menu menu){
            menu.add(0, ITEM1, 0, "开始游戏");
            menu.add(0, ITEM2, 0, "退出游戏");
            return true;
        }
    
        public boolean onOptionsItemSelected(MenuItem item){
            switch(item.getItemId()){
            case ITEM1:
                setTitle("开始");
                break;
            case ITEM2:
                setTitle("结束");
                break;
            }
            return true;
        }
    
        public void onCreateContextMenu(ContexMenu menu, View v, ContextMenuInFo menuInfo){
            menu.add(0, ITEM3, 0, "红色背景");
            menu.add(0, ITEm4, 0, "绿色背景");
            menu.add(0, ITEM5, 0, "白色背景");
        }
    
        public boolean onContextItemSelected(MenuItem item){
            switch(item.getItemId()){
            case ITEM3:
                setBackgroundColor(Color.RED);
                break;
            case ITEM4:
                setBackgroundColor(Color.GREEN);
                break;
            case ITEM5:
                setBackgroundColor(Color.WHITE);
                break;
            }
            return true;
        }
    }
    

    创建选项菜单的步骤:

    1. 覆盖Activity的onCreateOptionsMenu()方法,当第一次打开菜单时,该方法被调用。
      2.调用Menu的add()方法添加菜单项
      3.覆盖Activity的onOptionsItemSelected()方法来响应事件。

    创建上下文菜单的步骤:

    1.在onCreate()方法中调用registerForContextMenu()方法为视图注册上下文菜单
    2.重写onCreateContextMenu()方法,调用add()添加菜单项
    3.重写onContextItemMenu()方法,响应菜单点击事件。

    用于开发用户应用程序交互功能的组件

    • 广播接收器
    • 意图
    • 适配器
    • 内容提供器

    Intent由动作、数据、分类、类型、组件和扩展信息组成

    public class Activity1 extends Activity{
    
        public void onCreate(Bundle savedInstanceState){
            RadioGroup RG_OS;
            RadioButton RG_OS_BT1;
            RadioButton RG_OS_BT2;
            RadioButton RG_OS_BT3;
            Button button_submit;
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity1);
    
            RG_OS = (RadioGroup)findViewById(R.id.RG_OS);
            RG_OS_BT1 = (RadioButton)findViewById(R.id.RG_OS_BT1);
            RG_OS_BT2 = (RadioButton)findViewById(R.id.RG_OS_BT2);
            RG_OS_BT3 = (RadioButton)findViewById(R.id.RG_OS_BT3);
            button_submit = (Button)findViewById(R.id.button_submit);
            button_submit.setOnClickListener(new ButtonOnClickListener());
        }
    
        class ButtonOnClickListener implements OnClickListener{
            public void onClick(View v){
                Intent myIntent = new Intent();
                myIntent.setClass(Activity1.this, Activity2.class);
                Activity1.this.startActivity(myIntent);
                Activity1.this.finish();
            }
        }
    }
    
    public class Activity2 extends Activity{
        Button button_back;
        public void onCreate(Bundle savedInstanceState){
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity2);
            button_back = (Button)findViewById(R.id.button_back);
            button_back.setOnCliclListener(new ButtonOnClickListener());
        }
    
        class ButtonOnClickListener implements OnClickListener{
            Intent myIntent = new Intent();
            myIntent.setClass(Activity2.this, Activity1.class);
            Activity2.this.startActivity(myIntent);
            Activity2.this.finish();
        }
    }
    

    简述Intent的过滤机制

    Intent过滤器是一种根据Intent中的动作(action)、类别(category)和数据(data)等内容。对适合接收该 Intent 的组件进行匹配和筛选的机制。Intent过滤器可以匹配数据类型、路径和协议,还可以确定多个匹配项顺序的优先级(priority)。应用程序的Activity、Service和 BroadcastReceiver 组件都可以注册Intent过滤器。这样,这些组件在特定的数据格式上则可以产生相应的动作。

    Service类似于Linux操作系统中的守护进程。

    Service具有以下特点:
    1. 没有用户界面,不与用户交互
    2. 长时间运行,不占用程序控制权。
    3. 比Activity的 优先级更高,不会轻易的倍Android系统终止,即使Service倍系统终止,在系统资源恢复之后Service仍将自动运行。
    4. 用于进程间通信,解决两个不同进程间的调用和通信问题。

    展开全文
  • Activity是一个Android的应用组件,它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口,窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上 Activity的生命周期 如何保存Activity的状态 1...

    废话不多说,直接上图:
    在这里插入图片描述

    Activity

    什么是Activity?

    Activity是一个Android的应用组件,它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口,窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上

    Activity的生命周期

    在这里插入图片描述

    如何保存Activity的状态

    1.一般来说, 调用 onPause()和 onStop()方法后的 activity 实例仍然存在于内存中, activity 的所有信息和状态数据不会消失, 当 activity 重新回到前台之后, 所有的改变都会得到保留。
    但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有
    该 activity 的实例对象了。如果之后这个 activity 重新回到前台, 之前所作的改变就会消失。为了避免此种情况的发生,我们可以覆写 onSaveInstanceState()方法 onSaveInstanceState()方法接受一个 Bundle 类型的参数, 开发者可以将状态数据存储到这个 Bundle 对象中, 这样即使 activity 被系统摧毁, 当用户重新启动这个 activity 而调用它的onCreate()方法时, 上述的 Bundle 对象会作为实参传递给 onCreate()方法,(或者是onRestoreInstanceState) 开发者可以从 Bundle 对象中取出保存的数据, 然后利用这些数据将 activity 恢复到被摧毁之前的状态。
    2.需要注意的是, onSaveInstanceState()方法并不是一定会被调用的, 因为有些场景是不需要保存状态数据的.如按下back键退出当前活动

    两个Activity之间跳转时必然会执行的是哪几个方法?

    当在A 里面激活B 组件的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。
    这个时候B覆盖了A的窗体, A会调用onStop()方法。
    如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。
    如果B已经存在于Activity栈中,B就不会调用onCreate()方法。

    横竖屏切换时Activity的生命周期

    第一次运行Activity : onCreate–>onStart–>onResume–>
    切换成横屏时:onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>
    在切换成竖屏时:onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>
    onSaveInstanceState–>onPause–>onStop–>onDestroy–>onCreate–>onStart–>onRestoreInstanceState–>onResume–>

    如何将一个Activity设置成窗口的样式

    activity中配置android:theme="@android:style/Theme.Dialog",另外
    android:theme="@android:style/Theme.Translucent"是设置透明

    如何退出Activity?如何安全退出已调用多个Activity的Application?

    退出Activity 直接调用 finish () 方法即可,退出activity 会执行 onDestroy()方法

    多个Activity的Application退出方法:

    1.记录打开的Activity:
    每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
    2、发送特定广播:
    在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
    3、递归退出
    在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。

    Activity的四种启动模式,singletop和singletask区别是什么?一般书签的使用模式是singletop,那为什么不使用singletask?

    Activity的四种启动模式

    在 AndroidManifest.xml 文件中 Activity 元素的 android:launchMode 属性。
    Activity的四种启动模式:standard:这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。
    singleTop: 如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的
    onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例
    singleTask:如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。
    singleInstance:在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。

    singletop和singletask区别是什么:

    singleTop要求如果创建intent的时候栈顶已经有要创建的Activity的实例,则将intent发送给该实例,而不发送给新的实例。(注意是栈顶,不在栈顶照样创建新实例!)
    singleTask模式:当intent到来,需要创建singleTask模式Activity的时候,系统会检查栈里面是否已经有该Activity的实例。如果有直接将intent发送给它。

    一般书签的使用模式是singletop,那为什么不使用singletask?

    singletask属性是如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。彻底改变了栈内的位置顺序

    Android中的Context, Activity,Appliction有什么区别?

    相同:Activity 和 Application 都是 Context 的子类。
    Context 从字面上理解就是上下文的意思,在实际应用中它也确实是起到了管理 上下文环境中各个参数和变量的总用,方便我们可以简单的访问到各种资源。
    不同:维护的生命周期不同。Context 维护的是当前的 Activity 的生命周期, Application 维护的是整个项目的生命周期。使用 context 的时候,小心内存泄露,防止内存泄露,注意一下几个方面:
    不要让生命周期长的对象引用 activity context,即保证引用 activity 的对 象要与 activity 本身生命周期是一样的。
    对于生命周期长的对象,可以使用 application,context.
    避免非静态的内部类,尽量使用静态类,避免生命周期问题,注意内部类 对外部对象引用导致的生命周期变化。

    两个Activity之间传递数据,除了intent,广播接收者,content provider还有啥?

    1.利用static静态数据,public static成员变量
    2.利用外部存储的传输,
    3. 例如 File 文件存储
    4. SharedPreferences首选项
    5. Sqlite 数据库

    Context 是什么?

    1.它描述的是一个应用程序环境的信息,即上下文。
    2、该类是一个抽象(abstract class)类,Android 提供了该抽象类的具体实 现类(ContextIml)。
    3、通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作, 例如:启动一个 Activity,发送广播,接受 Intent,信息,

    Service

    Service是否在main thread中执行, service里面是否能执行耗时的操作?

    默认情况,如果没有显示的指 service 所运行的进程, Service 和 activity 是运行在当前 app 所在进程的 main
    thread(UI 主线程)里面。
    service 里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 )

    Activity怎么和Service绑定,怎么在Activity中启动自己对应的Service?

    Activity通过bindService(Intent service, ServiceConnection conn, int flags)跟Service进行绑定

    private class myconn implements ServiceConnection
    
    {
    
    public void onServiceConnected(ComponentName name, IBinder service) {
    // TODO Auto-generated method stub
    //可以通过IBinder的对象 去使用service里面的方法
    }
    
    public void onServiceDisconnected(ComponentName name) {
    // TODO Auto-generated method stub
    
    }
    
    }
    
    Service生命周期

    只调用 startService() 启动服务:onCreate() -> onStartCommand() -> onDestory()
    只调用 bindService() 绑定服务:onCreate() -> onBind() -> onUnBind() -> onDestory()
    同时使用startService()与bindService():onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory。

    什么是IntentService?有何优点?

    IntentService 是 Service 的子类,比普通的 Service 增加了额外的功能。
    优点:
    会创建独立的worker线程来处理所有的Intent请求;
    会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
    所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
    为Service的onBind()提供默认实现,返回null;
    为Service的onStartCommand提供默认实现,将请求Intent添加到队列中;

    Activity、Intent、Service是什么关系

    一个 Activity 通常是一个单独的屏幕,每一个 Activity 都被实现为一个单独的类,这些类都是从 Activity 基类中继承而来的。
    Activity 类会显示由视图控件组成的用户接口,并对视图控件的事件做出响应。
    Intent 的调用是用来进行屏幕之间的切换。Intent 描述应用想要做什么。Intent 数据结构中两个最重要的部分是动作和动作对应的数据,一个动作对应一个动作数据。
    Service 是运行在后台的代码,不能与用户交互,可以运行在自己的进程里,也可以运行在其他应用程序进程的上下文里。需要一个Activity 或者其他 Context 对象来调用。
    联系:
    Activity 跳转 Activity,Activity 启动 Service,Service 打开 Activity 都需要 Intent 表明意图,以及传递参数,Intent 是这些组件间信号传递的承载着

    Service和Activity在同一个线程吗

    一般来说:同一个包内的activity和service,如果service没有设定属性android:process=":remote"的话,service会和activity跑在同一个进程中,由于一个进程只有一个UI线程,所以,service和acitivity就是在同一个线程里面的。

    Service里面可以弹吐司么

    Service不仅可以弹Toast还能弹出对话框,第一,Service是运行在主线程当中;第二,弹吐司有个条件就是得有一个 Context 上下文,而 Service 本身就是 Context 的子类;因此在 Service 里面弹吐司是完全可以的。

    Service里面可以弹吐司么

    Context.startService() 和 Context.bindService()。 区别 为
    Context.startService():Service 会经历 onCreate -> onStart(如果 Service 还没有运行, 则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(), 所以一个 Service 的 onStart 方法可能会重复调用多次 ); stopService 的时候直接 onDestroy,如果是调用者自己直接退出而没有调用 stopService 的话,Service 会一直在后 台运行。该 Service 的调用者再启动起来后可以通过 stopService 关闭 Service

    Service有哪些启动方法,有什么区别,怎样停用Service?

    Service 的方式 Context.startService() 和 Context.bindService()。 区别 为 Context.startService():Service 会经历 onCreate -> onStart(如果 Service 还没有运行, 则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(), 所以一个 Service 的 onStart 方法可能会重复调用多次 ); stopService 的时候直接 onDestroy,如果是调用者自己直接退出而没有调用 stopService 的话,Service 会一直在后 台运行。该 Service 的调用者再启动起来后可以通过 stopService 关闭 Service
    Context.bindService():Service 会经历 onCreate() -> onBind(),onBind 将返回给客户端 一个 IBind 接口实例,IBind 允许客户端回调服务的方法,比如得到 Service 运行的状态或其 他操作。这个时候把调用者(Context,例如 Activity)会和 Service 绑定在一起,Context 退出了,Srevice 就会调用 onUnbind -> onDestroyed 相应退出,所谓绑定在一起就共存亡 了 。
    停用 service 使用 context.stopService()

    service的生命周期方法onstartConmand()可不可以执行网络操作?如何在service中执行网络操作?

    可以直接在Service中执行网络操作

    Broadcast Receiver
    描述一下BroadcastReceiver

    用于监听(接收)应用发出的广播消息,并做出响应

    在manifest和代码中如何注册和使用BroadcastReceiver

    首先写一个类要继承 BroadcastReceiver
    第一种:在清单文件中声明,添加
    第二种使用代码进行注册如:
    创建IntentFilter ,并将要广播接收器接收的参数传进去
    创建广播接收器,New出一个广播接收器
    接着使用registerReceiver()方法,将上述创建的两个参数传进去

    BroadCastReceiver的生命周期

    每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 , 该对象即 被销毁

    ContentProvider
    请介绍下ContentProvider是如何实现数据共享的

    使用 ContentProvider 可以将数据共享给其他应用,让除本应用之外的应用也可以访问本应用的数据。它的底层是用 SQLite 数据库实现的,所以其对数据做的各种操作都是以 Sql 实现,只是在上层提供的是 Uri,用户只需要关心操作数据的 uri 就可以了,ContentProvider 可以实现不同 app 之间共享

    请介绍下Android的数据存储方式

    五种 SharePreferences、SQLite、Contert Provider、File、网络存储

    为什么要用ContentProvider?它和sql的实现上有什么差别?

    ContentProvider实现了不同APP之间数据共享,ContentProvider为其他应用程序提供了访问本应用程序的接口,其他应用程序可以通过ContentResolver来操作ContentProvider提供的数据,同时ContentProvider保证了被访数据的安全性,用户只需要关心操作数据的uri就可以了。
    sql也有增删改查的方法,单sql只能操作本应用下的数据库。

    说说ContentProvider、ContentResolver、ContentObserver之间的关系

    ContentProvider——内容提供者, 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider 对你应用中的数据进行添删改查。
    ContentResolver——内容解析者, 其作用是按照一定规则访问内容提供者的数据(其实就是调用内容提供者自定义的接口来操作它的数据)。
    ContentObserver——内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。

    Intent
    Intent传递数据时,可以传递哪些类型数据?

    Intent/Bundle支持传递基本类型的数据和基本类型的

    Serializable和Parcelable的区别

    两者区别在于存储媒介的不同。
    Serializable使用IO读写存储在硬盘上。序列化过程使用了反射技术,并且期间产生临时对象。优点代码少。
    Parcelable是直接在内存中读写,我们知道内存的读写速度肯定优于硬盘读写速度,所以Parcelable序列化方式性能上要优于Serializable方式很多。但是代码写起来相比Serializable方式麻烦一些。

    请描述一下Intent 和 IntentFilter

    filter一般不会在java代码中设置,而是在应用的manifest文件中作为元素的方式声明。一个例外是,为broadcast
    receiver注册动态的filter,可以调用Context.registerReceiver()方法,通过直接实例化IntentFilter对象创建。

    Fragment
    Fragment跟Activity之间是如何传值的

    fragment跳转activity传值 采用Bundle

    Intent intent = new Intent(getActivity(), FirstActivity.class);
    Bundle bundle = new Bundle();
    bundle.putString("address", address);
    intent.putExtras(bundle);
    startActivity(intent);
    
    描述一下Fragment的生命周期

    被创建到用户可见: onAttach()->onCreate()->onCreateView()->onActivityCreated()onStart()->onResume()
    后台模式:onPause()->onStop()
    销毁: onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()

    Fragment的replace和add方法的区别

    可以看到add()方法添加的Fragment没有发生销毁对象的情况,怎么切换还是原来的Fragment
    而replace()方法,会销毁前一个Fragment1,重新创建Fragment2

    Fragment如何实现类似Activity栈的压栈和出栈效果的?

    Fragment的事物管理器内部维持了一个双向链表结构,该结构可以记录我们每次add的Fragment和replace的Fragment,然后当我们点击back按钮的时候会自动帮我们实现退栈操作。

    如何切换fragement,不重新实例化

    正确的切换方式是add(),切换时hide(),add()另一个Fragment,再次切换时,只需hide()当前,show()另一 个。

    扩展
    在单线程模型中Message,Handler,Message Queue,Looper之间的关系。

    拿主线程来说,主线程启动时会调用Looper.prepare()方法,会初始化一个Looper,放入Threadlocal中,接着调用Looper.loop()不断遍历Message Queue, Handler的创建依赖与当前线程中的Looper,如果当前线程没有Looper则必须调用Looper.prepare()。Handler , sendMessage到MessageQueue,Looper不断从MessageQueue中取出消息,回调handleMessage方法。

    内存泄漏有哪些场景以及解决方法
    1. 类的静态变量持有大数据对象 静态变量长期维持到大数据对象的引用,阻止垃圾回收。
    2. 非静态内部类存在静态实例 非静态内部类会维持一个到外部类实例的引用,如果非静态内部类的实例是静态的,就会间接长期维持着外部类的引用,阻止被回收掉。
      3.资源对象未关闭 资源性对象比如(Cursor,File文件等)往往都用了一些缓冲,我们在不使用的时候,应该及时关闭它们, 以便它们的缓冲及时回收内存。它们的缓冲不仅存在于java虚拟机内,还存在于java虚拟机外。 如果我们仅仅是把它的引用设置为null,而不关闭它们,往往会造成内存泄露。 解决办法: 比如SQLiteCursor(在析构函数finalize(),如果我们没有关闭它,它自己会调close()关闭), 如果我们没有关闭它,系统在回收它时也会关闭它,但是这样的效率太低了。 因此对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,然后才置为null. 在我们的程序退出时一定要确保我们的资源性对象已经关闭。 程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小, 对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险,记得try catch后,在finally方法中关闭连接
      4.Handler内存泄漏 Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:
      5.一些不良代码习惯 有些代码并不造成内存泄露,但是他们的资源没有得到重用,频繁的申请内存和销毁内存,消耗CPU资源的同时,也引起内存抖动 解决方案 如果需要频繁的申请内存对象和和释放对象,可以考虑使用对象池来增加对象的复用。 例如ListView便是采用这种思想,通过复用converview来避免频繁的GC
    如何避免 OOM 问题的出现

    1.使用更加轻量的数据结构 例如,我们可以考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构。通常的HashMap的实现方式更加消耗内存,因为它需要一个额外的实例对象来记录Mapping操作。另外,SparseArray更加高效,在于他们避免了对key与value的自动装箱(autoboxing),并且避免了装箱后的解箱。
    2.避免在Android里面使用Enum Android官方培训课程提到过“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具体原理请参考
    3. 减小Bitmap对象的内存占用 Bitmap是一个极容易消耗内存的大胖子,减小创建出来的Bitmap的内存占用可谓是重中之重,,通常来说有以下2个措施: inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。 decode format:解码格式,选择ARGB_6666/RBG_545/ARGB_4444/ALPHA_6,存在很大差异
    4. Bitmap对象的复用 缩小Bitmap的同时,也需要提高BitMap对象的复用率,避免频繁创建BitMap对象,复用的方法有以下2个措施 LRUCache : “最近最少使用算法”在Android中有极其普遍的应用。ListView与GridView等显示大量图片的控件里,就是使用LRU的机制来缓存处理好的Bitmap,把近期最少使用的数据从缓存中移除,保留使用最频繁的数据, inBitMap高级特性:利用inBitmap的高级特性提高Android系统在Bitmap分配与释放执行效率。使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的Bitmap会尝试去使用之前那张Bitmap在Heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放Bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小
    5.使用更小的图片 在涉及给到资源图片时,我们需要特别留意这张图片是否存在可以压缩的空间,是否可以使用更小的图片。尽量使用更小的图片不仅可以减少内存的使用,还能避免出现大量的InflationException。假设有一张很大的图片被XML文件直接引用,很有可能在初始化视图时会因为内存不足而发生InflationException,这个问题的根本原因其实是发生了OOM。
    6.StringBuilder 在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”。避免在onDraw方法里面执行对象的创建 类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。

    Android 中常用的五种布局

    Android 布局是应用界面开发的重要一环,在 Android 中,共有五种布局方式,分别是: FrameLayout (框架布局),LinearLayout (线性布局),AbsoluteLayout (绝对布局), RelativeLayout (相对布局), TableLayout (表格布局)。

    handler机制的原理

    andriod提供了Handler和Looper来满足线程间的通信。Handler先进先出原则。Looper类用来管理特定线程内对象之间的消息交换(MessageExchange)。
    1.Looper:一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。
    2.Handler:你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从MessageQueue取出)所送来的消息。
    3.MessageQueue(消息队列):用来存放线程放入的消息。
    4.线程:UIthread通常就是mainthread,而Android启动程序时会替它建立一个MessageQueue。

    AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?

    解析 AsyncTask 运用的场景就是我们需要进行一些耗时的操作,耗时操作完成后更新主线程,或者在操作过程中对主线程的UI进行更新。 缺陷:AsyncTask中维护着一个长度为128的线程池,同时可以执行5个工作线程,还有一个缓冲队列,当线程池中已有128个线程,缓冲队列已满时,如果 此时向线程提交任务,将会抛出RejectedExecutionException。 解决:由一个控制线程来处理AsyncTask的调用判断线程池是否满了,如果满了则线程睡眠否则请求AsyncTask继续处理。

    展开全文
  • Android常用知识点总汇

    2019-07-24 15:08:26
     如果在你的android系统上安装了多种浏览器,能否指定某浏览器访问指定页面?答案当然是:肯定的。  具体方法如下: Intent intent = new Intent(); intent.setAction("android.intent.action.VIEW"); Uri.....

    一、系统上安装了多种浏览器,能否指定某浏览器访问指定页面?请说明原由。

      如果在你的android系统上安装了多种浏览器,能否指定某浏览器访问指定页面?答案当然是:肯定的。

      具体方法如下:

    复制代码
    Intent intent = new Intent();        

    intent.setAction("android.intent.action.VIEW");
    Uri content_uri_browsers = Uri.parse("http://isomobile.com");
    intent.setData(content_uri_browsers);
    intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");
    startActivity(intent);
    复制代码

      问题的关键在于我们设置了class name,也就是我们想要跳转的pakcage的activity。如果你想要跳转到其它的浏览器,只需要修改一下这个函数就OK了。

      好,我们现在来让刚刚的思路来指导我们的实践。假如我们现在要直接启动UC浏览器,那么我们该怎么做呢?让我们step by step吧。
      1)下载UC apk:http://i-uc.net/read.php?2
      2)用7zip解压apk文件,得到classes.dex文件
      3)下载反编译dex文件工具:http://nchc.dl.sourceforge.net/project/dedexer/dedexer/1.5/ddx1.5.jarDedexer 项目主页:  http://dedexer.sourceforge.net/
      4)执行命令:java -jar ddx1.5.jar -o -D -d c:\     c:\classes.dex
      5)得到package name是:com.uc.browser,启动的activity是:com.uc.browser.ActivityUpdate(补充:当我在这里选择采用ActivityBrowser的时候发觉权限不够,报permiss denied 异常,而且也不是我们要的那个activity,幸运的是在第二次尝试用ActivityUpdate,刚好能满足要求)
      6)修改上面的代码为intent.setClassName("com.uc.browser","com.uc.browser.ActivityUpdate");

    二、请解释下Android程序运行时权限与文件系统权限的区别

      要区分apk运行时的拥有的权限与在文件系统上被访问(读写执行)的权限两个概念。apk程序是运行在虚拟机上的,对应的是Android独特的权限机制,只有体现到文件系统上时才使用linux的权限设置。
      (一)linux文件系统上的权限
      -rwxr-x--x system   system       4156 2010-04-30 16:13 test.apk
      代表的是相应的用户/用户组及其他人对此文件的访问权限,与此文件运行起来具有的权限完全不相关。比如上面的例子只能说明system用户拥有对此文件的读写执行权限;system组的用户对此文件拥有读、执行权限;其他人对此文件只具有执行权限。而test.apk运行起来后可以干哪些事情,跟这个就不相关了。千万不要看apk文件系统上属于system/system用户及用户组,或者root/root用户及用户组,就认为apk具有system或root权限
      (二)Android的权限规则

      (1)Android中的apk必须签名
      这种签名不是基于权威证书的,不会决定某个应用允不允许安装,而是一种自签名证书。重要的是,android系统有的权限是基于签名的。比如:system等级的权限有专门对应的签名,签名不对,权限也就获取不到。默认生成的APK文件是debug签名的。获取system权限时用到的签名,见:如何使Android应用程序获取系统权限

      (2)基于UserID的进程级别的安全机制

      大家都知道,进程有独立的地址空间,进程与进程间默认是不能互相访问的,是一种很可靠的保护机制。Android通过为每一个安装在设备上的包(apk)分配唯一的linux userID来实现,名称为"app_"加一个数字,比如app_43不同的UserID,运行在不同的进程,所以apk之间默认便不能相互访问。Android提供了如下的一种机制,可以使两个apk打破前面讲的这种壁垒。在AndroidManifest.xml中利用sharedUserId属性给不同的package分配相同的userID,通过这样做,两个package可以被当做同一个程序,系统会分配给两个程序相同的UserID。当然,基于安全考虑,两个package需要有相同的签名,否则没有验证也就没有意义了。(这里补充一点:并不是说分配了同样的UserID,两程序就运行在同一进程, 下面为PS指令摘取的,显然,system、app_2分别对应的两个进程的PID都不同,不知Android到底是怎样实现它的机制的)

    User   PID PPID
    system    953   883   187340 55052 ffffffff afe0cbcc S system_server
    app_2     1072 883   100264 19564 ffffffff afe0dcc4 S com.android.inputmethod.
    system    1083 883   111808 23192 ffffffff afe0dcc4 S android.process.omsservi
    app_2     1088 883   156464 45720 ffffffff afe0dcc4 S android.process.acore

      (3)默认apk生成的数据对外是不可见的
      实现方法是:Android会为程序存储的数据分配该程序的UserID。借助于Linux严格的文件系统访问权限,便实现了apk之间不能相互访问似有数据的机制。
    例:我的应用创建的一个文件,默认权限如下,可以看到只有UserID为app_21的程序才能读写该文件。
      -rw------- app_21   app_21      87650 2000-01-01 09:48 test.txt

    如何对外开放?
      <1> 使用MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE 标记。
    When creating a new file with getSharedPreferences(String, int), openFileOutput(String, int), or openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), you can use the MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE flags to allow any other package to read/write the file. When setting these flags, the file is still owned by your application, but its global read and/or write permissions have been set appropriately so any other application can see it.

      (4)AndroidManifest.xml中的显式权限声明
    Android默认应用是没有任何权限去操作其他应用或系统相关特性的,应用在进行某些操作时都需要显式地去申请相应的权限。
    一般以下动作时都需要申请相应的权限:

    A particular permission may be enforced at a number of places during your program's operation: 

    • At the time of a call into the system, to prevent an application from executing certain functions.
    • When starting an activity, to prevent applications from launching activities of other applications.
    • Both sending and receiving broadcasts, to control who can receive your broadcast or who can send a broadcast to you.
    • When accessing and operating on a content provider.
    • Binding or starting a service.

      在应用安装的时候,package installer会检测该应用请求的权限,根据该应用的签名或者提示用户来分配相应的权限。在程序运行期间是不检测权限的。如果安装时权限获取失败,那执行就会出错,不会提示用户权限不够。大多数情况下,权限不足导致的失败会引发一个 SecurityException, 会在系统log(system log)中有相关记录。

      (5)权限继承/UserID继承
    当我们遇到apk权限不足时,我们有时会考虑写一个linux程序,然后由apk调用它去完成某个它没有权限完成的事情,很遗憾,这种方法是行不通的。前面讲过,android权限是经营在进程层面的,也就是说一个apk应用启动的子进程的权限不可能超越其父进程的权限(即apk的权限),即使单独运行某个应用有权限做某事,但如果它是由一个apk调用的,那权限就会被限制。实际上,android是通过给子进程分配父进程的UserID实现这一机制的。

      (三)常见权限不足问题分析
      首先要知道,普通apk程序是运行在非root、非system层级的,也就是说看要访问的文件的权限时,看的是最后三位。另外,通过system/app安装的apk的权限一般比直接安装或adb install安装的apk的权限要高一些。
      言归正传,运行一个android应用程序过程中遇到权限不足,一般分为两种情况:
      (1)Log中可明显看到权限不足的提示。
      此种情况一般是AndroidManifest.xml中缺少相应的权限设置,好好查找一番权限列表,应该就可解决,是最易处理的情况。有时权限都加上了,但还是报权限不足,是什么情况呢?Android系统有一些API及权限是需要apk具有一定的等级才能运行的。比如 SystemClock.setCurrentTimeMillis()修改系统时间,WRITE_SECURE_SETTINGS权限好像都是需要有system级的权限才行。也就是说UserID是system。

      (2)Log里没有报权限不足,而是一些其他Exception的提示,这也有可能是权限不足造成的。比如:我们常会想读/写一个配置文件或其他一些不是自己创建的文件,常会报java.io.FileNotFoundException错误。系统认为比较重要的文件一般权限设置的也会比较严格,特别是一些很重要的(配置)文件或目录。
      -r--r----- bluetooth bluetooth      935 2010-07-09 20:21 dbus.conf
      drwxrwx--x system   system            2010-07-07 02:05 data 
      dbus.conf好像是蓝牙的配置文件,从权限上来看,根本就不可能改动,非bluetooth用户连读的权利都没有。/data目录下存的是所有程序的私有数据,默认情况下android是不允许普通apk访问/data目录下内容的,通过data目录的权限设置可知,其他用户没有读的权限。所以adb普通权限下在data目录下敲ls命令,会得到opendir failed, Permission denied的错误,通过代码file.listfiles()也无法获得data目录下的内容。

      上面两种情况,一般都需要提升apk的权限,目前我所知的apk能提升到的权限就是system(具体方法见:如何使Android应用程序获取系统权限),
    至于是否有root级的,如何提升至root级不得而知,知道的朋友劳烦告知,感激不尽。

    三、AIDL的全称是什么?如何工作?能处理哪些类型的数据?

      详情请参看:http://buaadallas.blog.51cto.com/399160/372090

      部分概念: 在Android每个应用程序都可以有自己的进程在写UI应用的时候经常要用到Service. 在不同的进程中怎样传递对象呢?  显然, Java中不允许跨进程内存共享因此传递对象只能把对象拆分成操作系统能理解的简单形式以达到跨界对象访问的目的J2EE,采用RMI的方式可以通过序列化传递对象Android则采用AIDL的方式。 理论上AIDL可以传递Bundle,实际上做起来却比较麻烦.

      AIDL(AndRoid接口描述语言)是一种借口描述语言编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的如果需要在一Activity访问另一个Service中的某个对象需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数在消息的接收端使用这些参数组装成自己需要的对象

      AIDLIPC的机制和COMCORBA类似是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相关类; 2. 调用aidl产生的class。

      AIDL的创建方法:

      AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。由于远程调用的需要这些参数和返回值并不是任何类型.下面是些AIDL支持的数据类型:

      1. 不需要import声明的简单Java编程语言类型(int,boolean)

      2. String, CharSequence不需要特殊声明

      3. List, MapParcelables类型, 这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型。

    四、请解释下在单线程模型中Message、Handler、Message Queue、Looper之间的关系。

    1. Android进程
      在了解Android线程之前得先了解一下Android的进程。当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行。同时,Android会为每个应用程序分配一个单独的LINUX用户。Android会尽量保留一个正在运行进程,只在内存资源出现不足时,Android 会尝试停止一些进程从而释放足够的资源给其他新的进程使用,也能保证用户正在访问的当前进程有足够的资源去及时地响应用户的事件。Android会根据进程中运行的组件类别以及组件的状态来判断该进程的重要性,Android会首先停止那些不重要的进程。按照重要性从高到低一共有五个级别:

      前台进程
      前台进程是用户当前正在使用的进程。只有一些前台进程可以在任何时候都存在。他们是最后一个被结束的,当内存低到根本连他们都不能运行的时候。一般来说,在这种情况下,设备会进行内存调度,中止一些前台进程来保持对用户交互的响应。

      可见进程
      可见进程不包含前台的组件但是会在屏幕上显示一个可见的进程是的重要程度很高,除非前台进程需要获取它的资源,不然不会被中止。

      服务进程
      运行着一个通过startService() 方法启动的service,这个service不属于上面提到的2种更高重要性的。service所在的进程虽然对用户不是直接可见的,但是他们执行了用户非常关注的任务(比如播放mp3,从网络下载数据)。只要前台进程和可见进程有足够的内存,系统不会回收他们。

      后台进程
      运 行着一个对用户不可见的activity(调用过 onStop() 方法).这些进程对用户体验没有直接的影响,可以在服务进程、可见进程、前台进程需要内存的时候回收。通常,系统中会有很多不可见进程在运行,他们被保存在LRU (least recently used) 列表中,以便内存不足的时候被第一时间回收。如果一个activity正确的执行了它的生命周期,关闭这个进程对于用户体验没有太大的影响。

      空进程
      未运行任何程序组件。运行这些进程的唯一原因是作为一个缓存,缩短下次程序需要重新使用的启动时间。系统经常中止这些进程,这样可以调节程序缓存和系统缓存的平衡。Android 对进程的重要性评级的时候,选取它最高的级别。另外,当被另外的一个进程依赖的时候,某个进程的级别可能会增高。一个为其他进程服务的进程永远不会比被服务的进程重要级低。因为服务进程比后台activity进程重要级高,因此一个要进行耗时工作的activity最好启动一个service来做这个工作,而不是开启一个子进程――特别是这个操作需要的时间比activity存在的时间还要长的时候。例如,在后台播放音乐,向网上上传摄像头拍到的图片,使用service可以使进程最少获取到“服务进程”级别的重要级,而不用考虑activity目前是什么状态。broadcast receivers做费时的工作的时候,也应该启用一个服务而不是开一个线程。

    2. 单线程模型
      当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

    2.1 子线程更新UI
      Android的UI是单线程(Single-threaded)的。为了避免拖住GUI,一些较费时的对象应该交给独立的线程去执行。如果幕后的线程来执行UI对象,Android就会发出错误讯息
    CalledFromWrongThreadException。以后遇到这样的异常抛出时就要知道怎么回事了!

    2.2 Message Queue
      在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍:
    1. Message
      Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。
    2. Handler
      Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的 Handler对象引用来sendMessage(Message)。而使用Handler,需要implement该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。
    3. Message Queue
      Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
      每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被 Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。
    4. Looper
      Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper() 得到当前线程的Looper就有可能为NULL。
      对于子线程使用Looper,API Doc提供了正确的使用方法:

      这个Message机制的大概流程:
      1)在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。
      2)一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用该Message的target指向的Hander的dispatchMessage函数对Message进行处理。
        在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:
        1) Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;
        2) Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;
        3) 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。
        由此可见,我们实现的handleMessage方法是优先级最低的!
    3. Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收!
        在网上有很多文章讲述主线程和其他子线程如何交互,传送信息,最终谁来执行处理信息之类的,个人理解是最简单的方法——判断Handler对象里面的Looper对象是属于哪条线程的,则由该线程来执行!
        1)当Handler对象的构造函数的参数为空,则为当前所在线程的Looper;
        2) Looper.getMainLooper()得到的是主线程的Looper对象,Looper.myLooper()得到的是当前线程的Looper对象。

    五、注册广播有几种方式,这些方式有何优缺点?请谈谈Android引入广播机制的用意。

    Android 的广播机制  
      在 Android 里面有各种各样的广播,比如电池的使用状态,电话的接收和短信的接收都会产生一个广播,应用程序开发者也可以监听这些广播并做出程序逻辑的处理。下面我画一张粗略的图来帮助大家理解广播的运行机制。

      Android 中有各式各样的广播,各种广播在Android 系统中运行,当系统/应用程序运行时便会向 Android 注册各种广播,Android 接收到广播会便会判断哪种广播需要哪种事件,然后向不同需要事件的应用程序注册事件,不同的广播可能处理不同的事件也可能处理相同的广播事件,这时就需要 Android 系统为我们做筛选。

    案例分析:
      一个经典的电话黑名单,首先通过将黑名单号码保存在数据库里面,当来电时,我们接收到来电广播并将黑名单号码与数据库中的某个数据做匹配,如果匹配的话则做出相应的处理,比如挂掉电话、比如静音等等...

    Demo 分析:
      下面通过一个小DEMO 来讲解一下广播在Android 中如何编写,在Demo中我们设置了一个按钮为按钮设置点击监听通过点击发送广播,在后台中接收到广播并打印LOG信息。代码如下:

    复制代码
    //BroadCastActivity 页面代码
    public class BroadCastActivity extends Activity {
    public static final String ACTION_INTENT_TEST = "com.terry.broadcast.test";

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Button btn = (Button) findViewById(R.id.Button01);
    btn.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    // TODO Auto-generated method stub
    Intent intent = new Intent(ACTION_INTENT_TEST);
    sendBroadcast(intent);
    }
    });
    }
    }

    //接收器代码如下:

    public class myBroadCast extends BroadcastReceiver {
    public myBroadCast() {
    Log.v("BROADCAST_TAG", "myBroadCast");
    }

    @Override
    public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Log.v("BROADCAST_TAG", "onReceive");
    }
    }
    复制代码

      Android 广播的生命周期 在上面的接收器中,继承了BroadcastReceiver 并重写了它的onReceive 并构造了一个函数,下面通过图片来一步一步认识 Android 广播的生命周期。当我点击一下按钮,它向Android 发送了一个广播,如下图: 

       这时我们再点击一下按钮,它还是会再向 Android 系统发送广播,此时日志信息如下: 

      下面本人画一张图像,描述了Android 中广播的生命周期,其次它并不像Activity 一样复杂,运行原理很简单如下图:

      下面来看一下SDK给出的解释: 

      大意为:如果一个广播处理完onReceive 那么系统将认定此对象将不再是一个活动的对象,也就会finished掉它。 至此,大家应该能明白 Android 的广播生命周期的原理,代码也不用多介绍,很简单的一个发送广播并处理广播的Demo。  

       Android 如何判断并筛选广播? 前 面说过 Android 的广播有各式各样,那么Android 系统是如何帮我们处理我们需要哪种广播并为我们提供相应的广播服务呢?这里有一点需要大家注意,每实现一个广播接收类必须在我们应用程序中的 manifest 中显式的注明哪一个类需要广播,并为其设置过滤器,如下图: 

      Tip:action 代表一个要执行的动作,在Andriod 中有很action 比如 ACTION_VIEW,ACTION_EDIT

      那么有些人会问了,如果我在一个广播接收器中要处理多个动作呢?那要如何去处理?

       在Android 的接收器中onReceive 以经为我们想到的,同样的你必须在Intent-filter 里面注册该动作,可以是系统的广播动作也可以是自己需要的广播,之后你之需要在onReceive 方法中,通过intent.getAction()判断传进来的动作即可做出不同的处理,不同的动作。具体大家可以去尝试测试一下。

       小结:

       在Android 中如果要发送一个广播必须使用sendBroadCast 向系统发送对其感兴趣的广播接收器中。

    • 使用广播必须要有一个intent 对象必设置其action动作对象
    • 使用广播必须在配置文件中显式的指明该广播对象
    • 每次接收广播都会重新生成一个接收广播的对象
    • 在BroadCast 中尽量不要处理太多逻辑问题,建议复杂的逻辑交给Activity 或者 Service 去处理

      Android广播机制(两种注册方法) 

      在android下,要想接受广播信息,那么这个广播接收器就得我们自己来实现了,我们可以继承BroadcastReceiver,就可以有一个广播接受器了。有个接受器还不够,我们还得重写BroadcastReceiver里面的onReceiver方法,当来广播的时候我们要干什么,这就要我们自己来实现,不过我们可以搞一个信息防火墙。具体的代码:

    复制代码
    public class SmsBroadCastReceiver extends BroadcastReceiver    
    {
    @Override
    public void onReceive(Context context, Intent intent)
    {
    Bundle bundle = intent.getExtras();
    Object[] object = (Object[])bundle.get("pdus");
    SmsMessage sms[]=new SmsMessage[object.length];
    for(int i=0;i<object.length;i++)
    {
    sms[0] = SmsMessage.createFromPdu((byte[])object[i]);
    Toast.makeText(context, "来自"+sms[i].getDisplayOriginatingAddress()+" 的消息是:"+sms[i].getDisplayMessageBody(), Toast.LENGTH_SHORT).show();
    }
    //终止广播,在这里我们可以稍微处理,根据用户输入的号码可以实现短信防火墙。
    abortBroadcast();
    }
    }
    复制代码

      当实现了广播接收器,还要设置广播接收器接收广播信息的类型,这里是信息:android.provider.Telephony.SMS_RECEIVED。我们就可以把广播接收器注册到系统里面,可以让系统知道我们有个广播接收器。这里有两种,一种是代码动态注册:

    复制代码
    //生成广播处理   
    smsBroadCastReceiver = new SmsBroadCastReceiver();  
    //实例化过滤器并设置要过滤的广播   
    IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");

    //注册广播
    BroadCastReceiverActivity.this.registerReceiver(smsBroadCastReceiver, intentFilter);
    复制代码

      一种是在AndroidManifest.xml中配置广播

    复制代码
    <?xml version="1.0" encoding="utf-8"?>  
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package
    ="spl.broadCastReceiver"
    android:versionCode
    ="1"
    android:versionName
    ="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".BroadCastReceiverActivity"
    android:label
    ="@string/app_name">
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    </activity>

    <!--广播注册-->
    <receiver android:name=".SmsBroadCastReceiver">
    <intent-filter android:priority="20">
    <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
    </receiver>

    </application>

    <uses-sdk android:minSdkVersion="7" />

    <!-- 权限申请 -->
    <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>

    </manifest>
    复制代码

      两种注册类型的区别是:

         1)第一种不是常驻型广播,也就是说广播跟随程序的生命周期。

         2)第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

     

    BroadcastReceiver用于监听被广播的事件

    必须被注册,有两种方法:

    1、在应用程序的代码中注册

    注册BroadcastReceiver:

    registerReceiver(receiver,filter);

    取消注册BroadcastReceiver:

    unregisterReceiver(receiver);

    当BroadcastReceiver更新UI,通常会使用这样的方法注册。启动Activity时候注册BroadcastReceiver,Activity不可见时候,取消注册。

    2、在androidmanifest.xml当中注册

    <receiver>

        <intent-filter>

         <action android:name = "android.intent.action.PICK"/>

        </intent-filter>

    </receiver>

    使用这样的方法注册弊端:它会始终处于活动状态,毕竟是手机开发,cpu和电源资源比较少,一直处于活动耗费大,不利。

    六. Android ServiceBinderAIDL?

      作为Android重要的后台服务,这些每个Android开发者都应该掌握,这也算是和Java SE最大的不同了,具体的实例大家可以查看Android音乐播放器的源代码Music.git中的,这里不再赘述。



    sourceurl:http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350068.html

    转载于:https://www.cnblogs.com/hnrainll/archive/2012/12/18/2824229.html

    展开全文
  • 接触 Android 开发也有一段时间了,前段时间便开始想抽空整理一些知识点,通过笔记整理的方式减少自己重复学习的时间成本和提高自身的效率。 目前先是总结了部分 Android知识点,这就是本文的主要分享内容。想...
  • 一、Android四大组件 Activity相关, Activity生命周期理解、 Activity四种启动模式,Activity的显示/隐式启动,Activity之间的跳转与回调,Activity之间的intent数据传递,理解Activity工作原理Activity与Window...
  • Activity 一 生命周期 4种状态 running / paused / stopped /...Activity启动 onCreate -> onStart -> onResumeHome返回主界面 onPause -> onStop再次回到原Activity onRestart -> onStart -> onResume退出Ac
  • 说明:本篇博客只是一个知识整理,因为网上对于Android知识介绍足够多,因此我不再写相关文章(主要是因为我写的不如人家好),所以所有文章均来自网络,不贴原文章,只提供连接,因此本文旨在减少你对相关知识的...
  • Android知识点汇总

    2018-07-27 13:20:23
    1.Activity生命周期: 正常流程:onCreate()-&gt;onStart()-&gt;onResume()-&gt;onpause()-&gt;onStop()-&gt;onDestory();...android面试(2)-Activity篇 2.service生命...
  • ///////////////////////之前转载过一篇题目为《一张思维导图,告诉你Android新手如何快速入门》的文章,这篇文章是从stormzhang的公众号里看到的,关于Android知识点总结,大家有兴趣可以看看。本篇文章就是根据...
  • Android知识点-思维导图在Android应用开发也摸爬滚打两年了,也算积累了些经验,接下来的日子我会根据如下思维导图,不定期的不按顺序的写写文章来讲述每个知识点。
  • Android知识点总结 Android知识点总结(一)Android事件分发机制 Android 知识点总结 (二) view绘制流程
  • android知识点总结

    2013-03-26 19:32:00
    1. activity的生命周期 函数调用过程: 启动第一个Activity的时候: 第一次创建onCreate()-->Activity可见了onStart()-->Activity可以操作了onResume()。   ...第一个Activity暂停onPause()-->创建第二个Activity
  • Android 学习笔记总结;陪伴我大二一学期,掏钱买的,看了很多遍,很不错的资源
  • 这篇博客留着记录一些比较深入和思路清晰的大神的文章链接。 也是在一边学习一边整理,持续更新中,也在此感谢那些懂得分享的大神们:   ...3、动画原理,底层如何给上层信号 任玉刚(《Andro...
  • Android知识点总结

    2016-08-28 17:54:26
    Android知识点总结如下: App在不同平台下的性能比较
  • 1,Android UI体系 1) Android之MVC、MVP 对于小项目可以按如下分法(mvp选用);对于大项目可以按模块分,然后模块内再按如下分发。 分包(按功能分): basal:基类; surface(fragment、...
  • Android中的异步任务机制 Android中AsyncTak的使用与源码分析 http://blog.csdn.net/bboyfeiyu/article/details/8973058 Android进阶2之AsyncTask实现异步处理任务 htt
  • Android知识点复习整理

    2016-09-26 17:09:20
    Android任何一个Thread中都跟着一个Looper,Looper提供了MessageQueue。只要Thread拥有MessageQueue,别的线程就可以往其中添加Message。Looper.prepare(),Looper.loop(),Looper.release(). 如果不
1 2 3 4 5 ... 20
收藏数 132,964
精华内容 53,185
关键字:

安卓知识点