Android学习之路笔记

这里写图片描述

最近是看了下大二上学期的时候学习Android的一些笔记资料,觉得以前是写的还有需要改进的地方,所以准备再重新整理整理发出来。学习Android的时候,是采用的视频+文档结合的方式。书呢看的是:郭大神的《第一行代码》。所以本篇笔记还是按照郭大神的目录来进行记录的。

第一章:了解全貌——Android王国简介

1、Android的四层架构:Linux内核层、系统运行库层、应用框架层和应用层
2、Android的四大组件:活动(Activity)、服务(Service)、广播接收器(Broadcast Receiver)、内容提供器(Content Provider)
3 、使用res目录下的资源的两种方式

例如:
    使用Res/values/string.xml文件,内容如下   
<resources>
    <string name="app_name>HrlloWorld</string>
</resources>
在代码中采用R.string.app_name获得HelloWorld的引用
在XML中通过@string/app_name获得引用

4、app下的build.grade文件分析

apply plugin: 'com.android.application'   应用的插件,有两种值可以选,com.android.application 表示这是一个应用程序模块,com.android.library表示这是一个库模块。
                                         应用程序模块和库模块的最大区别是应用程序模块是可以直接运行的,而库模块只能作为代码库依赖于其他应用程序模块来运行。
android
   compileSdkVersion 25   项目编译的版本
   buildToolsVersion "25.0.2"   项目构建工具的版本
   defaultConfig {  对项目的更多细节进行配置
       applicationId "com.example.dimple.alertdialog"   指定项目的包名
       minSdkVersion 25    指定项目最低兼容的安卓版本
       targetSdkVersion 25    表示Android25上已经做了充分的测试,
       versionCode 1      指定项目的版本号
       versionName "1.0"    指定项目的版本名
       testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
   }
   buildTypes { 用于指定安装文件的相关配置
       release {
           minifyEnabled false   表示是否对项目进行代码混淆
           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  指定混淆的时候使用的规则文件
       }
   }
}
​
dependencies {  指定当前项目的依赖关系,Android中一共有三种依赖方式:本地依赖、库依赖、远程依赖。
                本地依赖可以对本地的jar包或者目录添加依赖关系,库依赖可以对项目中的库模块进行添加依赖关系。
                远程依赖可以对jcenter库上的开源项目添加依赖关系。
   compile fileTree(dir: 'libs', include: ['*.jar'])   本地依赖声明,表示将lib目录下的所有的jar文件添加到项目的构建路径中
   androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
       exclude group: 'com.android.support', module: 'support-annotations'
   })
   compile 'com.android.support:appcompat-v7:25.3.0'   标准的远程依赖库格式,其中“com.android.support”是域名部分,用于和其他公司的库作区分。
                                                        “appcompat-v7”是组名称,用于和同一个公司的不同的库作区分。“25.3.0”是版本号,用于和同一个库的不同版本作区分。
   compile 'com.android.support.constraint:constraint-layout:1.0.1'
   testCompile 'junit:junit:4.12'
}

第二章 先从看得到的入手——探究活动

1、Genenate Layout File 是表示自动为Activity创建一个布局,Launcher Activity表示将当前活动设置为主活动。

2、配置主活动的方法:在Manifest中的Activity标签中添加标签,并在这个标签中添加

<action android:name="android.intent.action.MAIN"/>
<category android:name-"android.intent.category.LAUNCHER"/>  

3、在活动中使用Menu

在res中新建Menu文件夹,创建XML文件,然后在相应的Java代码中重写onCreateOptionMenu()和onOptionItemSelect()方法。

在onCreateOptionMenu():  
public boolean onCreateOptionMenu()
{
   getMenuInflater().inflater(R.menu.main,menu);
   return true;
}  

onOptionItemSelect()用于响应用户的事件。在此函数中,可以通过:item.getItemId判断点击的是哪一个菜单项。

4、销毁一个活动使用finish()函数,效果和按下back键是一样的

5、使用Intent

Intent是Android程序中各组件之间进行交互的主要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同的组件之间进行数据的传递。Intent一般可以用于启动活动,启动服务,以及发送广播等场景。

