Linux内核层:为Android设备的各种硬件提供了底层的驱动,如:显卡驱动、音频驱动、照相驱动、蓝牙驱动、WI-FI驱动、电源管理等;
系统运行库层:通过一些C/C++库来为Android系统提供了主要的特性支持.
应用框架层:提供了构建应用程序时可能用到的各种API;
应用层:所有安装在手机上的应用程序都属于这一层;
http://www.androiddevtools.cn/(软件下载网址)
JDK
Android Studio
Android SDK
项目目录结构 1、.gradle和.idea(自动生成,无需关心); 2、app:项目中的代码、资源等内容几乎都是放置在这个目录下的;build和外层的build类似,主要包含一些编译时自动生成的文件;libs:项目中使用到的第三方的jar包,需要将这些jar包都放在libs目录下,放在这个目录下的jar包都会被自动添加到构建路径里去;androidTest:编写Android Test 测试用例,可以进行一些自动化测试;java:放置Java代码的地方;res:项目中使用到的所有图片、布局、字符串等资源都要存放在这个目录下。AndroidManifest.xml:你整个Android项目的配置文件,你程序中定义的所有四大组件都需要在这个文件里注册,另外还可以在这个文件中给应用程序添加权限声明;test:用来编写Unit Test测试用例,对项目进行自动化测试的另一种方式;.gitignore:将app模块内的指定的目录或文件排除在版本控制之外,作用和外层的.gitignore文件类似;app.iml: IntelliJ IDEA项目自动生成的文件;build.gradle:app模块的gradle构建脚本,这个文件中会指定很多项目构建相关的配置;proguard-rules.pro:指定项目代码的混淆规则; 3、build:编译时自动生成的; 4、gradle:包含gradle wrapper的配置文件,使用gradle wrapper的方式不需要提前将gradle下载好,而是会自动根据本地缓存情况决定是否需要联网下载gradle; 5、.gitignore:这个文件是用来将指定的目录或文件排除在版本控制之外的. 6、build.gradle:这个文件是全局的gradle构建脚本.1.3.6详解build.gradle文件; 7、Doctor.iml:iml文件是所有IntelliJ IDEA项目都会自动生成的一个文件,Android Studio是基于IntelliJ IDEA开发的,用于标识这是一个IntelliJ IDEA项目; 8、gradle.properties:这个文件是全局的gradle配置文件,在这里配置的属性将会影响到项目中所有的gradle编译脚本; 9、gradlew和gradlew.bat:这两个文件是用来在命令行界面执行gradle命令的,其中gradlew是在Linux或Mac系统中使用的,gradlew.bat是在Windows系统中使用的 10、local.properties:这个文件用于指定本机中Android SDK路径,通常自动生成的; 11、setting.gradle:这个文件用于指定项目中所有引入的模块。 12、External Libraries
Res目录;所有以drawable开头的文件夹都是用来放图片的,所有以mipmap开头的文件夹都是用来放应用图标的,所有以values开头的文件夹都是用来放字符串、样式、颜色等配置的,layout文件夹是用来放布局文件的.更多的时候美工只会提供给我们一份图片,这时把 所有图片都放在drawable-xxhdpi文件夹下就好了.
不同于Eclipse,Android Studio是采用Gradle来构建项目的.Gradle是一个非常先进的构建工具,它使用了一种基于Groovy的领域特定语言(DSL)来声明项目设置,摒弃了传统基于XML(如Ant和Maven)的各种烦琐配置.Android项目中两个build.gradle文件对构建Android Studio项目都起到了至关重要的作用; 项目外层目录下的build.gradle(全局的项目构建配置)文件:jcenter代码托管仓库,声明了jcenter()配置之后,我们可以在项目中轻松引用任何jcenter上的开源项目. 声明了classpath 'com.android.tools.build:gradle:2.2.2'配置表明我们使用Gradle来构建Android(Java、C++等)项目; 项目内层:看看Doctor项目中的build.gradle文件,Android Studio项目中一共有三种依赖方式:本地依赖(可以对本地的Jar包或目录添加依赖关系)、库依赖(可以对项目中的库模块添加依赖关系)和远程依赖(可以对jcenter库上的开源项目添加依赖关系).
res—>menu—>main布局 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/add_item" android:title="=Add" /> <item android:id="@+id/remove_item" android:title="Remove" /> </menu> 一个简单的demo: @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.add_item://实现相应的功能 break; case R.id.remove_item://实现相应的功能 break; default: } return true; }
Intent一般可被用于启动活动、启动服务以及发送广播等情景; Intent分为:显式和隐式两种; 隐式:(1)注册 <activity android:name=".activity.UpdateSoftActivity"> <intent-filter> <action android:name="com.example.activitytest.ACTION_START"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> (2)使用
Intent intent = new Intent("com.example.activitytest.ACTION_START"); startActivity(intent);
每个Intent只能指定一个action但却能多个category; 使用隐式Intent调用系统的浏览器来打开百度: Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("https://www.baidu.com/")); startActivity(intent); 使用隐式Intent调用系统内置的打电话的功能: Intent intent = new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); 更多关于Intent详细的用法(例如:geo显示地理位置)请查看Intent API 当用户在一个活动中按了返回键通过重写下面的方法做相应的业务逻辑操作: @Override public void onBackPressed() { super.onBackPressed(); Log.i(TAG, "onBackPressed:我按了返回键哦~"); }
返回栈:一种后进先出(或者先进后出)的数据结构;Activity可以分为3种生存期: (1)完整生存期:Activity在onCreate(完成各种初始化操作)方法和onDestroy(完成释放内存的操作)方法之间所经历的就是完整生命期。 (2)可见生存期:Activity在onStart(为了合理地管理那些对用户可见的资源,在onStart方法中对资源进行加载)方法和onStop(对资源进行释放)方法之间所经历的就是可见生存期. (3)前台生存期:Activity在onResume()方法和onPause()方法之间所经历的就是前台生存期。 避免系统内存不足Activity被回收造成数据丢失: onCreate()方法中 if (savedInstanceState!=null){ String tempData = savedInstanceState.getString("data_key"); Log.d(TAG, "onCreate: "+tempData); } 重写onSaveInstanceState()方法 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); String tempData = "just do it"; outState.putString("data_key",tempData); }
4种standard、singleTop、singleTask和singleInstance;使用方法在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式; 随时知晓当前是哪个Activity;让其他Activity继承下面的BaseActivity public class BaseActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i("BaseActivity", getClass().getSimpleName()); } } 随时随地退出程序: public class ActivityCollector { public static List<Activity> activities = new ArrayList<>(); public static void addActivity(Activity activity){ activities.add(activity); } public static void removeActivity(Activity activity){ activities.remove(activity); } public static void finishAll(){ for (Activity activity:activities) { if (!activity.isFinishing()){ activity.finish(); } } } } android.os.Process.killProcess(android.os.Process.myPid());//用于杀死当前程序的进程
第三章
TextView、Button、EditText、ImageView、ProgressBar(visible表示可见;invisible表示控件不可见,但是它仍然占据原来的位置和大小;gone表示控件不仅不可见,而且不再占用任何屏幕空间)进度条横向的属性 style="?android:attr/progressBarStyleHorizontal" android:max="100";AlertDialog、ProgressDialog setCancelable(false)表示不能通过back键取消这个ProgressDialog;Android百分比布局的引入以及使用: compile 'com.android.support:percent:25.0.1'
Title: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/title_bg"> <Button android:id="@+id/title_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dp" android:background="@drawable/back_bg" android:text="Back" android:textColor="#fff" /> <TextView android:id="@+id/title_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" android:gravity="center" android:text="Title Text" android:textColor="#fff" android:textSize="24sp" /> <Button android:id="@+id/title_edit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_margin="5dp" android:background="@drawable/edit_bg" android:text="Edit" android:textColor="#fff" /> </LinearLayout> TitleLayout: public class TitleLayout extends LinearLayout { public TitleLayout(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.title, this); Button titleBack = (Button) findViewById(R.id.title_back); Button titleEdit = (Button) findViewById(R.id.title_edit); titleBack.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ((Activity) getContext()).finish(); } }); titleEdit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getContext(), "You clicked Edit button", Toast.LENGTH_SHORT).show(); } }); } } MainActivity.class public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ActionBar actionbar = getSupportActionBar(); if (actionbar != null) { actionbar.hide(); } } } activity_main: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.uicustomviews.TitleLayout android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> inflate(R.layout.fragment_body_temperature, container, false);
inflate(R.layout.fragment_body_temperature, container, false);第三个参数只让父布局中声明的layout属性生效,但不为这个View添加父布局,因为一旦View有了父布局之后,它就不能再添加到ListView了;ListView中convertView的复用,提高效率;
LayoutManager(实现水平布局)、GridLayoutManager(实现网格布局)和StaggeredGridLayoutManager(实现瀑布流布局);RecyclerView(强大之处)可以轻松实现子项中任意控件或布局的点击事件(点9图的制作);
Fragment强大之处,可以在程序运行时动态地添加到活动当中;动态添加Fragment碎片分5步: RightFragment rightFragment = new RightFragment();//1、创建碎片实例 FragmentManager fragmentManager = getSupportFragmentManager();//2、获取碎片的管理者 FragmentTransaction transaction = fragmentManager.beginTransaction();//3、开启一个事务 transaction.replace(R.id.right_layout,rightFragment);//4、向容器中添加或替换碎片 transaction.commit();//5、提交事务 在Framgent碎片中模拟返回栈: transaction.addToBackStack(null);Fragment的生命周期查看官方文档; Fragment动态加载布局的技巧:res目录下新建layout-large布局;新建layout-sw600dp代表屏幕宽度大于600dp加载layout-sw600dp该目录下的文件,屏幕宽度小于600dp时加载原来res下对应的布局;Fragment碎片同时兼容手机和平板(在layout-sw600dp中加一个news_content_fragment的id,如果能够找到这个id,则加载平板双页模式,如果没有找到则加载手机单页模式);
跨进程的通信方式(Exported表示允许这个广播接收本程序以外的广播;Enabled属性表示是否启用这个广播接收器.);为了安全,可以发送本地广播(通过Local BroadcastManager类实现,只有本程序才能接收到);
git config --global user.name “MrSun” git congfig –global user.email “Mrsun@gmail.com” 创建代码仓库:git init .git文件夹用来记录本地所有的Git操作(查看当前目录所有文件夹ls -al) 提交本地代码: 一次性把所有文件都添加好:git add .; 提交:git commit -m “First commit” 忽略文件:修改根目录下面的.gitignore和app模板下面的.gitignore文件; 查看文件修改情况:git status 查看更改的内容:git diff 撤销未提交的修改:git checkout app/src/main/java/com/example/providertest/MainActivity.class;(该撤销方式只是用于那些还没有add命令的文件) 取消添加:git reset HEAD app/src/main/java/com/example/providertest/MainActivity.class; 查看提交记录:git log 查看其中一条记录:git log id -1; 查看这条提交记录具体修改了什么内容:git log id -1–p; 分支 查看当前版本库中有哪些分支:git branch 创建分支:git branch version1.0; 删除分支:git branch –D version1.0 切换分支:git checkout version1.0 合并:git merge version1.0 将本地修改的内容同步到远程版本库:git push origin(远程版本库的Git地址) master(同步到的分支) 将远程版本库上的修改同步到本地:git fetch origin master 查看远程版本库上到底修改了哪些东西:git diff origin/master 将origin/master分支上的修改合并到主分支上: Git merge origin/master; Pull命令相当于将fetch和merge两个命令放在一起执行; 从远程版本库中获取最新的代码并且合并到本地: git pull origin master
详解持久化技术(文件存储、SharedPreference、SQLite数据库存储、ContentProvider)
核心技术就是Context类提供的openFileInput()和openFileOutput()方法;(不适合保存一些较为复杂的文本数据); MODE_PRIVATE:默认的操作模式,表示当指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容,而MODE_APPEND:则表示如果该文件已经存在,就往文件里面追加内容,不存在就创建新文件.
3步 SharedPreferences.Editor editor = getSharedPreferences("ID", MODE_PRIVATE).edit(); //1、获取一个SharedPreferences.Editor对象; editor.putString("patientName",patientName); //2、对象中添加数据 editor.commit();//3、或editor.apply()将添加的数据提交
CURD(Create,Retrieve,Update,Delete):insert select update delete;query SQLiteOpenHelper SQL语句创建book:create table Book( id integer primary key autoincrement, author text,price real,pages integer,name text) 命令行界面查看数据库:
1、adb shell(进入到设备的控制台) ;
2、进入cd /data/data/包名/databases/目录下;ls 命令查看该目录里的文件;
3、sqlite3 +数据库名打开数据库;
4、.table命令查看目前数据库中有哪些表;5、通过.schema命令来查看建表语句;
6、键入.exit或.quit退出数据库的编辑; 升级数据库: sqLiteDatabase.execSQL("drop table if exists Book");//如果数据库中存在Book表 就将它drop(删除)掉 sqLiteDatabase.execSQL("drop taable if exists Category");//如果数据库中存在Catgory表 就将它drop掉 onCreate(sqLiteDatabase); MyDataBaseHelper myDataBaseHelper = new MyDataBaseHelper(this, "BookStore.db", null, 2);//2版本,用于升级数据库 myDataBaseHelper.getWritableDatabase(); 使用LitePal工具(优化SQLiteDatabase)操作SQLite数据库(LitePal增(save())删(deleteAll())改(updateAll())查(findAll())操作);关于更多find操作请见书P252页; 将数据更新成默认值的操作:setToDefault(); 对象关系映射:将面向对象的语言和面向关系的数据库之间建立一种映射关系;
探究内容提供器(ContentProvider)
要想访问内容提供者中共享的数据,一定要借助ContentResolver(Context.getContentResolver())类,ContentResolver中提供了一系列的方法用于对数据进行CURD操作, insert()添加数据, update()更新数据, delete()删除数据,query()查询数据;不同于SQLiteDatabase使用一个Uri参数代替表名参数,Url由两部分组成:authority和path; 例如:Uri content://com.example.app.provider/table1 协议声明 authority path URI通配符: *:表示匹配任意长度的任意字符; #:表示匹配任意长度的数字; 创建内容提供器的步骤:1、新建一个类去继承ContentProvider(实现相应的方法);
2、借助UriMatcher类轻松实现匹配URI的功能;
3、实现getType()中的业务逻辑(用于获取Uri对象所对应的MIME类型);
运用手机多媒体
PendingIntent,取消通知(setAutoCancel()和cancel()方法),播放一段音频setSound(Uri.fromFile(new File(path))),让手机震动(需要加权限):setVibrate(new long[]{}),控制手机LED灯闪烁setLights(Color.GREEN,1000,1000),构建出富文本的通知内容,setStyle()方法,如长文字、图片等,setPriority()设置通知的重要程度;
打开摄像头拍照功能和从相册中选择照片两个案例;
播放音频:MediaPlayer(更多详细的用法请查看Android api); 播放视频:VideoView(更多详细的用法请查看Android api);
使用网络技术
WebView webView = new WebView(this); webView.getSettings().setJavaScriptEnable(true); webView.setWebViewClient(new WebViewClient()); webView.loadUrl("http://www.baidu.com);
OkHttp GET请求: new Thread(new Runnable() { @Override public void run() { String url = "http://10.10.10.152:6688/Service1.asmx/GetWorkStation"; OkHttpClient okHttpClient = new OkHttpClient(); RequestBody body = new FormBody.Builder().add("inXml", "<Request> <LoginName>5007</LoginName><Password></Password></Request>").build(); Request request = new Request.Builder().url(url).post(body).build(); Call call = okHttpClient.newCall(request); try { Response response = call.execute(); Log.i(TAG, response.body().string()); } catch (IOException e) { e.printStackTrace(); } } }).start();
Pull解析方式、SAX解析方式(还可以用XStream框架解析XML)
网络公用类的抽取和接口回调的使用;
探究服务(服务是Android中实现程序后台运行的解决方案,后台长期运行的任务,依附于创建服务时所在的应用程序进程)
解析Handler异步消息处理机制,以及AsyncTask的使用,它的原理也是基于异步消息处理机制(封装);关于AsyncTask的详细用法请查看Android api;
Activity和Service之间通信,通过bindService(Intent,ServiceConnection,BIND_AUTO_CREATE(绑定后自己创建))
1、前台服务(Notification实现类似于通知) 2、、使用IntentService(创建一个异步的、会自动停止的服务) 3、下载的示例(ServiceBestPractice项目)
基于位置的服务 得到某个应用程序的指纹:keytool -list –v -keystore <签名文件路径>
获取看的懂的位置信息option.setIsNeedAddress(true);
(1) 让地图显示出来,添加百度的自定义(com.baidu.mapapi.map.MapView)控件 SDKInitializer.initialize(getApplicationContext()); (2) 移动到我的位置; (3) 让“我”显示在地图上;(百度地图的更详细的用法和更新请参考官方文档); http://lbsyun.baidu.com/
最佳的UI体验----Material Design实战 Meterial Design谷歌的设计师们基于传统优秀的设计原则,结合丰富的创意和科学技术所发明的一套全新的界面设计语言;
Glide加载图片 Glide.with(context).load(Url).into(view); AppBarLayout(解决RecyclerView遮挡Toolbar的问题)
SwipeRefreshLayout(实现下拉刷新的功能)
Android高级技巧
一、全局获取Context的技巧(Application) 二、使用Intent传递对象 三、定制自己的日志工具
(源码地址https://github.com/guolindev/booksource)