Android知识学习总结
android四大组件:
1、活动(Activity)
2、广播(Broadcast)3、服务(Service)4、内容提供器(ContentProvider)四大组件的超类都是ContextActivity
包含用户界面的组件,主要用于和用户进行交互
状态:运行状态、暂停状态、停止状态、销毁状态
生命周期:
onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()
onRestart()
启动模式:
standard
singleTop
singleTask
singleInstance
在AndroidMenifest.xml中设置activity的属性可以更改它的启动模式 (android:launchMode=””)活动间传递数据:Intent显式IntentIntentintent = new Intent(A.this, B.class);
startActivity(intent);
隐式Intent<activity...>
<intent-filter>
<actionandroid:name=”a”/>
//默认的<categoryandroid:name=”android.intent.category.DEFAULT”/>
</intent-filter>
</activity>
Intentintent = new Intent(“a”);
startActivity(intent);
<activity...>
<intent-filter>
<actionandroid:name=”a”/>
<categoryandroid:name=”android.intent.category.DEFAULT”/>
<categoryandroid:name=”b”/>
</intent-filter>
</activity>
Intentintent = new Intent(“a”);
intent.addCategory(“b”);
startActivity(intent);
//调用系统浏览器(其他程序的活动)Intentintent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(“http://www.baidu.com”));
startActivity(intent);
//跳至系统拨号页面Intentintent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(“tel:10086”));
startActivity(intent);
传数据:putExtra(key,value);接收:getStringExtra()getIntExtra() getBooleanExtra()向上一个活动返回数据:
Intentintent = new Intent(A.this, B.class);
startActivityForResult(intent,1);
在A中重写onActivityResult(),B被销毁后会回调上一个活动即A的onActivityResult()利用Intent传对象Bundlebundle = new Bundle();
bundle.putSerializable(“user”,user);
intent.putExtras(bundle);
接收:
Useruser = intent.getSerializableExtra(“user”);
或者
Bundlebundle = new Bundle();
bundle.putSerializable(“list”,(Serializable)list);
intent.putExtras(bundle);
接收:
List<User>list = intent.getSerializableExtra(“list”);
Broadcast
标准广播Normalbroadcasts完全异步执行的广播,广播一发出sendBroadcast(..), 所有的广播接收器几乎会在同一时刻接收到这条广播消息, 效率较高,无法被截断有序广播Orderedbroadcasts同步执行的广播,广播发出后sendOrderedBroadcast(..), 优先级高的先收到广播,可以在AndroidMenifest 中对应的<receiver>标签中设置优先级<intent-filterandroid:priority=10>,默认为0, 值越大优先级越高,范围是[-1000,1000],前 面的广播接收器收到后还可以截断该广播abortBroadcast()。广播接收器注册广播(定义自己能收到的广播是什么):在AndroidMenifest.xml中,对于每一个广播接收器都会进行注册,即<receiver>标签。动态注册及发送
先写个广播接收器,eg:...class NetworkChangeReceiver extends BroadcastReceiver 重写onReceive()然后在代码中注册(一般在初始化代码里):
IntentFilterintentFilter = new IntentFilter();
intentFilter.addAction(“Broadcast1”);
NetworkChangeReceivernetworkchangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkchangeReceiver,intentFilter);
注意:动态注册的广播接收器要在onDestroy()中注销unregisterReceiver(networkchangeReceiver)发送Intentintent = newIntent(“Broadcast1”);sendBroadcast(intent);后,会回调 接受该广播的广播接收器的onReceive()方法。 如果发送的是有序广播sendOrderedBroadcast(),可以在onReceive()里实现广播截断。静态注册及发送:
如果要静态注册该广播接收器想要接收的广播,可以在<receiver>标签里添加<intent-filter> 标签,并在其中添加<action、<category等属性。发送如上
动态及静态注册的区别:动态注册的广播接收器可以自由的控制注册和注销,灵活性较好,但是它必须 要在程序启动之后才能接收到广播,而静态注册在 程序未启动的情况下就可接收到广播。
关于本地广播
为了解决广播的安全性问题,使用本地广播机制发送的广播只能在本应用程序内部进行传递,并且广播 接收器也只能接收来自本应用程序发出的广播。
代码与动态注册广播并发送的代码几乎一样,只是用LocalBroadcastManager来对广播进行管理。 (本地广播不能用静态注册的方式接收)LocalBroadcastManagerlocal = LocalBroadcastManager.getInstance(this);
…local.sendBroadcast(intent);
local.registerBroadcast(广播接收器实例,intentFilter);local.unregisterBroadcast(广播接收器实例);优势:
可以明确的知道正在发送的广播不会离开我们的程序,不用担心机密数据泄露的问题
其他的程序无法将广播发送到我们程序的内部,因此不需要担心会有安全漏洞的隐患
发送本地广播比发送系统广播更高效
Service
适于执行不需要和用户交互但又要求长期运行的任务。
服务的运行不依赖于任何用户界面,依赖于创建服务时所在的应用程序进程
异步消息处理机制
Message、Handler、MessageQueue、Looper、AsyncTaskHandler主要用于发送和处理消息,发送:Handler的sendMessage(Messagemsg)方法,消息会 传到Handler的handleMessage()中。MessageQueue主要用于存放所有通过Handler发送的消息Looper是每个线程中MessageQueue的管家,每当发现MessageQueue里存在一条消息,就会将它 取出,并传到Handler的handlerMessage()方法中。异步消息处理流程:
先创建一个Handler对象,并重写handlerMessage()方法,当子线程中需要进行UI操作时,就创 建一个Massage对象,并通过Handler将消息发出去, 之后这条消息会被添加到MessageQueue的队列中等待被处理,然后Looper会一直尝试从队列中取出 待处理消息,分发到Handler的handlerMessage中 进行处理。AsyncTask是一个抽象类,需要创建子类去继承它,继承时可以为AsyncTask类指定三个泛型参数Params执行AsyncTask时需要传入的参数,可用于在后台任务中使用;Progress后台任务执行时,若需要在界面上显示当前的进度,则使用这里的泛型作为进度单位;Result当任务执行完毕后,若需要对结果进行返回,则使用这里指定的泛型作为进度单位以上三个参数的可取值为:Integer、void、Boolean等泛型该子类还需要重写以下几个方法才能完成对任务的定制
onPreExecute():
在后台任务开始执行前调用,用于进行一些页面上的初始化操作,比如显示一个进度条对话框
doInBackground(Params…):
该方法的所有代码都在子线程中运行,用于处理所有的耗时任务,任务一旦完成就可通过return语句 来将任务的执行结果返回,如果第三个泛型参数为 void,就可以不用返回任务执行结果,该方法中不能进行UI操作,如果有UI元素需要更新,就可以在 方法中调用publishProgress(Progress...) 来完成onProgressUpdate(Progress…)
当后台调用了publishProgress(Progress...)方法后,该方法很快也会被调用,在该方法中可 以对UI进行操作onPostExecute(Result):
当任务执行完毕并通过return语句进行返回时,该方法就很快会被调用,返回的数据会作为参数传 到该方法中,可以进行UI操作使用AsyncTask:启动AsyncTask:子类实例对象.execute()在doInBackground()中执行具体的耗时操作,在里面调用publishProgress()方法进入 onProgressUpdate(),在onProgressUpdate()中执行 UI操作,在onPostExecute()中执行一些任务的收尾工作Service的基本用法抽象类,需要用子类实现它,Service有一个唯一的抽象方法onBind(),服务常用的三个方法: onCreate()服务创建时调用、onStartCommand()每次服务启动时调用、onDestroy()服务 销毁时调用。服务的启动和停止:
借助Intent,intent= new Intent(this, MyService.class);开始:Activity中调用startService(intent);停止:由活动控制Activity中调用stopService(intent);由自己控制Service中调用stopSelf();可以借助onBind()来加深活动与服务的联系,活动指挥服务MyService中:创建一个Binder对象:用一个子类MyBinder继承Binder,写自己的逻辑方法, onBind()里返回这个Binder对象。Activity中:创建ServiceConnection匿名类,重写onServiceConnnected()和 onServiceDisconnected(),分别在活动与服务成功绑定及 连接断开时调用。privateServiceConnection connection = new ServiceConnection(){
//重写onServiceConnnected()和onServiceDisconnected()……//onServiceConnnected()可以将参数IBinder对象向下转型为MyBinder对象,就可以调用 //MyService.MyBinder中的方法了}
…通过bindService(intent,connection, xxx)绑定服务xxx可以为BIND_AUTO_CREATE,表示活动与服务绑定后自动创建服务。通过unbindService(connection)断开连接每个服务在整个应用程序内都是通用的,可以和多个活动绑定。
服务的生命周期:
调用startService()后,服务启动,回调onStartCommand(),如果该服务之前并未被创建, onCreate()会先于onStartCommand()执行, 一直到调用stopService()或stopSelf(),服务停止。调用bindService()后,回调onBind(),如果该服务之前并未被创建,onCreate()会先于 onBind()执行,只要连接没有断开,服务就会一直 处于运行状态。调用bindService()之后调用了unbindService(),onDestroy()会被调用;调用 startService()之后调用了stopService(),onDestroy()会被调用;如果bindService() 与startService()都被调用了,则只有unbindService()与stopService()都被调用之后, onDestory()才会被执行。服务的更多技巧
前台服务
Intentintent = new Intent(this, MainActivity.class);
PendingIntentpi = PendingIntent.getActivity(this, 0, intent, 0);
Notificationnotification = new NotificationCompat.Builder(this)
.setContentTitle(“title”)
.setContentText(“text”)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResources(), R.mipmap.ic_launcher)
.setContentIntent(pi)
.build();
startForeground(1,notification);
IntentService:异步的、会自动停止的服务。抽象类,需要一个子类继承它,构造方法中,需要实现父类的有参构造方法,实现onHandleIntent() 抽象方法
ContentProvider
运行时权限:
Android中危险权限共9组24个,需要用户手动授权才能启用,我们在进行运行时权限处理时使用的 是具体的权限名,但是用户一旦同意授权了, 那么该权限所在的一个权限组中所有的其他权限也会同时被授权eg:拨打电话Intent.ACTION_CALL需要声明权限首先在AndroidMenifest.xml中,声明权限 <uses-permissionandroid:name=”android.permission.CALL_PHONE”>在低于Android6.0系统的手机上就可以了,但6.0及更高版本的手机上会报错: PermissionDenial,需要对权限进行处理例如调用系统对话框申请权限:
if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission. CALL_PHONE) !=PackageManager.PERMISSION_GRANTED){
//系统对话框,请求权限,输入一个请求码(固定值)ActivityCompat.requestPermission(MainActivity.this,new
String[]{Mainifest.permission.CALL_PHONE},1);
}
else{
call();
}
…//ActivityCompat.requestPermission()的回调函数publicvoid onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
switch(requestCode){
//请求码case1:
//请求赋权结果存放在grantResults数组里if(grantResults.length > 0&& grantResults[0] ==
PackageManager.PERMISSION_GRANTED){
call();
}
else{
Toast.makeText(this,“You denied the
permission”,Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
跨程序访问数据
ContentResolver的基本用法:每个应用程序要想访问内容提供器中共享的数据,一定要借助ContentResolver类,可以通过 Context中的getContentResolver() 方法获取该类实例。ContentProvider中的增删改查方法均不接受表名参数,使用一个唯一的uri参数代替,即内 容uri,由authority及path组成, authority对不同的应用程序做区分,path对不同的表做区分,内容URI格式例子: content://com.example.app.provider/table1内容URI字符串需要通过Uri.parse(“内容uri字符串”)被解析成uri对象一般通过URI判定是用的自定义的Provider还是利用的现有的Provider,因为自定义的Provider 会在Menifest文件中注册,并声明 anthorities属性,uri若是系统封装好了的,则使用的现有的Provider,若是自定义的uri,则 必有对应的Provider被定义。Cursorcursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
if(cursor!= null) {
where(cursor.moveToNext){
Stringcolumn1 = cursor.getString(cursor.getColumnIndex(“column1”));
intcolumn2 =
cursor.getInt(cursor.getColumnIndex(“column2”));
Log.d(“aaaaa”, column1 +“, ” + column2);
}
}
CotentValuesvalues = new ContentValues();
values.add(“column1”,”text”);
values.add(“column2”,“1”);
getContentResolver().insert(uri,values);
ContentValuesvalues = new ContentValues();
values.put(“column1”,“aaaa”);
getContentResolver().update(uri,values, “column1 = ? and column2 = ?”, new String[]{“text”,“1”});
getContentResolver().delete(uri,“column2 = ?”, new String[]{“1”});
创建自定义内容提供器
新建一个类继承ContentProvider来创建自己的内容提供器,实现它的6个抽象方法:onCreate()
只有当ContentResolver尝试访问我们程序中的数据时,内容提供器才会被初始化query(uri, projection, selection, selectionArgs, sortOrder)
调用db.query()来查询,将查询结果放在cursor中返回insert(uri, contentValues)
添加成功后,返回一条用于表示这条新记录的URIupdate(uri, contentValues, selection, selectionArgs)
返回受影响的行数
delete(uri, selection, selectionArgs)
返回被删除的行数
getType(uri)
返回对应的MIME类型(String)MIME字符串:@ 1必须以vnd开头@ 2 若内容uri以路径结尾,则后接android.cursor.dir,若以id结尾,则接 android.cursor.item/@ 3 最后接上vnd.authority.path内容uri还可以在以路径结尾的内容uri上添加一个id,表示期望访问该表中id为多少的数据。 Eg:……app.provider/table2/1或者也可用通配符来匹配以路径结尾或以id结尾的这两种格式。Eg:…… app.provider/*匹配任意表的URI格式(*匹配任意长度的任意字符)……app.provider/table1/#匹配table1表的任意行数据(#表示匹配任意长度的数字)利用UriMatcher类实现匹配内容URI的功能uriMatcher.addURI(authority,path,自定义代码)eg:…… static final int TABLE_ITEM = 0;……
UriMatcheruriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(“com.example.app.provider”, “table/#”, TABLE_ITEM);
通过uriMatcher.match(uri)来获取对应的自定义代码数据存储
文件存储:存储一些简单的文本数据或二进制数据
SharedPreferences存储:存储一些较为复杂的文本数据SQLite数据库存储:存储一些复杂的关系型数据文件存储:
openFileOutPut(“文件名”,文件操作模式)写出数据到文件中文件名不可包含路径,所有文件均默认存储到/data/data/<packagename>/files/目录下文件操作方式默认为MODE_PRIVATE,即当指定同样文件名时,会覆盖掉原文件中的内容, MODE_APPEND表示如果该文件已存在则在该文 件中追加,不存在就创建新文件Stringdata = “this is data to write”;
FileOutputStreamout = null;
BufferdWriterwriter = null;
out= openFileOutPut(“file1”, Context.MODE_PRIVATE);
writer= new BufferdWriter(new OutputStreamWriter(out));
writer.write(data);
openFileInPut(“文件名”)从文件中读进数据FileInputStreamin = null;
BufferdReaderreader = null;
StringBuildercontent = new StringBuilder();
in= openFileInput(“file1”);
reader= new BufferdReader(new InputStreamReader(in));
Stringline = “”;
while((line= reader.readLine()) != null) {
content.append(line);
}
SharedPreferences存储采用键值对方式存储数据,支持多种不同的数据类型
SharedPreferences文件都存放在/data/data/<packagename>/shared_prefs/目录下, SharedPreferences文件使用XML格式来对数据进行管理写数据:
1、先得到SharedPreferences对象;Context类中的getSharedPreferences()方法、Activity类的getPreferences()方法、 PreferencesManager类中的getDefaultSharedPreferences()方法。2、然后调用SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象;3、向SharedPreferences.Editor对象中添加数putBoolean()、putString();4、调用apply()将添加的数据提交SharedPrefernces.Editoreditor = getSharedPreferences(“share1”,MODE_PRIVATE).edit();//只有一种操作模式,也是默认模式,传入0效果一样editor.putString(“name”,“Tom”);
editor.putInt(“age”,12);
editor.putBoolean(“married”,false);
editor.apply();
读数据:
1、先得到SharedPreferences对象;Context类中的getSharedPreferences()方法、Activity类的getPreferences()方法、 PreferencesManager类中的 getDefaultSharedPreferences()方法。2、通过SharedPreferences对象的get方法获取文件中的内容getString(key),getInt(key)……SharedPreferncespref = getSharedPreferences(“share1”,MODE_PRIVATE);Stringname = pref.getString(“name”);
intage = pref.getInt(“age”);
booleanmarried = pref.getBoolean(“married”);
SQLite数据库存储新建一个类MyDatabaseHelperextends SQLiteOpenHelper帮助类,实现onCreate()和onUpgrade()抽象方法,有两个构造方法可供重写,一般选择参数少的重写, SQLiteOpenHelper还有两个实例方法,getReadableDatabase()、getWritableDatabase(), 这两个方法都可以创建或打开一个现有的数据库,并返回一个可对数据库进行读写操作的对象,当数据库 不可写入时,getReadableDatabase()返回的对象将以只读方式去打开数据库,而 getWriteableDatabase()将会出现异常。创建表
real浮点型 blob二进制类型Stringcreate_book = “create table Book (id integer primary keyantoincrement, author text, price real, pages integer)”;
Stringcreate_category = “create table Category (…… )”;
………… onCreate(SQLiteDatabase db){
db.execSQL(create_book);db.execSQL(create_category);…… }
…… onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion){ db.execSQL(“drop table ifexists Book”); db.execSQL(“drop table ifexists Category”);
onCreate(db);}
添加数据
privateMyDatabaseHelper dbHelper;
……SQLiteDatabasedb = dbHelper.getReadableDatabase();
ContentValuesvalues = new ContentValues();
values.put(key,value);…… //key列名 value值
db.insert(“表名”,null, values);values.clear(); //清空valuesvalues.put(key,value);…… //继续添加db.insert(“表名”,null, values); //第二个参数用于在未指定添加数据的情况下给某些可 为空的列自动赋值null,一般赋null
更新数据
db.update(“表名”,ContentValues对象,selections, selectionArgs);
//values可以只有一个或几个列的值
SQLiteDatabasedb = dbHelper.getReadableDatabase();
ContentValuesvalues = new ContentValues();
values.put(“price”,12.34);
db.update(“Book”,values, “name = ?”, new String[]{“The First Book”});
删除数据
db.delete(“表名”,selections, selectionArgs);
db.delete(“Book”,“page > ?”, new String[]{“500”});
查询数据
db.query(“表名”,columns, selection, selectionArgs, groupBy, having, orderBy);
Cursorcursor = db.query(“Book”, null,null,null,null,null,null);
if(cursor.moveToFirst){
do{
Stringname =
cursor.getString(cursor.getColumnIndex(“name”));
……getDouble()、getInt()}while(cursor.moveToNext());
}
cursor.close();
使用SQL操作数据库db.execSQL(“insertinto Book (name, author, …… )values(?,?,……)”, new String[]{“TheFirst Book”, “Tom”, ……});db.execSQL(“updateBookset price = ? where name = ?”, new String[] {“12.34”, “TheFirst Book”});
db.execSQL(“deletefromBook where page > ?”, newString[]{“50”});
db.rawQuery(“select* from Book”, null);
拓展:
getClass.getSimpleName()获取当前实例的类名getTaskId()获取返回栈的Id,Activity都被放在返回栈中。UI相关重写onBackPressed()可以自定义Back建的功能imageview.setImageResource() 设置ImageView的背景图片setVisibility();设置控件是否可见(android:vidibility)visible可见 invisible不可见但占空间 gone不可见且不占空间进度条:ProgressBar默认为圆形style=”?android:attr/progressBarStyleHorizontal”可设为水平进度条 android:max设最大值,setProgress()、getProgress()AlertDialog、ProgressDialog可在界面上弹出一个对话框,ProgressDialog会在对话框中 显示一个进度条,表示当前操作比较耗时, 请用户耐心等待progressDialog.setCancelable(false)表示按back键不能取消,须在代码中控制:当数据 加载完后调用ProgressDialog的dismiss() 来关闭对话框,否则progressDialog将会一直存在。4种基本布局: 线性布局LinearLayout、相对布局RelativeLayout、百分比布局(PercentFrameLayout/ PercentRelativeLayout)、帧布局(FrameLayout)百分比布局: 要在app/build.gradle的dependencise闭包里添加百分比布局的依赖库 (compile‘com.android.support:percent:24.2.1’),在xml布局里可以 <android.support.percent.PercentFrameLayout..android:heightPercent=”10%” android:widthPercent=”20%”
引入布局: <includelayout=”@layout/布局文件名”隐藏系统自带标题栏:
ActionBaractionbar = getSupportActionBar();
if(actionbar!= null){ actionbar.hide(); }
android:inputType属性用来设置文本的类型,用于帮助输入法显示合适的键盘类型。android:inputType="取值如下"textEmailSubject 邮件主题textShortMessage 短信息(会多一个表情按钮出来)textLongMessage 长讯息textPersonName 人名textPostalAddress 地址textPassword 密码 textVisiblePassword 可见密码datetime时间日期 date日期 time时间android:inputType="phone" 拨号键盘android:inputType="textCapWords" 单词首字母大小 android:inputType="textCapSentences" 仅第一个字母大小android:inputType="number" 数字格式 android:inputType="numberSigned" 有符号数字格式 android:inputType="numberDecimal" 可以带小数点的浮点格式 android:inputType="phone" 拨号键盘EditText
mEditText.setSelection(intindex);设置光标的位置Button
mButton.setEnabled(false);按钮元素不可见
《第一行代码》学后知识小总结
最新推荐文章于 2022-09-28 09:53:38 发布