Intent有多个构造函数:Intent(Context packageContext,Class

6、Intent向上一个活动传递数据。

使用startActivityForResult()方法在A中来启动Activity B;第一个参数是Intent,第二个参数是请求码,用于在回调之后来判断数据的来源。

在B中Intent中putExtra()来返回要传递的数据。

同时调用setResult()方法,第一个参数是要上一个活动A传递的处理结果,一般只使用RESULT_OK或RESULT_CANCELED两个值,第二个参数价将带有数据的Intent返回。

在A中重写onActivityResult()方法,此方法有三个参数,第一个参数requestCode是我们在A中使用startActivityForResult()方法传入的,第二个参数是resultCode是在B中返回数据的时候传入的setResult方法中的结果码。第三个参数是传入的数据。

一般是重写back键按下之后回调的方法:onBackPressed();

7、活动的生命周期

  • 当活动被首次创建的时候:
    会依次调用:    onCreate()方法、onStart()方法、onResume方法。
  • 当从当前的活动跳转到另一个界面的时候(当前活动不可见)
    会依次调用:      onPause()方法、onStop()方法
  • 当从其他活动再跳转回来的时候
    会依次调用:     onRestart()方法、onStart()方法、onResume()方法
  • 当从当前活动跳转自另一个活动的时候(当前活动可见)
    会依次调用:    onPause()方法
  • 当从这个活动跳转会主活动的时候
    会依次调用:    onResume()方法
  • 结束当前活动的时候
    会依次调用:     onDestory()方法
    # 第三章 常用控件的使用方法

ListView的使用

listView 的简单用法

        首先,需要在布局中加入ListView控件,然后需要定义适配器(一般是ArrayAdapter)
ArrayAdapteradapter=new ArrayAdapter(
   context,resourse,data);
listView.setAdapter(adapter);

ListView之自定义适配器

    首先先创建一个类,这个类中包含了需要进行自定义适配器需要用到的相关资源文件,此类为JAVABean。
此外,还需要一个适配器,适配器继承自ArrayAdapter<>并泛型为定义的类。在此适配器中,重写getView()方法。

   `     
    /***  
    * 自定义适配器,继承自ArrayAdapter,并将泛型指定为Fruit类  
    */  
    class MyAdapter extends ArrayAdapter<Fruit>{  
       /**  
        *  
        * @param context  
        * @param resource  
        * @param objects  
        */  
       private  int Resource;  
       public MyAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<Fruit> objects) {  
           super(context, resource, objects);  
           Resource=resource;  
       }  
    ​  
       @NonNull  
       @Override  
       public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {  
           View view;  
           ViewHolder viewHolder;  
           Fruit fruit=getItem(position);    
           if (convertView==null){  
               view= LayoutInflater.from(getContext()).inflate(Resource,parent,false);  
               viewHolder-new ViewHolder();  
               viewHolder.ImageView imageView=view.findViewById(R.id.imageView);  
               viewHolder.TextView textView=view.findViewById(R.id.textView);  
               view.setTag(viewHolder);//将ViewHolder存储在View中
           }else{  
               view=convertView;  
               viewHolder=(ViewHolder)getTag();//重新获取ViewHolder  
           }  
           imageView.setImageResource(fruit.getFruitImage());  
           textView.setText(fruit.getFruitName());  
           return view;  
       }  
       class ViewHolder(){  
           ImageView fruitImage;  
           TextView fruitName;  
           
       }  `

其中getItem()方法是每个子项滚动到屏幕类的时候被调用。
    convertView将之前的项目进行缓存。
新建一个内部类ViewHolder,用于对实例对象进行缓存,把控件的实例都存放在viewHolder中,然后调用View的setTag()方法,将ViewHolder对象保存在View中,当convertView不为null的时候,调用View中的getTag()方法,将ViewHolder取出。这样系统每次就不用通过findViewById()来获取控件实例。
    点击事件需要设置监听

   @Override
   public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
      Fruit fruit=fruitList.get(i);
       Toast.makeText(getApplicationContext(),"position"+i+fruit.getFruitName(),Toast.LENGTH_LONG).show();
   }

RecyclerView使用

由于是新增的部件,所以需要添加依赖包

