第一行代码(安卓)
Kotlin
1.变量
用var 创建变量

2.函数

如果函数的返回值只有一句,那么可以使用Kotlin的语法糖,省略写法

3.逻辑控制语句
1) if条件语句
普通写法

精简1

精简2

精简3

2)when条件语句
带参写法
| when(传入的参数){ 匹配值 -> {执行逻辑} }
|

允许类型匹配

不带参写法

3)循环语句

循环体内的关键字

4.函数
定义
| private fun doSomething(age:Int,flag:Boolean):String{ return "result" }
|
函数默认参数
也就是在函数没有传入参数的时候,默认使用的值
| private fun fix(name:String = "jack",age: Int = 5){ println(name+"-----"+age) }
|
具名函数
也就是在调用函数的时候,传入的参数可以指定参数的名字传进去

函数无返回值时
Kotlin没有返回值就是uint
Nothing也可以是无返回值
反引号函数名
可以用反引号包裹特殊的函数名,一般用于测试

匿名函数
无参匿名
在{}内可以用lamada表达式对函数进行操作
| val totals = "sadadagsdffgdfsgsd".count({ it -> it == 's' })
|
有参匿名

it关键字

函数类型推断
无参

有参

定义参数是函数的函数

函数引用


函数类型作为返回类型

5.类与对象
新建一个类

创建一个对象

继承与构造方法

init结构体
对变量进行初始化
接口
统一使用冒号进行实现


数据类
Java中需要重写toString equals等方法
在Koltin中只需要一个data关键字

单例类

6.容器
List集合
创建

其他写法
不可变集合(不能改变集合的长度)

可变集合的创建

Set集合

Map集合

遍历

函数式API

空指针检查
在变量的类型后加?
代表这个变量可为空


判空辅助工具
不可空操作符
?. 的用法

空合并操作符
?: 的用法

非空断言工具

let函数

7.异常

8.数据类型
字符串类型
字符串遍历

字符串分割

数字类型
安全转换函数

四舍五入转换

apply函数

let函数

换句话说,就是谁调用let,it就指代的是谁
| "testLet".let { println(it) println(it) println(it) return 1 }
|
let,apply,with,run函数区别
let
默认当前对象闭包的 it 参数,返回值是函数里面最后一行,或者指定return
| fun testLet():Int { "testLet".let { println(it) println(it) println(it) return 1 } }
|
apply
调用某对象的 apply 函数,在函数范围内,可以调用该对象的任意函数,返回值是该对象。
| fun testApply() { ArrayList<String>().apply { add("apply1") add("apply2") add("apply3") }.let { print(it) } }
|
with
返回值是最后一行,函数范围中可以调用对象方法。像 let 和 apply 结合
| fun testWith() { with(ArrayList<String>()) { add("testWith") add("testWith") add("testWith") this }.let { println(it) } }
|
run
run函数和apply函数很像,只不过run函数是使用最后一行的返回,apply返回当前自己的对象。
| fun testRun() { "testRun".run { println("this = " + this) }.let { println(it) } }
|
Android
Activity
设置主启动Activity

在Activity中使用Toast

1.新建一个menu布局文件

2.重写onCreateOptionsMenu方法

3.重写onOptionsItemSelected方法

销毁一个Activity
调用finish()方法销毁
使用Intent在Activity之间跳转
显示Intent跳转

隐式跳转Intent
在AndroidManifest.xml中定义Activity的Action和Category属性
通过隐式调用intent会自动匹配合适的Action和Category


向下一个Activity传递数据


