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有固定的数据组织形式
ArrayAdapterSimpleAdapter继承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。而且RadioGroupLinearLayout的子类,可以通过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),存放在SDKplatform-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);
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