compile 'com.android.support:recyclerview-v7:26.+'  //此处需要注意的是V7:后的,是appcompat后面的版本号

      initData();//初始化集合List中的数据
       RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
       FruitAdapter adapter = new FruitAdapter(fruitList);
       /**
        * 这里用于指定RecyclerView的布局方式
        */
       LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
       recyclerView.setLayoutManager(linearLayoutManager);
       recyclerView.setAdapter(adapter);
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
   private List<Fruit>mFruitList;

       /**
        * 构造函数用于将要展示的数据传入,并赋值给一个全局变量mFruitList。
        * @param mFruitList
        */
       public FruitAdapter(List<Fruit> mFruitList) {
           this.mFruitList = mFruitList;
       }
    ​
       /**
        * 首先定义了一个内部类ViewHolder,ViewHolder要继承自RecyclerView.ViewHolder,然后ViewHolder的构造函数要传入一个view参数
        * 这个参数通常就是RecyclerView子项最外层的布局。
        */
       static class ViewHolder extends RecyclerView.ViewHolder{
           ImageView fruitImage;
           private View fruitView;//设置view点击事件  添加此变量来保存子项最外层的布局的实例
           TextView fruitName;
           public ViewHolder(View view) {
               super(view);
               fruitView=view;//获取View
               fruitImage=view.findViewById(R.id.imageView);
               fruitName=view.findViewById(R.id.textView);
    ​
           }
       }
    ​
       /**
        * onCreateViewHolder()是用于创建ViewHolder实例的,在这个方法中,将布局加载到ViewHolder的实例中,然后将ViewHolder实例返回
        * @param parent
        * @param viewType
        * @return
        */
       @Override
       public FruitAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
           View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
    ​
           final ViewHolder holder=new ViewHolder(view);
           /**
            * ViewHolder设置点击事件
            */
           holder.fruitView.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View view) {
                   /*
                   通过ViewHolder的getAdapterPosition获得position
                   然后可以通过该位置在List中获取实例
                    */
                   int position =holder.getAdapterPosition();
                   Fruit fruit=mFruitList.get(position);
                   Toast.makeText(view.getContext(),"this is "+ fruit.getFruitName(),Toast.LENGTH_LONG).show();
               }
           });
           return holder;
       }
    ​
       /**
        * 用于对RecyclerView子项的数据进行赋值,当每个子项被滚动到屏幕内的时候被调用
        * @param holder
        * @param position
        */
       @Override
       public void onBindViewHolder(FruitAdapter.ViewHolder holder, int position) {
           Fruit fruit=mFruitList.get(position);
           holder.fruitImage.setImageResource(fruit.getFruitImage());
           holder.fruitName.setText(fruit.getFruitName());
       }
    ​
       /**
        * 返回当前要加载的数据源的长度
        * @return
        */
       @Override
       public int getItemCount() {
           return mFruitList.size();
       }
    }`

瀑布流使用: StaggeredGridLayoutManager  设置瀑布流的布局方式

如果需要设置为横向滑动的话就需要在MainActivity中的LinearLayoutManager设置方向

 linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

使用步骤:

获取RecyclerView实例——设置layoutManager布局对象——绑定适配器
创建JavaBean类
创建适配器——继承自《RecyclerView.Adapter

第四章 碎片

碎片的静态加载

在MainActivity的布局文件中添加的使用

<fragment  
       android:id="@+id/id_fragment_title"  
       android:name="com.zhy.zhy_fragments.TitleFragment"  
       android:layout_width="match_parent"  
       android:layout_height="45dp" />  

在TitleFragment的布局文件和JAVA文件中进行操作
在java文件中重写onCreateView方法,注意要继承只V4包的Fragment

碎片的动态加载

在MainActivity的布局文件中声明一个区域作为碎片出现的位置 。
找MainActivity的JAVA文件中首先设置默认的显示的Fragment

prvate void setDefaultFragment(){
   FragmentManager fm =getFragmentManager();
   FragmentTransaction transaction = fm.beginTransaction();
   FragmentOne one=new FragmentOne();
   transaction.replace(R.id.mainactivity_fragment,one);
   transaction.commit();
}

Fragment常用的API:

Fragment常用的三个类

要用于定义Fragment。

  • android.app.FragmentManager主要用于在Activity中操作Fragment。
  • android.app.FragmentTransaction保证一系列Fragment操作的原子性。

获取FragmentManager的方式
- getFragmentManager()  //在V4包中,getSupportFragmentManager()

主要的操作中都是FragmentTransaction的方法
    FragmentManager fm =getSupportFragmentManager();
    FragmentTransaction transaction = fm.beginTransaction();//开启一个事务
    transaction.add(); //向Activity中添加一个Fragment
    transaction.remove();//从Activity中移除一个Fragment
    transaction.replace();//使用另一个Fragment替换掉当前的Fragment,实际上是remove()和add()的合体
    transaction.show();//显示之前隐藏的Fragment
    transaction.hide();//隐藏当前的Fragment,仅仅设置为隐藏,并不会销毁
    transaction.commit();//提交一个事务

注:如果希望保留用户在当前fragment的数据,就使用hide()和show()组合,这样不会销毁当前的Fragment
        如果不希望保留用户当前在Fragment的数据,就使用remove()和add()组合或者直接使用replace(),这样就会销毁当前的Fragment,再进去的时候就会重新加载
        如果使用replace的话,当程序已经不在当前的界面的时候,在其他界面按Back键的时候,将不会返回到这个界面,直接退出
        想要保留这个fragment的话,就需要将它添加到回退栈中: transaction.addToBackStack();
参考博客

第五章 广播

1、广播的两种类型

  • 标准广播  广播发出后,所有的广播接收器会在同一时间接收到这条广播。效率较高,无法截断。
  • 有序广播  广播发出后,同一时刻只有一个广播接收器能够接收到这条广播,并且优先级高的可以先接收到这条广播,并且前面的广播接收器可以截断广播。

2、注册广播的两种方式

    在代码中注册——动态注册——在程序关闭之后就不能再接收到广播
    在AndroidManifest中注册——静态注册——与程序是否关闭无关

3、创建广播接收器的方法

新建一个类,继承自BroadcastReceiver,并重写父类的onReceive()方法。
这样,当有广播到来的时候,onReceive()方法就会得到调用。

4、动态注册广播的方法

创建IntentInfilter的实例,添加一个action

IntentInfilter intentInfliter =new IntentInfliter();//创建IntentFilter实例  
intentInfilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//为这个IntentFilter添加action  
registerReceiver(networkChageReceiver,interFilter);//动态注册广播,这样networkChangeReceiver就会接收到所有值为android.net.conn.CONNECTIVITY_CHANGE的广播   

动态注册的广播需要取消注册,在onDestory中调用unRegisterReceiver()方法来实现的。

5、静态注册广播的方法

使用android Studio的快捷键创建一个广播接收器,点击包名——New——Other——Broadcast Receiver,Exported表示是否允许广播接收器接收本程序以外的广播,Enable表示是否启用这个广播。

(静态注册的广播接收器必须要在AndroidManifest中注册才能使用,使用Android Studio创建的广播接收器已经在AndroidManifest中注册了)
注册方式信息如下:

       <receiver
           android:name=".MyReceiver"
           android:enabled="true"//是否启用该广播接收器
           android:exported="true">//是否允许接受本程序之外的广播
           <intent-filter  android:priority="100">//priority是设置广播的优先级,优先级越高系统响应越快
               <action android:name="android.intent.action.BATTERY_LOW"/>//当系统低电量的时候就会发出这个广播
           </intent-filter>
       </receiver>
   </application>

在<intent-filter>标签中添加相应的Action标签

注意某些操作需要用到权限,需要在Manifest中添加权限。

此外,在onReceive中不能添加太多的逻辑以及耗时操作,在广播接收器中是不允许多开线程的,当此方法运行了太长时间而没有结束,程序会报错。

发送动态广播的方法:

Intent intent=new Intent("android.net.conn.CONNECTIVITY_CHANGE");
sendBroadcast(intent);

6、自定义广播

创建一个自定义的广播接收器继承自BroadcastReceicer,并重写onReceive()方法。
然后使用Intent发送广播。

  • 有序广播
    在Manifest中的Broadcast标签的Intent-filter中设置优先级属性priority
    发送广播的时候与标准广播不同
    sendOrderBroadcast(intent,null)//第一个是Intent实例,第二个是与权限相关的字符串,这里传入null
  • 截断广播
    abortBroadcast();//在广播接收器中调用这个方法就可以截断广播

7、本地广播

    本地广播的出现是为了解决广播在整个系统中运行中的安全性的问题,全局广播会被其他程序所截获,造成信息泄露。
    本地广播的用法
主要是使用一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和和注册广播的方法。

 localBroadcastManager=LocalBroadcastManager.getInstance(getApplicationContext());
       Button button= (Button) findViewById(R.id.button);
       button.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               Intent intent=new Intent("com.example.dimple.mytest.MYMY");
               localBroadcastManager.sendBroadcast(intent);
           }
       });
       IntentFilter intentFilter=new IntentFilter();
       intentFilter.addAction("com.example.dimple.mytest.MYMY");
       localBroadcastManager.registerReceiver(new MyReceiver(),intentFilter);

本地广播只能通过动态注册。

通过LocalBroadcastMaager的getInstance()方法得到实例。
然后注册广播的时候就调用LocalBroadcastManager()的registerRecriver()方法.
在发送广播的时候就调用LocalBroadcastManager的sendBroadcastManager()方法。

第六章 存储

1、使用SharedPreferences

SharedPreferences是采用键值对的方式来存储数据的。
要使用SharedPreferences需要首先获得SharedPreferences对象。获取该对象的方式有:
- Context类中的getSharedPreferences()方法,接收两个参数,第一个参数是文件的名称,第二个参数指定操作模式MODE,目前只能选择MODE_PRIVATE。
- Activity类中的getPreferences()方法,和getSharePreferences差不多,区别是使用getPreferences会使用当前的类名作为文件名。
- PrederencesManager类中的getDefaultSharedPreferences()方法 ,这是一个静态方法,接收一个context参数,会自动将当前的应用程序的包名作为前缀来命名SharePreferences文件

使用步骤
调用sharedPreferences对象的editor()方法来获得一个 sharedPerferences.Editor()对象
向sharedPerferences.Editor()对象添加数据。调用editor的putString()等些列方法
调用editor的apply()方法提交数据。

读取SharedPreferences的方法

获取SharedPreferences对象,通过getString()系列方法得到数据。注意这里有两个参数,第一个是要读取的数据的键,第二个参数是没有找到这个数据返回的值。

2、使用SQLite数据库进行存储

android中为了更好的管理数据库,提供了一个SQLiteOpenHelper的帮助类(抽象类),需要实现SQLiteOpenHelper抽象方法中的抽象方法onCreate()(在数据库被创建的时候会调用),onUpgrade()(在数据库版本被升级的时候被调用)

获取实例的方法:(都可以打开或者创建数据库)
getReadableDatebase()只能是通过只读的方式来打开数据库。
getWritableDatebase()使用读写的方式打开数据库。

使用方法:
新建一个JAVA类继承自SQLiteOpenHelper,实现两个抽象方法onCreate()和onUpgrade(),创建构造器(使用参数较少的那一个构造器),其参数有

Context context, String name, SQLiteDatabase.CursorFactory factory, int version

/*
第一个参数是context上下文
第二个参数是数据库名
第三个参数允许在查询的时候返回一个自定义的Cursor,一般为null
第四个参数是当前数据库的版本号,可用于对数据库的更新操作
*/

构建出SQLiteOpenHelper实例(new)以后,调用getReadableDatebase()或者getWritableDatebase()就可以创建数据库了。
创建的数据库的名字一般放在 /data/data//datebase目录下。

配置adb 在安卓SDK的目录下有一个platform-tools文件夹,将这个文件夹配置到系统的环境变量中,使用adb shell进入控制台终端

使用sqlite3 +数据库名称 打开数据库
使用.table 查看数据库中的表、
使用 .schema 查看建表语句

3、向SQLite数据库中添加数据
调用SQLiteOpenHelper的getReadableDatebase()或者getWritableDatebase()创建数据库后会返回一个SQLiteDatabase对象,借助这个对象就可以对数据库进行CRUD操作
添加数据
    SQLiteDatabase提供一个insert()方法用于添加数据。这个方法有三个参数。第一个参数是数据库表名称,第二个是用于指定在未添加数据的情况下给某些数据项自动赋值为null,第三个参数是ContentValues对象,它提供一系列的put()方法重载,用于向contentValues添加数据。使用此方法的时候需要创建ContentValues对象。

sqLiteDatabase.insert("Book",null,contentValues);//插入信息到Book

更新数据
    SQLiteDatabase提供一个update()的方法,第一个参数是表名,第二个参数是ContentValues对象,第三四个参数用于约定更新某一行或者某几行的数据。
    

    sqLiteDatabase.update("Book",contentValues,"id=?",new String[]{"1"});//更新id为1的书的信息
    第三个参数对应的是SQL的where语句,第四个提供约束的具体信息。

删除数据

    SQLiteDatabase提供一个delete()的方法,第一个参数是表名,第二三个参数用于约定删除某一行或者某几行的数据。

 sqLiteDatabase.delete("Book","pages>?",new String[]{"500"});//删除页数超过500页的书的信息  

查询数据

query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)方法各参数的含义:

 
- table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开。
 
- columns:要查询出来的列名。相当于select语句select关键字后面的部分。
 
- selection:查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符“?”
 
- selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常。
 
- groupBy:相当于select语句group by关键字后面的部分
 
- having:相当于select语句having关键字后面的部分
 
- orderBy:相当于select语句order by关键字后面的部分,如:personid desc, age asc;
 
- limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。

                   sqLiteDatabase=mySqlite.getWritableDatabase();
                   Cursor cursor=sqLiteDatabase.query("Book",null,null,null,null,null,null);//查询完毕后得到一个游标Cursor对象,通过这个对象去访问数据
                   if (cursor.moveToFirst()){//将游标移动到第一行的位置
                       do{//接下来是循环
                           //在这个循环中可以通过Cursor的getColumnIndex()方法获取到某一行的索引。将这个索引传入相应的取值方法中就可以得到相应的数据了。
    ​
                           String name=cursor.getString(cursor.getColumnIndex("name"));
                           String author =cursor.getString(cursor.getColumnIndex("author"));
                           int pages=cursor.getInt(cursor.getColumnIndex("pages"));
                           double price=cursor.getDouble(cursor.getColumnIndex("price"));
                           builder.append("name\n").append(name).append("author\n").append(author).append("pages\n").append(pages).append("price\n").append(price);
                       }while (cursor.moveToNext());
                       textView.setText(builder);
                   }

4、使用LitePal操作数据库

配置过程
    编辑app/build.gradle文件,在dependencies闭包中加入

   compile 'org.litepal.android:core:1.3.2'

然后在app/src/main目录新建一个assets目录,在此目录下创建一个litepal.xml文件

<litepal>  
    <!--dbname标签用于指定数据库名,version标签用于指定数据库版本号,list标签用于指定所有的映射模型-->  
    <dbname value="BookStore"></dbname>
    <version value ="2"></version>
    <list>
        <mapping class="com.example.dimple.sharedpreferencestest.Book"></mapping>
        <mapping class="com.example.dimple.sharedpreferencestest.Category"></mapping>
    </list>
</litepal>

最后需要在AndroidManifest中将项目的application配置为

   <application
       android:name="org.litepal.LitePalApplication"
       android:allowBackup="true"
       android:icon="@mipmap/ic_launcher"

创建数据库:
    使用面向对象的思想,定义一个Book类JavaBean类。
    将关系模型添加到映射模型列表中

<mapping class="com.example.dimple.sharedpreferencestest.Book"></mapping>

注:不管需要多少关系模型,注意要使用完整的类名,不管需要多少模型类映射,都需要用同样的方式在标签下配置。

在代码中使用Connector.getDatabase();创建数据库。

升级版本号,就可以直接修改litepal.xml中的version即可。此升级不会删除数据库。

添加数据
    需要将JavaBean类继承自DataSupport类。
    在java代码中,直接new一个JavaBean类的对象出来,然后调用set系列方法,最后调用DataSupport父类传下来的save()方法即可。

更新数据
直接new一个JavaBean对象出来,调用要修该的数据项的set函数,然后updataAll();  此方法可以设置约束条件

 book.updateAll("name=?","the da vinvi code ");//修改所有name=the da vinvi code的数据项。

删除数据

 DataSupport.deleteAll(Book.class,"price>?","17");
第一个参数是指定表,后面的参数是指定参数的数据项的属性。

查询数据
注:     
for (Book book:bookList)的意思是循环bookList集合,每次取得的实例就给Book book;

List bookList=DataSupport.findAll(Book.class);  
findAll()返回的是一个List集合。

常用的查询API
- 查询第一条数据

  Book book =DataSupport.findFirst(Book.class);  
  • 查询最后一条数据

    Book book =DataSupport.findLast(Book.class);  
    
  • select()方法可以指定查询那几列的数据。

    List<Book> bookList =DataSupport.select("name","pages").find(Book.class);
    
  • where()方法可以指定查询的约束条件

     List<Book> bookList =DataSupport.where("name=?","bianxiaofeng").find(Book.class);  
    
  • order()方法可以指定结果的排序方式

    List<Book> bookList =DataSupport.order("pages desc").find(Book.class);
    
  • limit()方法可以指定结果的数量

    List<Book> bookList =DataSupport.limit(3).find(Book.class);
    

还可以对所有的方法进行连缀组合操作。

第七章 内容提供器

1、内容提供器主要在不同的应用程序之间实现数据共享的功能。使用内容提供器是Android跨程序共享数据的标准方式。

2、运行时权限

    权限分为普通权限和危险权限。危险权限分为9组24个。每一个危险权限都属于一个权限组,一旦用户同意了某个权限组的一个权限,则对应的权限组都可以被获得权限。
    
步骤:
第一步需要判断用户是不是已经授权了。借助的是ContextCompat.setSelfPermission()方法。此方法接收两个参数:第一个是Context上下文,第二个是具体的权限名。
Manifest.permission.“`。使用方法的返回值和PackageManager.PERMISSION_GEANTED作比较,相等就表示已经授权。不相等就表示没有授权。

