1.隐藏状态栏:在Activity的onCreat中写
ActionBar actionBar=getSupportActionBar();
if (actionBar!=null){ actionBar.hide();}
2.布局的引入:在目标布局中加入
<include layout="@layout/title"/>
其中title为自定义布局文件
3.自定义控件
首先自定义控件title.xml文件
自定义控件内容自定义
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="BACK"
android:textColor="#fff"
android:layout_margin="5dp"
/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="XXXX"
android:textSize="24sp"
android:layout_weight="1"/>
<Button
android:id="@+id/item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="MUNE"
android:layout_margin="5dp"
android:textColor="#fff"/>
</LinearLayout>
然后在title.class中编辑:
public class title extends LinearLayout {
public title(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);//调取自定义布局文件
Button titleBack=findViewById(R.id.back);
Button titlemune=findViewById(R.id.item);
titleBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((Activity)getContext()).finish();//结束当前activity
}
});
titlemune.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(),"我是菜单!",Toast.LENGTH_SHORT).show();//提示
}
});
}
}
最后在需要用到的界面中添加自定义类的路径文件
<com.example.administrator.sendsmms.title
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/ss"/>
结束
二、更强大的滚动控件RecycleView
1.导入依赖库在app/build.gradle中的depencies闭包编写
implementation ‘com.android.support:recyclerview-v7:28.0.0’
2.在布局文件中加载该布局控件
<android.support.v7.widget.RecyclerView
android:id="@+id/recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
结束
三、网络连接使用开源库OKhttp
导入依赖库在app/build.gradle中的depencies闭包编写
implementation ‘com.squareup.okhttp3:mockwebserver:3.12.1’
首先需要创建一个OkhttpClient的实例
OkHttpClient client =new OkHttpClient();
接下来需要创建一个Request对象
Request request =new Request.Builder().build();
通过url()方法设置目标网络地址
Request request=new Request.Builder().url(“http://www.baidu.com”).build();
之后调用OKHttpClient的newCall()方法来创建一个Call对象,并调用它的execute()方法来发送请求并获取服务器返回的数据
Response reponse=client.newCall(request).execute();
其中Response对象就是服务器返回的数据了,我们可以使用如下写法来得到返回的具体内容:
String responseData=response.body().string();
如果发起的是post请求会比get请求复杂点,
我们需要先构建出一个requestBody对象来存放待提交的参数
RequestBody requestBody =new FormBody.Builder().add(“username”,”admin”).add(“password”,”123456”).build();
然后在RequestBuilder中调用一下post()方法,并将RequestBody对象传入
Request request =new Request.Builder().url(“http://www.baidu.com”).post(requestBody).build();
接下来的操作和Get方法都一样了
调取execute()方法来发送请求并获取服务器返回的数据即可。
注意:开启网络要开启子线程
new Thread(
new Runnable() {
@Override
public void run() {
try {
/*在这里编写网络操作*/
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder()
.url("http://www.baidu.com")
.build();
Response response=client.newCall(request).execute();
String responseData=response.body().string();
/*这里写显示到界面的操作提取responseData中的值*/
}catch (Exception e){
e.printStackTrace();
}
}
}
).start();
结束
四、解析json格式数据建议采用这两种方式JSONObject和GSON
1、JSONObject 方式
接上文拿到responseData数据结果
1.创建parseJson()方法传入responseData;如:parseJson(responseData);
2.编写方法:
private void parseJson(String jsonData) {
try {
JSONArray jsonArray=new JSONArray(jsonData);
for (int i=0;i<jsonArray.length();i++){
JSONObject jsonObject=jsonArray.getJSONObject(i);
String id=jsonObject.getString("id");
String name=jsonObject.getString("name");
String version=jsonObject.getString("version");
}
} catch (Exception e) {
e.printStackTrace();
}
}
2、GSON方式
1.导入依赖库在app/build.gradle中的depencies闭包编写
implementation 'com.google.code.gson:gson:2.8.5'
2.新建一个映射类将所需字段映射进去然后生成Getter/Setter下
3.创建parseGson()方法传入responseData;如:parseJson(responseData);
4.编辑方法
private void parseGson(String jsonData) {
Gson gson=new Gson();
List<app>appList=gson.fromJson(jsonData,new TypeToken<List<app>>(){}.getType());
for (app spp:appList){
Log.d("my", "id is: "+spp.getId());
Log.d("my", "name is: "+spp.getName());
Log.d("my", "version is: "+spp.getVersion());
}
}
结束
五、通常情况下我们都应该将这些通用的网络操作提取到一个公共的类里
这是OkHttpClient的方法更加简单明了
例如:
public class OkhttpUtil {
public static void sendOkHttpRequest(String address,okhttp3.Callback callback) {
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder()
.url(address)
.build();
client.newCall(request).enqueue(callback);
}
}
//okhttp3.Callback是这个OKHttp库中自带的一个回调接口
//调用enqueue方法的内部已经帮我们开好了子线程,然后会在子线程中去执行Http请求,并将最终的结果回调到okhttp3.Callback当中。
调用方法:
OkhttpUtil.sendOkHttpRequest("http://www.baidu.com",new okhttp3.Callback(){
@Override
public void onFailure(Call call, IOException e) {
//在这里对异常情况进行处理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//得到服务器返回的具体内容
String responseData =response.body().string();
}
});
结束
六、异步消息处理的使用方法由4部分组成:Message、Handler、MessageQueue和Looper
1.Message是在线程之间传递的消息,携带少量数据,用于不同线程之间交换数据。
2.Handler处理者,它主要用于发送和处理消息,发送消息一般是使用Handler的sendMessage()方法,最终会传递到Handler的handleMessage()方法中。
3.MessageQueue是消息队列,主要用于存放所有通过Handler发送的消息,会一直存在于队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
4.Looper是每一个线程中的MessageQueue的管家,调用Looper的loop()方法后就会进入无线循环当中,然后发现MessageQueue中存在一条信息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。
示意图:
更好的方法使用AsyncTask
结束
图片处理的依赖导入
implementation 'com.github.bumptech.glide:glide:3.8.0'
结束
使用ConvenientBanner 实现广告轮播,自动播放
<com.bigkoo.convenientbanner.ConvenientBanner
android:id="@+id/convenientBanner"
android:layout_width="match_parent"
android:layout_height="200dp"
app:canLoop="true"/>
结束
更新UI使用runOnUiThread直接刷新UI
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);//将Runnable Post到消息队列,由内部的mHandler来处理,实际上也是Handler的处理方式
} else {
action.run();//已经在UI线程,直接运行。
}
}
例:FusionField.currentActivity.runOnUiThread(new Runnable()
{
public void run()
{
Toast.makeText(getApplicationContext(), , "Update My UI",
Toast.LENGTH_LONG).show();
}
});
结束
数据库操作的开源库LitePal
1.导入依赖库在app/build.gradle中的depencies闭包编写
implementation ‘org.litepal.android:core:1.3.2’
2.新建目录,新建litepal.xml文件
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="cool_weather" />
//数据库名称
<version value="1" />
//数据库版本
<list>
<mapping class="com.coolweather.android.db.Province" />
<mapping class="com.coolweather.android.db.City" />
<mapping class="com.coolweather.android.db.County" />
</list>
//数据库建表
</litepal>
3.在主注册表中声明配置
<application
android:name="org.litepal.LitePalApplication"
......../>
4.升级数据库只需要version 的value+1就行,修改字段,只需修改Province类中的实例对象就行。
5.插入数据。
Province province = new Province();
province.setProvinceName(“张三”);
province.setProvinceCode(“18”);
province.save();
6.更新数据
更新为默认值:表名.setToDefault(“列名”);
再调用:表名.updataAll();
使用DataSupport.deleteAll(指定表名,指定条件);删除数据,条件参数为空时,删除表中所有数据。
7.查询数据
使用DataSupport.findAll(表名);返回的是一个List集合,所以不用自己一行行去取值。
List<Book> books=DataSuppot.findAll(Book.class);
for(Book book:books){
Log.d(“TAG”,”书名”,book.getName());
Log.d(“TAG”,”价格”,book.getPrice());
}
查询表中第一条数据:Book bookFirst=DataSupport.findFirst(Book.class);
查询表中最后一条数据:Book lastBook=DataSupport.findLast(Book.class);
结束
动态权限申请
危险权限需要动态申请
表中每个权限都属于一个权限组,我们在进行运行时权限授权的是权限名,但一旦用户同意授权了,该权限所对应的权限组下的所有其他权限也会同时被授权。
结束
ContentResolver内容提供者
写法:
Cursor cursor=getContentResolver().query{
Uri, //指定某个程序下的某一张表
Projection, //指定查询的列名,可以写为null
Selection, //指定where的约束条件,可以写为null
selectionArgs, //为where中的占位符”?”提供具体的值,可以写为null
sortOrder, //指定查询结果的排序方式,可以写为null
}
接收返回结果,使用游标遍历结果集
写法:
if(cursor!=null){
While(cursor.moveToNext){
String column1=cursor.getString(cursor.getColumnIndex(“column1”));
Int colmun2=cursor.getString(cursor.getColumnIndex(“column2”));
}
Cursor.colse();
}
添加数据:将待添加的数据组装到ContentValues中然后调用ContenResolver的insert()方法实现,将URI和ContentValues作为参数传入即可。
写法:
ContentValues values=new ContentValues();
values.put(“column1”,”text”);
values.put(“column2”,1);
getContentResolver().insert(uri,values);
更新数据
写法:
ContentValues values=new ContentValues();
values.put(“column1”,””);
getContentResolver().update(uri,values,”column1=? and column2=?”,new String[]{“text”,”1”});
删除数据
写法:
getContentResolver().delete(uri,”column2=?”,new String[]{“1”});
创建自己的内容提供器
创建:通过新建一个类去继承ContentProvider的方式来创建
ContentProvider中有6个抽象方法需要子类进行重写。
1.onCreate();
2.query();
3.insert();
4.update();
5.delete();
6.getType();
结束
通知
创建通知:调用Context的getSystemService()方法获取到NotificationManager。
getSystemService()方法接收一个字符串参数用于确定获取系统的哪个服务。
写法:
NotificationManager manager=(NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
创建Notification对象
写法:
Notification notification=new NotificationCompat.Builder(context).build();
现在创建的一个空的通知,我们需要在build()方法之前来丰富Notification对象。
Notification notification=new NotificationCompat.Builder(context)
.setContentTitle(“标题:通知”)
.setContentText(“内容:xxxxx”)
.setWhen(System.currentTimeMillis())//创建的时间
.setSmallIcon(R.drawable.small_icon)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.large_icon)).build()
显示通知,只需调用notify()方法就可以了
写法:manager.notify(1,notification);//第一个参数是id,第二个参数是Notification对象。
给通知加入点击功能
Intent intent=new Intent(this,No2.class);
PendingIntent pi= pendingIntent.getActivity(this,0,intent,0);
No....
.setContentIntent(pi)
.build();
让通知消失有两种方法
1.在build()方法前加 .etAutoCancel(true)。当点击了通知,就会自动消失。
2.在NotificationManager manager=(NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
Managet.cancel(1);//传入通知的id号
丰富的通知API
setSound()//播放音频文件
写法:
No....
.setSound(Uri.fromFile(new File(“/system/media/audio/luna.mp3”)))
.build();
setVibrate()//震动
写法:
No....
.setVibrate(new long[]{0,1000,1000,1000})//0延迟立即震动1s然后停止1s在震动1s
.build();
需要权限有:android.permission.VIBRATE
setLights()//LED灯提示
写法:
No....
.setLinghts(Color.GREEN,1000,1000)//绿色的灯光一闪一闪
.build();
setDefaults()//直接使用通知的默认效果
写法:
No....
.setDefaults(NotificationCompat.DEFAULT_ALL)
.build();
通知的高级用法
通过setStyle()方法可以实现富文本、图片、等内容
长文本的写法:
No....
.setStyle(new NotificationCompat.bigTextStyle().bigText(“长文本内容”))
.build();
图片的写法
No....
.setStyle(new NotificationCompat.BigPictureStyle().bigPicture
(BitmapFactory.decodeResource(getResources(),R.drawable.big_image)))
.build();
通知的重要程度
一共有5个常量可选:由低到高
PRIORITY_DEFAULT,
PRIORITY_MIN,
PRIOITY_LOW,
PRIORITY_HIGH,
PRIORITY_MAX,//最高的重要程度,必须要让用户立即看到,并做出响应操作
写法:
No...
.setPriority(NotificationCompat.PRIORITY_MAX)
.build();
结束
由于6.0以后读写SD卡需要进行运行时权限处理才行,所以为了跳过该步骤可以使用调用应用关联缓存目录使用getExternalCacherDir()方法,来处理临时存储。
写法:
File myImage= new File(getExternalCacheDir(),”myImagr.jpg”);
读取SD卡动态权限申请
写法:
public void onClick(View v){
if(ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) !=PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(MainActivity.this,new
String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
}else{
openAlbum();//打开SD的相应操作
}
@Override
public void onRequestPermissionsResult(int requestCode,String[]permissions,
int[]grantResults){
swith(requestCode){
case 1:
if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
openAlbum();
}else{
Toast.makeText(this,”你拒绝了许可”,Toast.LENGTH_SHORT).show();
}
Break;}
WRITE_EXTERNAL_STORAGE表示同时授予程序对SD卡读写的能力。
READ_EXTERNAL_STORAGR表示SD卡读取权限
结束
播放音频:MediaPlayer()方法
获取音频文件路径:
写法:
private void initMediaPlayer(){
try{
File file =new File(Environment.getExternalStorageDirectory(),”music.mp3”);
mediaPlayer.setDataSource(file.getPath());//指定音频文件路径
mediaPlayer.perpare();//让MediaPlayer进入准备状态
}catch(Exception e){ e.printStackTrace();}
}
最后需要在onDestroy()方法中调用stop()方法和release()方法,将MediaPlayer相关的资源释放掉。
写法:
@Override
protected void onDestroy(){
super.onDestroy();
if(mediaPlayer!=null){
mediaPlayer.stop();
mediaPlayer.release();
}
}
播放视频:VideoView()方法
获取视频文件路径:
写法:
public initCIdeoPath(){
File file =new File(Environment.getExternalStorageDirectory(),”movie.mp4”);
videoView.setVideoPath(file.getPath());//指定视频文件路径
}
最后需要在onDestroy()方法中调用suspend()方法,将VideoVIew所占用的资源释放掉。
写法:
@Override protected void onDestroy(){ super.onDestroy(); if(videoView!=null){ videoVIew.suspend(); } }
结束
Retrofit网络框架封装
添加依赖:
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
implementation 'com.squareup.retrofit2:retrofit:2.0.2'
添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
创建接收服务器返回数据的类
public class News {
// 根据返回数据的格式和数据解析方式(Json、XML等)定义
...
}
创建用于描述网络请求的接口
public interface APi {
// @GET注解的作用:采用Get方法发送网络请求
// getNews(...) = 接收网络请求数据的方法
// 其中返回类型为Call<News>,News是接收数据的类(即上面定义的News类)
// 如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call<ResponseBody>
@Headers("apikey:81bf9da930c7f9825a3c3383f1d8d766")
@GET("word/word")
Call<News> getNews(@Query("num") String num,@Query("page")String page); }
创建Retrofit对象
写法:
Retrofit retrofit=new Retrofit.Builder()
//设置数据解析器
.addConverterFactory(GsonConverterFactory.create())
//设置网络请求的URL地址
.baseUrl(“http://apis.baidu.com/txapi”)
.build();
//创建网络请求接口的实例
mApi=retrofit.create(APi.class);
发起网络请求
写法:
//对发送请求进行封装
Call<News> news=mApi.getNews(“1”,”10”);
//发送网络请求(异步)
news.enqueue(new Callback<News>(){
@Override
public void onResponse(Call<News> call,Response<News> response){
//请求处理,输出结果
Response.body().show();
}
@Override
public void onFailure(Call<News> call,Throwable t){
//请求失败时的回调
}
})
结束
RxAndroid 的基本使用
添加依赖:
implementation 'io.reactivex.rxjava2:rxjava:2.2.5'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
1,初始化被观察者对象,并将对象发送出去
Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
@Override
//将事件发射出去,持有观察者的对象
public void subscribe(ObservableEmitter<String> e) throws Exception {
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
e.onNext("第一次调用");
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
e.onNext("第二次调用");
try {
Thread.sleep(1000);
} catch (Exception ee) {
}
e.onNext("第三次调用");
e.onComplete();
}
});
2,观察者执行
observable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.newThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String value) {
Toast.makeText(MainActivity.this,value, Toast.LENGTH_SHORT).show();
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() { }
});