Activity生命周期
启动一个新的活动。入栈,并处于栈顶。
销毁一个活动时,栈顶活动出栈。
系统总是会显示处于栈顶的活动给用户,即栈顶活动可见。
Activity状态
运行状态
一个活动位于栈顶时,这活动处于运行状态。
暂停状态
一个活动不处于栈顶位置,但仍然可见时,这活动处于暂停状态。活动完全存活着。(比如栈顶活动为对话框形式)
停止状态
一个活动不处于栈顶位置,且完全不可见,这活动处于停止状态。(还在栈中)
销毁状态
一个活动从栈中移除后,这活动处于销毁状态。
Activity的生存期
Activity的七个回调方法
onCreate()
活动第一次被创建的时候调用,在该方法中完成初始化操作,加载布局、绑定事件等。
onStart()
由不可见变为可见的时候调用。(非栈顶到栈顶)
onResume()
在活动准备好和用户交互的时候调用。(栈顶)
onPause()
准备去启动或恢复另一个活动时调用。
onStop()
在活动完全不可见时调用。
onDestroy()
在活动被销毁前调用。完成释放内存操作。
onRestart()
在活动由停止状态变为运行状态前调用。
除onRestart()外,其他两两对应,活动分为三种生存期:
完整生存期
onCreate()和onDestroy()之间所经历的,就是完整生存期。
可见生存期
onstart()和onStop()之间所经历的,就是可见生存期。
前台生存期
onResume()和onPause()之间所经历的,就是可见生存期。
Activity的几种启动模式
standard:默认为标准模式,每次启动一个活动都会创建一个新的实例
singletop:如果启动的活动在栈顶,则不创建新的实例,但不在栈顶会
创建新的实例。
singTask:每次启动活动时都会检查返回栈中是否已有该活动的实例,如果有则将其上面的活动出栈。使得该活动处于栈顶。不在创建实例。
singleInstance:创建一个新的返回栈来管理这个活动,达到在多个应用程序中共享这个活动的实例。
UI
常用控件
TextView
常用属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <TextView //指定控件的id android:id="@+id/text1" //控件的宽度 match_parent 为占满整个父控件 wrap_content为包裹内容 android:layout_width="match_parent" //控件的高度 match_parent 为占满整个父控件 wrap_content为包裹内容 android:layout_height="wrap_content" //控件内展示的文本 android:text="传递的数据" //控件内展示的文本的字体大小 android:textSize="18sp" //控件内展示的文本的字体样式 android:textStyle="bold" //控件内展示的文本的字体颜色 android:textColor="@color/teal_700" //android:gravity 组件的子组件在组件中的位置 android:gravity="center"/> //android:layout_gravity 组件自身在父组件中的位置
|
同上
| android:textAllCaps="false" //默认button上的英文会以大写的方式展示,设置为false就保留原始文字内容展示
|
EditText
同上
| <EditText android:layout_width="match_parent" android:layout_height="wrap_content" //指定输入框提示性的文字 android:hint=""/>
|
ImageView
同上
ProgressBar
同上
特殊属性
| <ProgressBar android:id="@+id/progress" android:layout_width="match_parent" android:layout_height="wrap_content" style="?android:progressBarStyleHorizontal"//更改进度条样式,使用水平进度条 android:max="100"//进度条最大长度 />
|
显示隐藏进度条/加快进度条