如果授权的话就执行具体的逻辑。如果不等的话就说明还没有得到用户的权限的同意,这个时候需要申请用户的权限。

调用ActivityCompat.requestPermission()方法来向用户申请权限。requrestPermission接受三个参数,第一个参数是要求的Activity实例,第二个参数是String数组,这里需要把要申请的权限名写在里面,第三个是请求码,需要唯一。在这个方法中判断是否得到授权。

//申请权限
if (ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission
                       .CALL_PHONE)!=PackageManager.PERMISSION_GRANTED){
                   ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest
                           .permission.CALL_PHONE},1);
               }else {
                  //do something else
               }
@Override
   public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                          @NonNull int[] grantResults) {
           switch (requestCode){
               case 1:
                   if (grantResults[0]==PackageManager.PERMISSION_GRANTED){
                       //do something else.
                   }else{
                       Toast.makeText(MainActivity.this,"failed!",Toast.LENGTH_LONG).show();
                   }
           }
   }

3、contentResolver的基本用法

对于一个应用程序来说,如果访问内容提供器中的共享的数据,就一定要借助ContentResolver类。可以通过getContentReslover来获取该类的实例。

使用inset()用于添加数据。update()用于更新数据。delete()用户删除数据。queny()用于查询数据。ContentReslover的增删查改需要接受Uri对象作为参数。

