Android移动应用开发
1、Android界面分为布局和控件。1、Android的体系架构。控件内容相对于控件的位置。控件相对于父控件的位置。2、Dalvik虚拟机。(所有UI类的父类)4、设置控件相对位置。
Android移动应用开发
1、认识Android
1、Android的体系架构
应用程序、应用程序框架、核心类库、Linux内核
2、Dalvik虚拟机
3、ART虚拟机
2、Android界面开发方法
2.1 布局控件
1、Android界面分为布局和控件
2、布局类LinearLayout 继承自 ViewGroup
控件类TextView 继承自 View(所有UI类的父类)
3、小结
带+在r文件中自动生成一个常量代替该文件
android:id=“@+id/button”
2.2 Android常用公有属性
1、layout_width、layout_height 设置控件宽高
wrap_content 包裹内部控件
match_parent 填充父容器
2、layout_margin 控件的外边距
3、padding 控件的内边距
4、设置控件相对位置
layout_gravity 控件相对于父控件的位置
gravity 控件内容相对于控件的位置
靠左、靠右、顶部、底部:left、right、top、bottom
居中:center
水平居中:center_horizontal
垂直居中:center_vertical
2.3 线性布局 LinearLayout
1、排列规则:水平排列、垂直排列
注意:默认是水平,控件不会自动换行,超出布局的不显示
2、特有属性 orientation 设置方向
水平:horizontal 从左到右
垂直:vertical 从上到下
3、layout_weight
4、background和backgroundIint
background:除了纯色背景还可以加图片
backgroundIint:适用于api level 21 更高的版本
5、setTextColor修改颜色的三种方式
(Color.RED)
(Color.rgb(0,0,255))
(Color.parseColor(“#66CCFF”))
2.4 values下xml 技巧
1、colors.xml 定义颜色
<resources>
<color name="color">#3F51B5</color>
</resources>
android:textColor="@color/color"
2、string.xml 定义字符串
<resources>
<string name="hello">hello</string>
</resources>
android:text="@string/hello"
2.5 button的使用
1、ImageButton
<ImageButton
android:id="@+id/button16"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/selector_button"
android:scaleType="fitXY"
android:src="@mipmap/sqrt" />
src:前景
background:背景
fitXY:图片适应控件大小
2、单个Button的事件处理
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
textView.setTextColor(Color.parseColor("red"));
}
});
3、多个Button的事件处理
总体思路:使用switch方法
在Activity中实现事件监听接口
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//此处省略部分代码
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.button:
textView.setTextColor(Color.parseColor("red"));
break;
case R.id.button2:
textView.setTextColor(Color.YELLOW);
break;
case R.id.button3:
textView.setTextColor(Color.GREEN);
break;
}
}
}
也可在Activity构造方法后,在xml布局中调用onClick
<Button
android:id="@+id/button"
android:text="红色"
android:backgroundTint="@color/red"
style="@style/buttonstyle"
android:onClick="doLogin"/>
2.6 shape图形 selector
1、利用shape属性构建一个圆形
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<!-- 大小-->
<size android:height="180dp" android:width="400dp"/>
<!-- 填充颜色-->
<solid android:color="@color/white"/>
<!-- 描边-->
<stroke android:color="@color/black" android:width="1dp" android:dashWidth="3dp" android:dashGap="1dp"/>
<!-- 圆角半径-->
<corners android:radius="10dp"/>
</shape>
2、selector 点击图片后显现另一个图片
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 不设置状态的这一行,一定要写在最后面,否则不起作用-->
<item android:state_pressed="true" android:drawable="@drawable/button_pressed_orig"/>
<item android:drawable="@drawable/button_normal_orig"/>
</selector>
2.7 相对布局ReLativeLayout的使用
1、兄弟控件
2、父控件
2.8 Spinner控件的使用
1、spinner列表框模式
android:spinnerMode
dialog:弹出对话框
dropdown:下拉框
android:entries 设置列表项,值为数组资源
android:popupBackground 设置下拉项的背景
2、spinner列表框实现方式一
<Spinner
android:id="@+id/spanner_dropdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/dropdown"
android:spinnerMode="dropdown"
android:popupBackground="@color/teal_700"></Spinner>
values/arrs.xml
<resources>
<string-array name="dropdown">
<item>软件二班</item>
<item>软件一班</item>
<item>软件三班</item>
<item>软件四班</item>
</string-array>
</resources>
2、spinner列表框实现方式二
<Spinner
android:id="@+id/spinner_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:spinnerMode="dialog">
</Spinner>
//1.获取列表控件
spinner=findViewById(R.id.spinner_dialog);
//2.准备数据
String arr[]=new String[]{"北京","上海","潍坊","西双版纳"};
//3.创建adapter适配器对象上下文、列表项数据的布局数据
//this 当前类对象对象,监听器类,监听器不能充当上下文
ArrayAdapter arrayAdapter=new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1,arr);
//4.设置adapter
spinner.setAdapter(arrayAdapter);
2.9 Dialog对话框对的使用
1、简单对话框
(1)调用AlertDialog 的静态内部类 Builder创建AlertDialog. Builder对象。
(2)调用AlertDialog.Builder的 setTitle()和setIcon( )方法设置对话框的标题名称和图标。
(3)调用AlertDialog.Builder 的setMessage( )、setSingleChoiceItems()等方法设置对话框的提示信息、单选选项等显示内容。
(4)调用AlertDialog.Builder的setPositiveButton()和 setNegativeButton()方法设置对话框的“确认”和“取消”按钮。
(5)调用AlertDialog. Builder 的 create()方法创建AlertDialog 对象。
(6)调用AlertDialog 对象的show()方法显示对话框。
(7)调用AlertDialog对象的dismiss()方法取消对话框。
2、单选对话框
private void genderDialog() {
String[] genders=new String[]{"男","女"};
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setTitle("选择性别");
builder.setSingleChoiceItems(genders, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
gender1.setText(genders[i]);
dialogInterface.dismiss();
}
});
AlertDialog dialog=builder.create();
dialog.show();
}
3、多选对话框
AlertDialog.Builder b = new AlertDialog.Builder(this);
final String items[]=new String[]{"音乐", "画画", "游泳", "电影", "游戏", "运动"};
boolean[] checks=new boolean[]{false, false, false, false, false, false};
b.setTitle("选择你喜欢的项目:");
/*b.setMultiChoiceItems第一个参数为复选按钮组,第二个为是否默认选中,对应复选按钮组,true为默认选中,第三个为监听事件*/
b.setMultiChoiceItems(items, checks, new DialogInterface.OnMultiChoiceClickListener(){
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
Toast.makeText(MainActivity.this, "你选择了"+items[which], Toast.LENGTH_SHORT).show();
}
});
b.setPositiveButton("确定", null);
b.show();//显示对话框
4、日期对话框
private void birthdayDialog() {
Calendar c=Calendar.getInstance();
int year1=c.get(Calendar.YEAR);
int month1=c.get(Calendar.MONTH);
int day1=c.get(Calendar.DAY_OF_MONTH);
DatePickerDialog dialog=new DatePickerDialog(this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datePicker, int i, int i1, int i2) {
birthday1.setText(i+"年"+(i1+1)+"月"+i2+"日");
}
},year1,month1,day1);
dialog.show();
}
5、自定义对话框
private void usernameDialog() {
View v=View.inflate(this,R.layout.dialog_username,null);
AlertDialog.Builder builder=new AlertDialog.Builder(this);
builder.setTitle("修改昵称");
builder.setView(v);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
EditText ed1_up=v.findViewById(R.id.ed1);
String name=ed1_up.getText().toString().trim();
username1.setText(name);
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
AlertDialog dialog=builder.create();
dialog.show();
}
3、界面跳转的实现
3.1 认识Intent
1、显式Intent
Intent intent=new Intent(MainActivity.this,SecondActivity.class);
startActivity(intent);
2、隐式Intent
AndroidManifest.xml
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>//过滤器
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:exported="false">
<intent-filter>
<action android:name="com.example.appjump.SecondActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
MainActivity.java
Intent intent=new Intent("com.example.appjump.SecondActivity");
startActivity(intent);
3.2 Activity间的数据传递
1、向下一个Activity传递数据
(1)、单个存取
Intent intent=new Intent("com.example.appjump.SecondActivity");
String t=t1.getText().toString().trim();
intent.putExtra("text",t);
Intent intent=getIntent();
String text=intent.getStringExtra("text");
(2)、打包存取
Intent intent=new Intent("com.example.appjump.SecondActivity");
Bundle bundle=new Bundle();
bundle.putString("name",uname);
bundle.putString("password",pas);
intent.putExtra(bundle);
Intent intent=getIntent();
Bundle bundle=intent.getExtras();
String name=bundle.getString("name");
String password=bundle.getString("password");
2、返回数据给上一个Activity
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.button1:
Intent intent=new Intent("com.example.appjump.SecondActivity");
String t=t1.getText().toString().trim();
intent.putExtra("text",t);
startActivityForResult(intent,2);
break;
}
}
@Override
public void onClick(View view) {
Intent intent1=new Intent(SecondActivity.this,MainActivity.class);
String t2=e1.getText().toString().trim();
intent1.putExtra("text2",t2);
setResult(RESULT_OK,intent1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==2){
if(resultCode==RESULT_OK){
String text2=data.getStringExtra("text2");
t1.setText(text2);
}
}
}
3.3 Activity生命周期
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
Log.e("生命周期","onCreate");
}
@Override
protected void onStart() {
super.onStart();
Log.e("生命周期","onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.e("生命周期","onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.e("生命周期","onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.e("生命周期","onStop");
}
@Override
protected void onRestart() {
super.onRestart();
Log.e("生命周期","onRestart");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("生命周期","onDestroy");
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
Log.e("生命周期","onSavaInstanceState");
}
4、用户信息的存储
4.1 简单存储SharedPreferences
1、存储形式
键值对
2、存储位置
/data/data/<包名>/shared-prefs
3、存数据
SharedPreferences spf=getSharedPreferences("data",MODE_PRIVATE);
SharedPreferences.Editor editor=spf.edit();
editor.putString("username","nolan");
editor.putString("password","123456");
editor.commit();
4、取数据
SharedPreferences spf1=getSharedPreferences("data",MODE_PRIVATE);
String name=spf1.getString("username","admin");//第二个参数为默认值
4.2 文件存储
1、内部存储
(1)存储位置
/data/data/<包名>/files
(2)存文件
private void saveData() {
//String fileName="mydb.txt"; //文件名称
//String strNr="HelloWorld,我被写出来啦!";//要保存的数据
String a=ed1.getText().toString();
FileOutputStream fos=null;
try {
fos=openFileOutput(fileName,MODE_PRIVATE);
fos.write(a.getBytes());//将数据写入文件中去
Toast.makeText(this,"存入数据成功",Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(fos!=null) {
fos.close();
}
}catch (Exception ex){
ex.printStackTrace();
}
}
}
(3)取文件
private void readData() {
String strNr="";
FileInputStream fis=null;
try {
fis=openFileInput(fileName);//获取输入流对象
byte[] buffer=new byte[fis.available()]; //创建数据的缓冲
fis.read(buffer);
strNr=new String(buffer);//将内容转换成字符串
text.setText(strNr);
Toast.makeText(this,"读取数据成功",Toast.LENGTH_LONG).show();
}catch (Exception ex){
ex.printStackTrace();
} finally {
try {
if(fis!=null){
fis.close();
}
}catch (Exception ex){
ex.printStackTrace();
}
}
}
2、外部存储
(1)存储位置
Environment.getExternalStorageDirectory().getPath():该方法返回外部存储根路径,返回值为"String"
/storage/emulated/0
(2)创建文件
public static File getFile(String filePath) {
//通过文件路径创建文件对象
File file = new File(filePath);
//判断父文件夹是否存在 如果不存在则创建文件夹
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
//判断文件是否存在 如果不存在则创建文件
if (!file.exists()) {
try {
file.createNewFile();
} catch (Exception e) {
Log.e("创建失败", e.getMessage());
}
}
return file;
}
(3)申请权限
1、Androud6.0以下的版本
在AndroidManifest.xml中对所需权限进行声明
在manifest节点和application节点之间
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2、Androud6.0~10.0的版本
步骤一:在Activity的onCreate()方法中,添加动态权限申请
if(ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,Manifest.permission.READ_EXTERNAL_STORAGE)
!=PackageManager.PERMISSION_GRANTED){
Log.e("权限问题","有权限么");
ActivityCompat.requestPermissions(this,new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE},1);
}else {
saveData(filePath, a);
}
步骤二:添加回调方法onRequestPermissionsResult()
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode==1){//判断请求码
for(int i=0;i<permissions.length;i++){//循环判断权限授予结果
if(grantResults[i]==PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"权限"+permissions[i]+"申请成功",Toast.LENGTH_LONG).show();
}else {
Toast.makeText(this,"权限"+permissions[i]+"申请失败",Toast.LENGTH_LONG).show();
}
}
}
}
3、Androud10.0以上的版本
在AndroidManifest.xml的application节点中,加入以下属性设置
android:requestLegacyExternalStorage="true"
(4)存文件
private void saveData(String filePath,String content) {
//调用getFile()方法创建文件并返回
File file=getFile(filePath);
FileWriter fw=null;
BufferedWriter bw=null;
try {
//创建缓冲流对象实现数据的写入
fw=new FileWriter(file,false);
bw=new BufferedWriter(fw);
bw.write(content);
Toast.makeText(this,"数据存入成功",Toast.LENGTH_LONG).show();
} catch (IOException e) {
Log.e("写文件出错",e.getMessage());
}finally {
try {//先关包装流,再关节点流
if(bw!=null)
bw.close();
if(fw!=null)
fw.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
(5)取文件
private String readData(String filePath) {
File file=new File(filePath);
String s=null;
StringBuilder stringBuilder=new StringBuilder();
FileReader fr=null;
BufferedReader reader=null;
int count=0;
try{
//创建缓冲流对象
fr=new FileReader(file);
reader=new BufferedReader(fr);
//循环按行读取数据
while ((s=reader.readLine())!=null){
stringBuilder.append(s);
}
Toast.makeText(this,"数据读取成功",Toast.LENGTH_LONG).show();
}catch (Exception e){
Log.e("读取文件出错",e.getMessage());
}finally {
try{
if(reader!=null)
reader.close();
if(fr!=null)
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
return stringBuilder.toString();
}
5、ListView的应用
5.1 使用Adapter设置数据及布局
1、在布局文件中加入ListView控件
2、写好列表项的布局文件
3、准备将要在列表项中显示的数据,可以为数组或集合
4、创建Adapter对象,设置选中项的显示布局和数据
5、将Adapter对象设置给ListView对象
5.2 简单适配器SimpleAdapter
将数据转给布局中的控件
//List继承自Map集合,data:List对象,List中的对象:Map集合的对象,Map对象:键:String 值:不知道是什么类型
//一个Map对象代表一个列表项,有几个列表项就有几个Map
//准备数据
String[] names=new String[]{"太阳","水星","金星","地球","火星","木星","土星","天王星","海王星"};
int[] images=new int[]{R.mipmap.ty,R.mipmap.sx,R.mipmap.jx,R.mipmap.dq,R.mipmap.hx,R.mipmap.mx,R.mipmap.tx,R.mipmap.twx,R.mipmap.hwx};
//创建一个List对象
ArrayList list=new ArrayList();
//一个列表项的数据组成一个Map对象
for(int i=0;i< names.length;i++){
HashMap map=new HashMap();
map.put("image",images[i]);
map.put("name",names[i]);
list.add(map);
}
//准备适配器
//第1个参数:上下文对象,第2个参数:数据集合 List集合,其中元素是Map对象,第3个参数:列表项布局
//第4个参数:Map中键的数组,第5个参数:是布局中控件的id,键和id的数组要一一对应
SimpleAdapter adapter=new SimpleAdapter(this,list,R.layout.item_list,new String[]{"image","name"},new int[]{R.id.iv_icon,R.id.tv_name});
//列表项item点击事件处理
l1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
//第1个参数:点击的Adapter对象,第2个参数:点击的item,第3个参数:位置 第i个item,第4个参数:item在listview第几行 一般3和4是一样的
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(ListActivity.this, "您选择的是"+names[i], Toast.LENGTH_SHORT).show();
}
});
5.3 自定义适配器
ArrayAdapter适用于列表项中包含一个TextView
SimpleAdapter有固定的数据组织形式
ArrayAdapter和SimpleAdapter继承BaseAdapter抽象类
1、MyAdapter.java 自定义适配器将存储的数据转给控件
public class MyAdapter extends BaseAdapter {
private List<Planet> data;//数据集合
private int layoutId;//列表项布局id
private Context context;//上下文对象
public MyAdapter(Context context,List<Planet> data,int layoutId){
this.context=context;
this.data=data;
this.layoutId=layoutId;
}
//获取列表项个数
@Override
public int getCount() {
return data.size();
}
//获取i位置上的列表项对象
@Override
public Object getItem(int i) {
return data.get(i);
}
//获取i位置上的列表项的id,当前元素的位置
@Override
public long getItemId(int i) {
return i;
}
//将i位置上的数据放到列表项布局中
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
//数据位置 List集合data中,取出i位置的数据
Planet planet=data.get(i);
String name=planet.getName();
int image=planet.getImage();
//通过Inflater对象的inflate方法将布局转成一个view对象,再通过view对象findViewById找控件
//获取LayoutInflater实例,从一个Context中,获得一个布局管理器
LayoutInflater inflater=LayoutInflater.from(context);
//将xml布局转换为view对象,找到xml布局
View v=inflater.inflate(layoutId,null);
ImageView imageView=v.findViewById(R.id.iv_icon);
TextView textView=v.findViewById(R.id.tv_name);
//将数据放到相应的控件上
imageView.setImageResource(image);
textView.setText(name);
return v;
}
}
2、ListActivity.java 调用适配器完成存储
public class ListActivity extends AppCompatActivity {
private ListView l1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
l1=findViewById(R.id.l1);
//创建一个List对象
ArrayList list=new ArrayList();
list.add(new Planet("太阳",R.mipmap.ty));
list.add(new Planet("水星",R.mipmap.sx));
list.add(new Planet("金星",R.mipmap.jx));
list.add(new Planet("地球",R.mipmap.dq));
list.add(new Planet("火星",R.mipmap.hx));
list.add(new Planet("木星",R.mipmap.mx));
list.add(new Planet("土星",R.mipmap.tx));
list.add(new Planet("天王星",R.mipmap.twx));
list.add(new Planet("海王星",R.mipmap.hwx));
//自定义适配器
MyAdapter adapter=new MyAdapter(this,list,R.layout.item_list);
l1.setAdapter(adapter);
}
}
5.4 ViewHolder用法
ViewHolder通常出现在适配器里,为的是ListView滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升复用性,要按需填充并重新使用view来减少对象的创建。优化ListView的加载速度就要让convertView匹配列表类型,并最大程度上的重新使用convertView。
定义一个ViewHolder,将convetView的tag设置为ViewHolder,不为空时重新使用即可
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder=null;
if(view==null){
//创建ViewHolder对象 承载的是每一个列表项的视图
holder=new ViewHolder();
//将列表项布局转为View对象
LayoutInflater inflater=LayoutInflater.from(context);
view=inflater.inflate(R.layout.item_jf,null);
//获取控件
holder.t1=view.findViewById(R.id.tv_name);
holder.t2=view.findViewById(R.id.tv_describe);
holder.b1=view.findViewById(R.id.tv_button);
//Tag从本质上来讲是就是相关联的view的额外的信息,经常用来存储一些view的数据
view.setTag(holder);
}else{
//放着控件引用的ViewHolder对象,可以去复用
holder= (ViewHolder) view.getTag();
}
//取数据
Description description=data.get(i);
holder.t1.setText(description.getItname());
holder.t2.setText(description.getZtname());
return view;
}
//创建内部类
public final class ViewHolder{
public TextView t1;
public TextView t2;
public Button b1;
}
6、单选及复选按钮
6.1 复选按钮(CheckBox)
1、继承关系及使用方法
CheckBox继承CompoundButton
android:checked 设置按钮的勾选状态 true/false
CompoundButton分为两个部分,左侧是勾选图标,右侧是选项文字
若将andriod:button的值设为“@null”,则可以去掉左侧的勾选图标
若不设置android:text的值,则仅有左侧的勾选图标,没有右侧的选项文字
2、activity_main.xml
采用线性布局水平排列,有几个按钮选项就设几个TextView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你喜欢什么运动?"
android:textColor="@color/black"
android:textSize="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/t1"
android:textSize="15dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/t2"
android:textSize="15dp"/>
</LinearLayout>
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="跑步"
android:id="@+id/cb1"/>
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="游泳"
android:id="@+id/cb2"/>
3、MainActivity.java
实现CompoundButton.OnCheckedChangeListener 接口,重写onCheckedChanged()方法
public class MainActivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener {
private TextView t1,t2;
private CheckBox cb1,cb2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t1=findViewById(R.id.t1);
t2=findViewById(R.id.t2);
cb1=findViewById(R.id.cb1);
cb2=findViewById(R.id.cb2);
cb1.setOnCheckedChangeListener(this);
cb2.setOnCheckedChangeListener(this);
}
@Override
//第一个参数是按钮对象,第二个参数是当前状态
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
switch (compoundButton.getId()){
case R.id.cb1:
if(b){
t1.setText("A");
}else {
t1.setText("");
}
break;
case R.id.cb2:
if(b){
t2.setText("B");
}else {
t2.setText("");
}
break;
}
}
}
6.2 单选按钮(RadioButton)
1、继承关系及使用方法
RadioButton继承CompoundButton
RadioButton通常与单选组合框RadioGroup配合使用,以实现单选按钮间的互斥功能,RadioGroup中可以包含多个RadioButton。而且RadioGroup是LinearLayout的子类,可以通过android:orientation属性设置RadioButton的排列方式。
getCheckedRadioButtonId():获取当前选中的单选按钮ID
2、activity_main.xml
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rg"
android:orientation="vertical">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/rb1"
android:text="肯定真ikun"/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/rb2"
android:text="必是小黑子"/>
</RadioGroup>
3、MainActivity.java
public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener{
private TextView t1;
private RadioGroup rg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rg=findViewById(R.id.rg);
t1=findViewById(R.id.t1);
rg.setOnCheckedChangeListener(this);
}
@Override
//第一个参数为RadioGroup对象,第二个参数为选中单选选项ID
public void onCheckedChanged(RadioGroup radioGroup, int i) {
switch (i){
case R.id.rb1:
t1.setText("A");
break;
case R.id.rb2:
t1.setText("B");
break;
}
}
}
7、Fragment碎片
7.1 认识Fragment
Fragment把屏幕划分为几个碎片,对界面进行模块化处理,是一种嵌入Activity的UI片段
一个Activity中可以包含多个Fragment,一个Fragment也可以在多个Activity中使用
7.2 添加Fragment
1、在布局文件中添加
将Fragment作为一个控件加入布局文件中
在标签中需要添加“android:name”属性,其值为Fragment的完整路径名
<fragment
android:id="@+id/fm2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:name="com.example.newsdemo.BlankFragment2"/>
2、通过代码动态添加
在布局文件中加入一个布局容器FrameLayout
<FrameLayout
android:id="@+id/framelayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
在Activity中调用方法
public class BlankFragment2 extends Fragment {
Button button;
FragmentManager manager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//将布局转为view对象
View view=inflater.inflate(R.layout.fragment_blank2, container, false);
button=view.findViewById(R.id.b1);
//获取FragmentManger对象
manager=getActivity().getSupportFragmentManager();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取FragmentTransaction对象 Fragment事务
FragmentTransaction transaction=manager.beginTransaction();
BlankFragment fragment=new BlankFragment();
//第1个参数:要把Fragment添加到哪个控件,第2个参数:要添加的Fragment对象
//add方法添加碎片不会移除已经添加的碎片。但是replace会先清除所有碎片然后才添加新的碎片
transaction.add(R.id.framelayout,fragment);
transaction.commit();
}
});
return view;
}
}
7.3 Fragment的生命周期
由于Fragment不能独立存在,因此Fragment的生命周期直接受所在Activity 的影响。当在Activity中创建Fragment 时,Fragment 处于启动状态;当Activity暂停时,其上的所有Fragment都暂停;当Activity被销毁时,其上的所有Fragment 都被销毁。
以下5个生命周期方法是Fragment生命周期独有的方法:
onAttatch( ): Fragment 与Activity 建立关联时调用。
onCreate View( ):创建Fragment视图时调用,主要用于加载布局;在该方法返回后,会立即调用onViewCreate( )方法。
onActivityCreated( ): 在Activity 创建完毕后调用。
onDestroyView( ): Fragment关联的视图被销毁时调用。
onDetach( ): Fragment和Activity 解除关联时调用。
8、SQLite数据库
8.1 认识SQLite数据库
SQLite是一种轻量级的关系型数据库,运行速度快,占用资源少,特别适合在移动设备上使用。
SQLite数据库支持标准的SQL语法,但比一般的数据库简单,不需要安装,不需要设置用户名和密码就可以使用。
8.2 SQLite数据库的创建
要创建SQLite数据库,需要先创建一个类继承SQLiteOpenHelper类,在该类中重写onCreate( ) 和 OnUpgrade( ) 方法。
1、下面我们创建一个名为“UserManager.db”数据库,并在此库中创建一张“users”表,存放用户信息
MyDataBaseHelp.ava
public class MyDataBaseHelp extends SQLiteOpenHelper {
//将建表语句定义为一个字符串常量
public static final String CREATE_USERS="create table users("+
"id integer primary key autoincrement,"+
"username text,"+
"password text,"+
"age integer)";
private Context context;
//第一个参数:上下文,第二个参数:数据库名,第三个参数:在查询数据时返回一个自定义Cursor 一般为null,第四个参数:当前数据库版本号
public MyDataBaseHelp(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context=context;
}
//创建数据库
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_USERS);//执行建表语句
Toast.makeText(context,"数据库创建完毕",Toast.LENGTH_LONG).show();
}
}
2、创建MyDataBaseHelper对象,调用 getReadableDatabase( ) 或 getWritableDatabase( ) 方法,创建数据库
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MyDataBaseHelp dataBaseHelp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataBaseHelp=new MyDataBaseHelp(this,"UserManager.db",null,1);
dataBaseHelp.getWritableDatabase();
}
}
8.3 SQLite数据库的升级
在原有users表的基础上,再增加部门表department,进行数据库的更新(可以只看方法三)
方法一:在onCreate( )方法,执行department建表语句
public class MyDataBaseHelp extends SQLiteOpenHelper {
public static final String CREATE_USERS="create table users("+
"id integer primary key autoincrement,"+
"username text,"+
"password text,"+
"age integer)";
public static final String CREATE_DEPARTMENT="create table department("+
"id integer primary key autoincrement,"+
"departmentname text,"+
"departnamecode text)";
private Context context;
public MyDataBaseHelp(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
this.context=context;
}
//创建数据库
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_USERS);//执行建表语句
db.execSQL(CREATE_DEPARTMENT);
Toast.makeText(context,"数据库创建完毕",Toast.LENGTH_LONG).show();
}
}
运行程序,可以发现没有弹出“数据库创建成功”的提示,没有创建department表,这是因为程序运行过,数据库就已经存在了,onCreate( )方法不会再执行,除非删除数据库,才会再次执行,显然这种方法是不合理的,所以我们可以用 onUpgrade( )升级方法。
方法二:在 onUpgrade( )方法中,进行数据库的更新
public class MyDataBaseHelp extends SQLiteOpenHelper {
//省略
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists users");
db.execSQL("drop table if exists department");
onCreate(db);
}
}
执行两条drop语句,如果两个表都存在,就删除,然后调用onCreate( )方法重新创建表,这样可以避免重新创建时因表存在而导致程序报错
执行时,在创建MyDataBaseHelper对象时传入当前数据库版本号(比旧版本号大就行)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MyDataBaseHelp dataBaseHelp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataBaseHelp=new MyDataBaseHelp(this,"UserManager.db",null,2);
dataBaseHelp.getWritableDatabase();
}
}
但是这种方法会将原数据表删除,会使存储的本地数据全部丢失,所以还是看更好的方法三吧
方法三:只要指定的数据库版本号大于当前的版本号,就会进入onUpgrade( )方法,对当前数据库版本号进行判断,在执行相应的数据库更新操作
public class MyDataBaseHelp extends SQLiteOpenHelper {
//省略
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion){
case 1:db.execSQL(CREATE_DEPARTMENT);
}
}
}
通过switch判断当前版本号是1,就会只创建department表,如果有第3个版本数据库更新,就添加新的case语句,判断当前版本号为2.
注意:
1、activity和dao方法中的传参也要跟着变
2、case语句后没有break,这样可以在跨版本升级时,每一次数据库的修改语句都能全部执行
8.4 SQLite数据库的查看
数据库的存储位置与SharedPreferences相同,在datda/data/包名/目录下,查看数据可以使用Android调试桥(adb),存放在SDK的platform-tools目录下,可以用cmd打开
步骤一:配置环境变量
将platform-tools目录添加到环境变量中系统变量的Path中
步骤二:在cmd中输入”adb shell“命令,进入设备控制台
步骤三:使用cd命令,转到data/data/包名/databases目录下
若出现上图中的”Permission denied“,则表示没有查看系统的权限,要通过”su root“命令,更换系统用户
步骤四:使用ls命令,查看该目录下的文件
步骤五:输入”sqlite3 数据库名“,打开数据库
输入”.table“命令,可以查看数据库中的表,通过”.schema“命令可查看建表语句,也可用sql语句进行数据库操作
步骤六:输入”.quit“退出数据库调试,回到adb,输入”exit“命令退出设备控制台
8.5 SQLite数据库的基本操作
在这里我补充一个对数据进行增、删、改、查的案例,以users表为例
1、创建MyDataBaseHelper继承SQLiteOpenHelper,创建User实体类,在activity_main.xml完成布局,此处不再赘述
2、创建UserDao类,封装增、删、改、查方法
public class UserDao {
private MyDataBaseHelp dataBaseHelp;
public UserDao(Context context){
dataBaseHelp=new MyDataBaseHelp(context,"UserManager.db",null,2);
}
//添加数据
public long addUser(User user){
//1.获取数据库对象
SQLiteDatabase db=dataBaseHelp.getWritableDatabase();
ContentValues values=new ContentValues();
//key:数据表的列名,value:值
values.put("username",user.getUsername());
values.put("password",user.getPassword());
values.put("age",user.getAge());
//第一个参数:表名,第二个参数:自动赋值为null的列名,第三个参数:数据
//返回值:long,返回行号,如果添加不成功,返回-1
long id=db.insert("users",null,values);
//数据库关闭
db.close();
return id;
}
//查询数据
public ArrayList queryUser(){
ArrayList list=new ArrayList();
SQLiteDatabase db=dataBaseHelp.getWritableDatabase();
//query的参数对应于select查询sql语句中的各个部分
//db.query("users",new String[]{"id","username","password","age"},"id=?",new String[]{id},null,null,null);
//db.rawQuery();//接受sql语句作为参数
Cursor cursor=db.query("users",null,null,null,null,null,null);
//遍历cursor将数据放到list中
list=convertFromCursor(cursor);
return list;
}
private ArrayList convertFromCursor(Cursor cursor){
ArrayList list=new ArrayList();
//有没有返回值,是否查到结果,如果true,则有
if(cursor!=null&&cursor.moveToFirst()){
do{
int id=cursor.getInt(cursor.getColumnIndexOrThrow("id"));
String username=cursor.getString(cursor.getColumnIndexOrThrow("username"));
String password=cursor.getString(cursor.getColumnIndexOrThrow("password"));
int age=cursor.getInt(cursor.getColumnIndexOrThrow("age"));
User user=new User(id,username,password,age);
list.add(user);
}while (cursor.moveToNext());//true还有数据,继续遍历
}else{
list=null;
}
return list;
}
//修改数据
public int updateUser(User user){
SQLiteDatabase db=dataBaseHelp.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("password",user.getPassword());
values.put("age",user.getAge());
int i=db.update("users",values,"username=?",new String[]{user.getUsername()});
db.close();
return i;
}
//删除数据
public int deleteUser(User user){
SQLiteDatabase db=dataBaseHelp.getWritableDatabase();
int n=db.delete("users","username=?",new String[]{user.getUsername()});
db.close();
return n;
}
}
3、在MainActivity中编写逻辑代码,实现增、删、改、查功能
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private EditText et_username,et_password,et_age;
private Button bt_save,bt_query,bt_update,bt_delete;
private TextView tv_show;
private MyDataBaseHelp dataBaseHelp;
private UserDao userDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dataBaseHelp=new MyDataBaseHelp(this,"UserManager.db",null,2);
dataBaseHelp.getWritableDatabase();
userDao=new UserDao(this);
init();
}
public void init(){
et_username = findViewById(R.id.et_username);
et_password = findViewById(R.id.et_password);
et_age = findViewById(R.id.et_age);
bt_save = findViewById(R.id.bt_save);
bt_query = findViewById(R.id.bt_query);
bt_update = findViewById(R.id.bt_update);
bt_delete = findViewById(R.id.bt_delete);
tv_show = findViewById(R.id.tv_show);
bt_save.setOnClickListener(this);
bt_query.setOnClickListener(this);
bt_update.setOnClickListener(this);
bt_delete.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
//保存数据
case R.id.bt_save:
String uname= et_username.getText().toString();
String psw= et_password.getText().toString();
int age=Integer.parseInt(et_age.getText().toString());
User u=new User(uname,psw,age);
long id=userDao.addUser(u);
if(id!=-1){
Toast.makeText(this,"保存成功",Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this,"保存失败",Toast.LENGTH_LONG).show();
}
break;
//查询数据
case R.id.bt_query:
ArrayList users= userDao.queryUser();
StringBuffer stringBuffer=new StringBuffer();
if(users.size()==0){
tv_show.setText("无数据");
}else{
for(int i=0;i<users.size();i++){
User u1= (User) users.get(i);
stringBuffer.append("ID: "+u1.getId() +
" 用户名: "+u1.getUsername() +
" 密码: "+u1.getPassword() +
" 年龄: "+u1.getAge() +"\n");
}
tv_show.setText(stringBuffer);
}
break;
//修改数据
case R.id.bt_update:
String uname1=et_username.getText().toString();
String psw1=et_password.getText().toString();
int age1=Integer.parseInt(et_age.getText().toString());
User u1=new User(uname1,psw1,age1);
int i=userDao.updateUser(u1);
if(i!=0){
Toast.makeText(this,"修改成功",Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this,"修改失败",Toast.LENGTH_LONG).show();
}
break;
//删除数据
case R.id.bt_delete:
String uname2=et_username.getText().toString();
User u2=new User(uname2);
int n= userDao.deleteUser(u2);
if(n!=0){
Toast.makeText(this,"删除成功",Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this,"删除失败",Toast.LENGTH_LONG).show();
}
break;
}
}
}
注意:除了以上方法,还可以用SQL语句对数据库进行增、删、改、查操作
//增
db.execSQL("insert into users(username,password) values(?,?)",new Object[]{name,password});
//删
db.execSQL("delete from users where id=1");
//改
db.execSQL("update users set password=? where username=?",new Object[]{password,username});
//查
Cursor cursor=db.rawQuery("users",new String[]{"id","username","password","age"},"id=?",new String[]{id},null,null,null);
更多推荐
所有评论(0)