AlertDialog对话框
| val button: Button = findViewById(R.id.AlertDialogBtn) button.setOnClickListener { val builder = AlertDialog.Builder(this) builder.setTitle("弹窗的标题") builder.setMessage("弹窗消息") builder.setCancelable(false) builder.setPositiveButton("OK") { dialog, which -> Toast.makeText(this, "点击了OK", Toast.LENGTH_SHORT).show() } builder.setNegativeButton("Cancel") { dialog, which -> Toast.makeText(this, "点击了OK", Toast.LENGTH_SHORT).show() } builder.show() }
|
基础布局容器
Android 的UI 可以分为两类,一类叫做ViewGroup容器,一类叫做View视图
View视图:(TextView,Button,ImageView)都是常用常见的视图.
ViewGroup容器:内部可以承载、放置、添加View视图
布局
- LinearLayout线性布局:横着或竖着按顺序排列
- RelativeLayout相对布局:起始坐标时屏幕坐上角,以同级或上级为参考系定位位置
- FrameLayout帧布局:像千层饼一样,一层压着一层
- ConstraintLayout约束布局:google于2016年新发布的一种布局方式,它不在android的基础api包里,需要额外引入
AbsoluteLayout绝对布局(以屏幕左上角为参考系,定位自己的位置,从android 2.2版本后废弃)
GridLayout网格布局(可以指定行数列数,子控件自动根据行列数进行分配位置,于android 4.0后新增进api中)
TableLayout表格布局(类似于网格布局,以一个TableRow标签定义为一行或一列)
线性布局LinearLayout
线性布局就是从左到右或从上到下按顺序排列的一种布局。下面讲一讲LinearLayout的基础属性。
属性 |
可选值 |
说明 |
orientation |
1.vertical:垂直排列 2.horizontal:水平排列 |
也就是这个线性布局到底是水平方向逐个排列还是垂直方向逐个排列 |
layout_width layout_height |
1.match_parent:填充父容器的剩余空间 2.wrap_content:根据子视图宽高自适应自己的宽高 3.自定义大小50dp |
layout_width和layout_height是android中控件的必要属性,规定了控件的宽度和高度,这个两个属性的值可以是指定的值,也可以根据内容自适应,还可以填充整个剩余空间 |
background |
#ff0000 红色 |
填充背景色 |
gravity |
1.center:所有子视图相对于父容器居中显示 2.horizontal_center:所有子容器的横向方向上相对父容器居中显示 3.vertical_center:所有子视图的纵向方向上相对父容器居中显示 |
决定子控件相对该父容器的位置 |
layout_gravity |
1.center:该容器相对于它的父容器居中显示 2.horizontal_center:该容器横向方向上相对它的父容器居中显示 3.vertical_center:该容器纵向方向上相对它的父容器居中显示 |
决定该容器相对它的父容器的位置 |
weight |
|
按比例分配父容器剩余的宽度或高度 |
效果展示
- android:orientation =”vertical”所有子视图纵向摆放

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?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" android:gravity="center" //子视图相对父视图居中显示 android:orientation="vertical"> //所有子视图纵向摆放
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="普通按钮" />
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="普通按钮" />
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="普通按钮" />
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="普通按钮" />
</LinearLayout>
|
- android:orientation =”horizontal”所有子视图横向摆放

| <?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" android:gravity="center" //子视图相对父视图居中显示 android:orientation="horizontal"> //所有子视图横向摆放 ......... 省略 </LinearLayout>
|
相对布局RelativeLayout
相对布局在摆放子视图位置时,按照指定的参考系来摆放子视图的位置,默认以屏幕左上角(0,0)位置作为参考系摆放位置
属性 |
可选值 |
说明 |
layout_alignParentTop |
true/false |
是否让控件相对于父容器顶部对齐 |
layout_alignParentBottom |
true/false |
是否让控件相对于父容器底部对齐 |
layout_alignParentLeft |
true/false |
是否让控件相对于父容器左边对齐 |
layout_alignParentRight |
true/false |
是否让控件相对于父容器右边对齐 |
layout_centerHorizontal |
true/false |
相对父容器水平居中显示 |
layout_centerVertical |
true/false |
相对父容器垂直居中显示 |
centerInParent |
true/false |
相对父容器居中显示 |
属性 |
可选值 |
说明 |
layout_above |
@+id/ |
指定在那个控件的上侧 |
layout_below |
@+id/ |
指定在那个控件的上侧 |
android:layout_toLeftOf |
@+id/ |
指定在那个控件的左侧 |
android:layout_toRightOf |
@+id/ |
指定在那个控件的右侧 |
属性 |
可选值 |
说明 |
layout_alignLeft |
@+id/ |
该控件的左边沿与指定控件的左边对齐 |
layout_aliginRight |
@+id/ |
该控件的右边沿与指定控件的右边对齐 |
layout_alignTop |
@+id/ |
该控件的上边沿与指定控件的上边沿对齐 |
layout_alignBottom |
@+id/ |
该控件的下边沿与指定控件的下边沿对齐 |
效果演示