和数据库的操作一样是使用ContentValues作为中转传数据。调用CRUD函数进行操作。

第八章 运用手机多媒体

1、使用通知Notification

使用通知的步骤
首先需要一个NotificationManager来对通过通知进行管理,可以调用Context的getSystemService()方法来获取到。
getSystemService()方法接受一个字符串参数用于确定获取系统的哪一个服务。这里传入Context.NOTIFICATION_SERVICE即可。

NotificationManger manager=(NitificationManager)getSystemSerice(Context.NOTIFICATION_SERVICE);

接下来需要一个Builder构造器来创建Notification对象(为了实现兼容,使用v4包的NotificationCompat类)

Notification notification =new NotificationCompat.Builer(context);  

然后调用一系列的set方法对这个实体类进行设置。最后调用manager的notify()方法,该方法接收两个参数,第一个参数是Notification的id,第二个参数是Notification的类。
以上功能实现后就可以发送通知了,不过通知不可点击。如果需要点击需要PendingIntent

注:PendingIntent和Intent的异同点:

  • 都可以指明一个意图,都可以用于启动活动,服务,以及发送广播。

  • Intent倾向于立即去执行某个动作,PendingIntent更加倾向在合适的时机去执行某个动作。

pendingIntent的使用方法:
使用静态方法获得PendingIntent的实例,getActivity()、getBroadcast()、getService()。

四个参数:content,0,Intent对象、0

Intent intent=new Intent(MainActivity.this,nextActivity.class);
PendingIntent pi=PendingIntent.getActivity(MainActivity.this,0,intent,0);

不能这个通知写在OnClickListener的匿名内部类

2、调用摄像头

private void camera() {
       /**
        * 首先创建了一个File对象,用于存放摄像头拍下的图片,这里将图像命名为outputImage.jpg,并将它存放在手机的关联目录下、
        * 接着进行一个判断,如果设备系统的版本低于7.0 的话就,就调用Uri的fromFile()方法将File转化为Uri对象,这个Uri对象标识着outputImage这张图片的真实路径,否则
        * 就调用FileProvider的geUriForFile()将File转化成一个封装过的Uri对象。
        */
       File outputImage=new File(Environment.getExternalStorageDirectory(),"output_image.jpg");
       try{
           if (outputImage.exists()) {
               outputImage.delete();
           }
           outputImage.createNewFile();
       } catch (IOException e) {
           e.printStackTrace();
       }
       if (Build.VERSION.SDK_INT>=24){
           imageUri= FileProvider.getUriForFile(MainActivity.this,"com.example.dimple.test619.fileProvider",outputImage);
       }else{
           imageUri=Uri.fromFile(outputImage);
       }
       Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
       intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);//填入指定的文件输出地址
       startActivityForResult(intent,TAKE_PHOTO);
   }
@Override
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
       switch (requestCode) {
           case TAKE_PHOTO: {
               if (resultCode == RESULT_OK) {
                   try{
                       Bitmap bitmap= BitmapFactory.decodeStream(getContentResolver()//将图片解析为bitmap对象
                               .openInputStream(imageUri));
                       picture.setImageBitmap(bitmap);
                   } catch (FileNotFoundException e) {
                       e.printStackTrace();
                   }
​
               }
           }
           break;
           default:
               break;
       }

因为用到了ContentProvider,所以需要在Manifest中注册

<provider
            android:authorities="com.example.dimple.test619.fileProvider"
            android:name="android.support.v4.content.FileProvider"
           android:exported="false"
           android:grantUriPermissions="true">
           <meta-data   //指定Uri的共享路径
               android:name="android.support.FILE_PROVIDER_PATHS"
               android:resource="@xml/file_paths"/>
        </provider>
    </application>
​
</manifest>

新建XML文件

    <?xml version ="1.0" encoding="utf-8" ?>
        <path xmlns:android="http://schemas.android.com/apk/res/android">
        <external-path name="my_images" path=""/>
    </path>  

3、播放音频

在Android中播放音频文件一般都是使用MediaPayer来实现的,它对多种格式的音频文件提供了非常全面的控制方法,使得音频播放比较简单。

方法名         功能描述          备注    
setDataSource()     设置要播放的文件的地址     
prepare()       在开始播放之前调用这个方法完成准备工作     
start()     开始播放视频      
pause()     暂停播放音频      
reset()     将Mediaplayer对象重置为刚开始创建的状态       
seekTo()        从指定的位置开始播放音频        
stop()      停止播放音频      
release()       释放掉与MediaPlyer相关的资源     
isPlaying()     判断当前MediaPlayer是否在播放        
getDuration()    获取之路的音频文件的时长   

4、播放视频

方法名            功能描述       备注    
setVideoPat()   设置要播放的视频文件的地址           
start()     开始或继续播放视频       
pause()     暂停播放视频      
resume()        将视频从头播放     
isPlaying()     是否正在播放      
getDuration()       获取时长    
seekTo()        从指定的位置开始播放  
XML中包含VideoView。
通过VideoView来进行操作。

第九章 使用网络技术

1、WebView 的用法

获取WebView的实例,通过getSetting()方法对浏览的相关属性进行设置。调用setJavaScriptEnabled()方法来让WebView支持JavaScript脚本。调用wenViewClient()方法。是希望网页依然在本程序中,不然就会跳转出去。

2、使用HTTP协议访问网络

首先开启一个子线程,在子线程中进行网络数据请求操作,获取HttpRULConnection实例。

URL url=new URL("https://www.baidu.com");
HttpURLConnection connection==(HttpURLConnection)url.openConnection();
connection.setConnectionTimeOut(8000);//设置链接超时
connection.setReadTimeOut(8000);//设置读取超时