使用layout_below使得后面一个组件位于前面一个组件的下方
配合layout_toRightOf使得后面一个组件位于前面一个组件的右方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="普通按钮1" />
<Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/btn1" android:layout_toRightOf="@+id/btn1" android:text="普通按钮2" />
<Button android:id="@+id/btn3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/btn2" android:layout_toRightOf="@+id/btn2" android:text="普通按钮3" />
<Button android:id="@+id/btn4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/btn3" android:layout_toRightOf="@+id/btn3" android:text="普通按钮4" /> </RelativeLayout>
|
帧布局FrameLayout
组件的默认位置都是左上角,组件之间可以重叠。像千层饼一样,一层压着一层 可以设置上下左右的对齐、水平垂直居中、设置方式与线性布局相似
属性 |
可选值 |
说明 |
layout_gravity |
center/center_vertical/center_horizontal |
组件相对父容器的位置 |
layout_marginLeft |
具体的数值100dp |
左侧外间距 |
layout_marginTop |
具体的数值100dp |
上侧外间距 |
layout_marginRight |
具体的数值100dp |
右侧外间距 |
layout_marginBottom |
具体的数值100dp |
下侧外间距 |
效果演示

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:background="@color/purple_200" android:gravity="center_horizontal" android:paddingTop="100dp" android:text="layout_gravity:center" android:textSize="30dp" />
<TextView android:layout_width="300dp" android:layout_height="360dp" android:layout_gravity="center" android:background="@color/purple_500" />
<TextView android:layout_width="240dp" android:layout_height="240dp" android:layout_gravity="center" android:background="@color/purple_700" />
<TextView android:layout_width="140dp" android:layout_height="140dp" android:layout_gravity="center" android:background="@color/teal_700" />
<TextView android:layout_width="60dp" android:layout_height="60dp" android:layout_gravity="center" android:background="#ffffff" android:gravity="center" /> </FrameLayout>
|
总结

自定义控件
1.引入布局

2.隐藏actionbar
3.创建自定义控件

4.在mainActivity布局文件中引入全限定名

ContentProvider内容提供器
在程序运行时申请权限
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| package com.example.runtimepermissiontest;
import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat;
import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.make_call); button.setOnClickListener((View v) -> { if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE)!= PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE}, 1); }else { call(); } }); }
private void call() { try { Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); } catch (Exception e) { e.printStackTrace(); } }
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case 1: if (grantResults.length>0 &&grantResults[0]==PackageManager.PERMISSION_GRANTED){ call(); }else { Toast.makeText(this,"没权限", Toast.LENGTH_SHORT).show(); } break; default: } } }
|
访问其他程序中的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| package com.example.contactstest;
import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat;
import android.Manifest; import android.content.pm.PackageManager; import android.database.Cursor; import android.os.Bundle; import android.provider.ContactsContract; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast;
import java.util.ArrayList; import java.util.List;
public class MainActivity extends AppCompatActivity { ArrayAdapter adapter; List<String> contactsList = new ArrayList<>();
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView contactsView = findViewById(R.id.contacts_view); adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, contactsList); contactsView.setAdapter(adapter); if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 1); } else { readContacts(); } }
private void readContacts() { Cursor cursor = null; try { cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null); if (cursor != null) { while (cursor.moveToNext()){ String displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)); String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); contactsList.add(displayName + "\n" +number); } adapter.notifyDataSetChanged(); } }catch (Exception e){ e.printStackTrace(); }finally { if (cursor!=null){ cursor.close(); } } }
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { readContacts(); } else { Toast.makeText(this, "没权限", Toast.LENGTH_SHORT).show(); } break; default: } } }
|
创建内容提供器的步骤
暂时跳过
手机多媒体
使用通知
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package com.example.notificationtest;
import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.NotificationCompat;
import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.graphics.BitmapFactory; import android.os.Build; import android.os.Bundle; import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.send_notice); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("normal", "Normal", NotificationManager.IMPORTANCE_DEFAULT); notificationManager.createNotificationChannel(channel); } button.setOnClickListener((v -> { Notification notification = new NotificationCompat.Builder(this, "normal") .setContentTitle("通知标题") .setContentText("通知文本") .setWhen(System.currentTimeMillis()) .setSmallIcon(R.mipmap.ic_launcher) .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)) .build(); notificationManager.notify(1, notification); })); } }
|
为通知添加点击跳转

点击通知后通知消失
1.setAutoCancel方法

2.显示调用

通知的进阶用法
设置震动
设置提示音
设置为大图片
设置通知重要性