之后再调用getInputStream()方法获取到服务器返回的流,然后进行流读取。

ImputStream in=connection.getInputStream();
//下面进行流读取
BufferedReader reader=new BufferedReader(new InputStreamReader(in));
String line;
StringBuilder builder=new StringBuilder();
while((line=reader.readerLine())!=null){
  builder.append(line);
}

最后关闭链接
connection.disconnect();

3、使用OkHttp

在app/build.grade中dependencies中添加如下内容:

compile 'com.squareup.okhttp3:okhttp:3.4.1'

具体使用步骤:
创建一个OkHttpClient实例

OkHttpClient client=new OkHttpClient();  

接下来如果需要发起一条Http请求,需要创建一个Request对象

Request request=new Request.Builder().build();  

以上代码创建了一个空的Request对象,没有什么实际作用,在build()方法之前加入很多连缀来丰富这个request对象,可以使用uri()方法来设置目标网络地址。

之后调用OkHttpClient的newCall()方法来创建一个Call对象,并调用它的execute()方法来发送请求并获得服务器的数据。

Response response=client.newCall(request).execute();

其中Resopnse就是服务器返回的数据了,以下方法可以得到具体的内容

String responseData=response.body().string();

发送数据:

首先需要构建出一个RequestBody对象来存放待提交的数据。

ResquestBody requestBody=new FormBody.Builder().add("username","admin").add("password","123456").build();

接下来就和Get请求一样了,调用execute()方法来获得服务器返回的数据。

4、解析JOSN数据

http://mobileapi.72g.com/index.php?tp=andv4/quan&op=qinfo

5、解析Json数据

首先配置服务器:电脑端访问网址为127.0.0.1 模拟器访问端网址:10.0.2.2

使用JsonObject:
首先将从服务器中的数据放在JSONArray中,然后循环遍历这个Json数组,从中取出的每一个元素都是JSONObject对象,调用getString()方法就可以取出数据。

               JSONArray jsonArray=new JSONArray(response);
                   for (int i=0;i<jsonArray.length();i++){
                       JSONObject jsonObject=jsonArray.getJSONObject(i);
                       Log.d("TAG", "Data :"+jsonObject.getString("name")+jsonObject.getString("id")+jsonObject.getString("version"));
                   }

使用Gson
首先需要添加依赖

   compile 'com.google.code.gson:gson:2.8.1'

Gson可以将一段Json格式的字符串自动映射成为一个对象,从而不需要我们编写代码进行解析。

比如:一段json格式的数据如下
{“name”:”Tom”,”age”:”20”}
我们可以定义 一个Person类,并加入name和age两个字段。只需要简单的调用如下代码就可以将JSON数据自动解析成一个Person对象了。

Gson gson=new Gson();
Person person=gson.fromJson(jsonData,Person.class)  

如果解析的是一段json数组就需要借助TypeToken将期望解析成的数据类型传入到fromJson中。

Gson gson=new Gson();
 List<App>appList=gson.fromJson(response,new TypeToken<List<App>>(){}.getType());
for (App app:appList){
  Log.d("TAG", "run: "+app.getId()+"\n"+app.getName()+"\n"+app.getVersion());
 }

定义Okhttp工具类

public class HttpUtility {
   public static void senOkHttpRequest(String address,okhttp3.Callback callback){
       OkHttpClient client=new OkHttpClient();
       Request request=new Request.Builder().url(address).build();
       client.newCall(request).enqueue(callback);
   }
}
​

在调用工具类的时候就这样写:

HttpUtility.senOkHttpRequest("http://10.0.2.2/me.json", new okhttp3.Callback() {
           @Override
           public void onFailure(Call call, IOException e) {
//                T网络请求失败"相关逻辑
           }
​
           @Override
           public void onResponse(Call call, Response response) throws IOException {
//                网络请求成功相关逻辑
               String responseData=response.body().string();
               showResponse(responseData);
           }
       });

第12章 Material Design

1、ToolBar代替ActionBar

 需要在Manifest中设置主题为NoActionBar

<android.support.v7.widget.Toolbar
       android:layout_width="match_parent"
       android:layout_height="?attr/actionBarSize"
       android:id="@+id/toolBar"
       android:background="@color/colorPrimary" />
Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar);
       setSupportActionBar(toolbar);

扩展:在ToolBar中添加其他控件
新建menu文件夹,在其中添加Menu resourse file,创建一个xml文件。

<item  
       android:id="@+id/delete"
       android:icon="@drawable/wujiaoxing"//指定按钮的图标
       android:title="@string/delete"//指定按钮的文字
       app:showAsAction="always" />//指定按钮的显示位置。always表示永远显示再ToolBar中,如果屏幕不够就不显示
                                   nerver表示永远显示再菜单项中,ifRoom表示屏幕空间足够的情况下就显示在ToolBar中,如果不够的话就显示在菜单项中。
​

在MainActivity中重写onCreateOptionMenu方法显示出menu,使用onOptionsItemSelected()方法来响应点击事件。

2、滑动菜单——DrawerLayout

首先它是一个布局,在布局中只允许放入 两个直接控件,第一个子控件是主屏幕显示的内容,第二个子控件是滑动菜单栏显示的内容。

使用

<android.support.v4.widget.DrawerLayout></android.support.v4.widget.DrawerLayout>

注意:

第二个子控件需要设置android:layout_gravity=”“,需要告诉DrawerLayout菜单是再屏幕的右边还是左边

android:layout_gravity="start"  

使用ToolBar的最左边加入导航按钮。