调用摄像头拍照
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| package com.example.cameraaibumtest;
import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider;
import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; import android.util.Log; import android.widget.Button; import android.widget.ImageView;
import java.io.File; import java.io.FileNotFoundException; import java.io.IOException;
public class MainActivity extends AppCompatActivity { ImageView picture; Uri imageUri; private static final int TAKE_PHOTO = 1;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button takePhoto = findViewById(R.id.take_photo); picture = findViewById(R.id.picture); takePhoto.setOnClickListener(v -> { File outputImage = new File(getExternalCacheDir(), "output_image.jpg"); try { if (outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraaibumtest.fileprovider", outputImage); } else { imageUri = Uri.fromFile(outputImage); } Intent intent=new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); startActivityForResult(intent,TAKE_PHOTO); }); }
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case TAKE_PHOTO: if (resultCode == RESULT_OK) { try { Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); Log.d("this", "==== " + bitmap); picture.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } break; default: break; } } }
|

调用相册里的图片

使用网络技术
WebView的用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package com.example.webviewtest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.webkit.WebView; import android.webkit.WebViewClient;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); WebView webView = findViewById(R.id.web_view); webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { try { if (!url.startsWith("http:") ||!url.startsWith("https:")) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(intent); return true; } } catch (Exception e){ return false; }
view.loadUrl(url); return true; } }); webView.loadUrl("https://www.baidu.com"); }
}
|
OkHttp3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| package com.example.networktest;
import com.google.gson.Gson;
import androidx.appcompat.app.AppCompatActivity; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response;
import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView;
import com.example.notice;
import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL;
public class MainActivity extends AppCompatActivity implements View.OnClickListener { TextView responseText;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button sendRequest = findViewById(R.id.send_request); responseText = findViewById(R.id.response_text); sendRequest.setOnClickListener(this); }
@Override public void onClick(View v) { if (v.getId() == R.id.send_request) { sendRequestWithOKHttp(); } }
private void sendRequestWithOKHttp() { new Thread(new Runnable(){ @Override public void run() { try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url("http://124.93.196.45:10001/prod-api/api/metro/notice/1").build(); Response response = client.newCall(request).execute(); String responseData = response.body().string(); parseJSONWithJSONGSON(responseData); } catch (Exception e) { e.printStackTrace(); } } }).start(); } private void parseJSONWithJSONGSON(String responseData){ Gson gson = new Gson(); notice notice = gson.fromJson(responseData, notice.class); System.out.println(notice); showResponse(notice.toString()); } private void parseJSONWithJSONObject(String responseData) { try { JSONObject jsonObject = new JSONObject(responseData); JSONObject data = jsonObject.getJSONObject("data"); showResponse(data.toString()); } catch (JSONException e) { e.printStackTrace(); } }
private void sendRequestWithHttpURLConnection() { new Thread(new Runnable() { @Override public void run() { HttpURLConnection connection = null; BufferedReader reader = null; try { URL url = new URL("https://www.gravity.wang"); connection = (HttpURLConnection) url.openConnection(); connection.setReadTimeout(8000); connection.setRequestMethod("GET"); connection.setConnectTimeout(8000); InputStream is = connection.getInputStream(); reader = new BufferedReader(new InputStreamReader(is)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } showResponse(response.toString()); } catch (Exception e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); } } } }).start(); }
private void showResponse(String response) { runOnUiThread(new Runnable() { @Override public void run() { responseText.setText(response); } }); } }
|
解析XML
Pull解析方式
暂时跳过
SAX解析方式
暂时跳过
解析JSON
使用JSONObject
| private void parseJSONWithJSONObject(String responseData) { try { JSONObject jsonObject = new JSONObject(responseData); JSONObject data = jsonObject.getJSONObject("data"); showResponse(data.toString()); } catch (JSONException e) { e.printStackTrace(); } }
|
使用GSON
使用GSON可以将json直接封装成一个java对象(bean)
导入GSON的包
| private void parseJSONWithJSONGSON(String responseData){ Gson gson = new Gson(); notice notice = gson.fromJson(responseData, notice.class); System.out.println(notice); showResponse(notice.toString()); }
|
Service后台服务
在子线程更新UI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| package com.example.androidthreadtest;
import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView text; private Handler handler = new Handler() { @Override public void handleMessage(@NonNull Message msg) { switch (msg.what) { case 1: text.setText(msg.obj.toString()); break; default: break; } } };
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button changeText = (Button) findViewById(R.id.change_text); text = (TextView) findViewById(R.id.text); changeText.setOnClickListener(this); }
@Override public void onClick(View v) { switch (v.getId()) { case R.id.change_text: new Thread(new Runnable() { @Override public void run() { Message message = new Message(); message.what = 1; message.obj = "Nice to meet you"; handler.sendMessage(message); } }).start(); break; } } }
|
AsyncTask
AsyncTask(抽象类)实现原理基于异步消息处理机制。
AsyncTask类的三个泛型参数:
(1)Params:在执行AsyncTask是需要传入的参数。
(2)Progress:后台执行任务时,如果需在界面显示当前进度,则该泛型作为进度单位。
(3)Result:任务执行完毕后,如需对结果进行返回,该泛型作为返回值类型。
用AsyncTask类经常需重写的方法:
(1)onPreExecute(): 后台任务开始执行前调用,用于界面上的初始化操作。
(2)doInBackground(): 该方法中所有代码会在子线程中运行,在这里处理耗时任务,用return返回任务执行结果。如需更新UI元素,调用publishProgress(Progress…)来完成。
(3)onProgressUpdata(Progress…): 当后台调用publishProgress(Progreess…)后,该方法很快被调用,在这个方法中可进行UI操作。
(4)onpostExecute(Result): 后台任务执行完毕并通过return进行返回时,该方法被调用。返回的数据作为参数传递到该方法中,利用返回的数据可进行一些UI操作,例关闭进度条对话框等。
总结:在doInBackground()中执行耗时的任务,在onProgressUpdate()中进行UI操作,在onpostProgress()中执行任务的收尾工作。
Service服务
基本使用
启动和停止服务
创建一个服务
重写三个方法
onCreate会在服务被创建的时候调用
onStartCommand会在服务启动的时候被调用
onDestroy会在服务被销毁的时候被调用