ActionBar actionBar=getSupportActionBar();//获取ActionBar的实例,这个实例的具体提现是由ToolBar来实现的。


       if (actionBar!=null){
           actionBar.setDisplayHomeAsUpEnabled(true);//显示导航键
           actionBar.setHomeAsUpIndicator(R.drawable.meiyuan);//设置导航键的图标。这个图标叫做HOMEAsUp
       }

在onOptionsItemSelected()方法来对HomeAsUp按钮的点击事件,HomeAsUp的id是
android.R.id.home

然后调用DrawerLayout的openDrawert()方法将滑动菜单显示出来。

3、NavigationView

NavigationView是DesignSupport库中提供的一个控件。

使用的时候需要添加闭包关系

   compile 'de.hdodenhof:circleimageview:2.1.0'
   compile 'com.android.support:design:26.0.0-alpha1'

在使用Navigation之前,需要准备两个东西,menu和headLayout

menu是在navigationView中显示菜单项的,headLayout是在NavigationView中显示头部布局的。

头部布局中使用circleImage来设置圆形头像。

设置完毕后在MainActivity中添加

<android.support.design.widget.NavigationView
       android:id="@+id/nav_view"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:layout_gravity="start"
       app:headerLayout="@layout/nav_header"
       app:menu="@menu/nav_menu" />

同时可以设置监听

public boolean onNavigationItemSelected(@NonNull MenuItem item)

4、悬浮按钮和可交互提示

悬浮按钮

添加FloatActionButton布局

       <android.support.design.widget.FloatingActionButton
           android:id="@+id/floatButton"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="bottom|end"
           app:elevation="8dp"设置悬浮高度
           android:layout_margin="10dp"
           android:src="@drawable/meiyuan" />

setOnClickListener可以设置点击事件

可交互提示:SnakeBar

   Snackbar.make(view,"Date Deleted",Snackbar.LENGTH_LONG)   //make方法创建了一个Snake对象,第一个 参数需要传入一个人View,只要是当前界面的任意一个View都可以,第二个参数是SnakeBar中显示的内容,第三个是显示的时长
                       .setAction("Un Do", new View.OnClickListener() {//调用setAction来设置一个动作,从而让SnakeBar不仅仅是一个提示,而是可以和用户进行交互的//第一个是按钮的名字,第二个是点击事件。
                           @Override
                           public void onClick(View view) {
                               Toast.makeText(MainActivity.this, "Un Do Successed!", Toast.LENGTH_SHORT).show();
                           }
                       }).show();

调用setAction来设置一个动作,从而让SnakeBar不仅仅是一个提示,而是可以和用户进行交互的//第一个是按钮的名字,第二个是点击事件。

出现界面重叠,需要使用CoordinatorLayout来替换掉FrameLayout,它可以监听所有子控件的所有事件,从而自动做出合理的响应。

5、卡片式布局

添加依赖:

   compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
   compile 'com.android.support:cardview-v7:26.0.0-alpha1'
   compile 'com.github.bumptech.glide:glide:4.0.0-RC1'

Glide是一个强大的图片加载库,它不仅可以加载本地图片,还可以加载网络图片,GIF图片,甚至是本地视频。

具体操作见recyclerView,只是将recyclerView 的子项布局的外层布局改为CardView

这种会将ToolBar遮盖,使用AppBarLayout
使用AppBarLayout包裹ToolBar,同时指定RecyclerView的布局行为

           app:layout_behavior="@string/appbar_scrolling_view_behavior"

同时还可以设置滑动隐藏
在toolBar中加入

               app:layout_scrollFlags="scroll|enterAlways|snap"

scroll表示RecyclerView向上滑动的时候,ToolBar会一起向上隐藏,enterAlways表示向下滚动的时候,ToolBar会同步显示。snap表示还没有完全隐藏的时候,会自动向上向下偏移。

6、下拉刷新

SwipeRefreshLayout就是用于下拉刷新的核心类。使用《swipeRefreshLayout》包裹需要下拉刷新的部件。

wipeRefresh.setColorSchemeResources(R.color.colorPrimary);
       swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
           @Override
           public void onRefresh() {
               refreshFuite();
           }
       });  

7、可折叠标题栏ColapsingToolbarLayout

colapsing不能独立存在,在设计的时候就只能用作AppBarLayout的直接子布局。而AppBarLayout又必须是CoordinatorLayout的子布局

DrawerLayout ——滑动菜单栏——只能拥有两个字节子布局(第一个是主屏幕的内容、第二个是滑动屏的内容)

NavigationView——滑动菜单栏滑动屏布局(需要headLayout、和menu布局 (showAsAction))——需要Design Support库

FloatActionButton——悬浮按钮

SnakeBar——提示工具

CoordinatorLayout——加强版的FrameLayout——监听子控件各种事件、自动做出合理的响应。防止控件重叠。

CardView_FrameLayout——提供圆角和阴影效果(cardCornerRadius指定卡片的弧度,elevation指定卡片的高度)

Glide——图片加载库

AppBarLayout——解决FrameLayout中的默认位置为左上角造成的遮挡ToolBar——将ToolBar嵌套到AppBarLayout(    app:layout_scrollFlags=”scroll|snap|enterAlways”),然后给重叠的部件指定布局行为behaver

SwipeRefreshLayout——下拉刷新——包裹需刷新的部件

CollapsingToolbarLayout——可折叠标题栏——不能独立存在只能作为AppBarLayout的直接子布局、AppBarLayout必须是coordinatorLayout的子布局

NestedScrollView——ScrollView——内部只能存在一个直接子布局

总结

以上就是我的Android学习过程中整理的一些东西,重新再整理了一遍,也算是重新学习了一次,在重新学习的过程中,还是发现有很多不足不周到的地方。温故而知新,自己还记录了很多笔记,趁现在还时间充裕,还会再好好温习一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值