在AndroidManifest.xml中注册服务
服务的启动和停止

活动和服务进行通信
在服务的类创建一个子类
子类继承于Binder
子类内部定义方法,可以被activity(活动)访问
最后在OnBind()方法进行返回

创建一个服务连接对象
onServiceConnected方法是连接时执行的
onServiceDisconnected是在断开连接执行的

最后将activity和service进行绑定

服务的生命周期
一旦在项目的任何位置调用了Context 的startService()方法,相应的服务就会启动起来,并回调onStartCommand()方法。如果这个服务之前还没有创建过,onCreate()方法会先于onStartCommand()方法执行。服务启动了之后会一直保持运行状态,直到stopService()或stopSelf()方法被调用。注意虽然每调用一次startService()方法,onStartCommand()就会执行一次,但实际上每个服务都只会存在一个实例。所以不管你调用了多少次startService()方法,只需调用一次stopService()或stopSelf()方法,服务就会停止下来了。
另外,还可以调用Context 的bindService()来获取一个服务的持久连接,这时就会回调服务中的onBind()方法。类似地,如果这个服务之前还没有创建过,onCreate()方法会先于onBind()方法执行。之后,调用方可以获取到onBind()方法里返回的IBinder 对象的实例,这样就能自由地和服务进行通信了。只要调用方和服务之间的连接没有断开,服务就会一直保持运行状态。
当调用了startService()方法后,又去调用stopService()方法,这时服务中的onDestroy()方法就会执行,表示服务已经销毁了。类似地,当调用了bindService()方法后,又去调用unbindService()方法,onDestroy()方法也会执行,这两种情况都很好理解。但是需要注意,我们是完全有可能对一个服务既调用了startService()方法,又调用了bindService()方法的,这种情况下该如何才能让服务销毁掉呢?根据Android 系统的机制,一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被销毁。所以,这种情况下要同时调用stopService()和unbindService()方法,onDestroy()方法才会执行。
使用前台服务

使用IntentService(多线程)
创建一个子类继承IntentService
onHandleIntent这个方法已经在子线程里了

启动服务

Material Design