页面跳转

1
2
3
4
5
6
7
8
9
10
//切换页面
//0
startActivity(new Intent(this,SecondActivity.class););
//1
Intent intent1 = new Intent(this,SecondActivity.class);
startActivity(new Intent(this,SecondActivity.class));
//2
Intent intent2 = new Intent();
intent2.setClass(this,SecondActivity.class);
startActivity(intent2);

实现多监听器

点击不同按钮,触发不同的点击事件,在重写方法时,使用逻辑判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    @Override
public void onClick(View view) {
//跳转回第一个页面
if(view == buttonto1st){
Intent intent2 = new Intent();
intent2.setClass(this,MainActivityToSec.class);
startActivity(intent2);}
//跳转百度
else if(view == buttonbd){
startActivity(new Intent(this,MainActivityToSec.class));
Uri uri=Uri.parse("https://www.baidu.com");
startActivity(new Intent(Intent.ACTION_VIEW,uri));}
}
}

补充:Bundle类

Bundle类是用于为字符串与某组件对象建立映射关系的组件。

Bundle与Intent

Bundle组件与Intent配合使用,可在不同的Activity之间传递数据。

常用方法

将字符串用键值对的形式存放在Bundle对象中

1
putString(String key,String value)

移除指定的键值

1
remove(String key)

获取指定键值

1
getString(String key)

image-20221020185341060

image-20221020185403045

image-20221020185446243

image-20221020185551352

补充:Toast组件

在Android 11中Toast行为发生变更

  • 禁止后台自定义Toast
  • text toast不允许自定义
  • setView()被启用
  • 新增Toast.Callback回调

官方推荐使用Snackbar来代表

Snackbar组件

image-20221020194453485

image-20221020194513221

image-20221020194902706

image-20221020194940000

dialog组件

对话框

带有边框、标题、独立存在的容器,用户能够进行交互。

创建AlertDialog步骤

  1. 创建AlertDialog.Builder对象
  2. 调用Builder对象的setTitle方法设置标题,seticon方法设置图标
  3. 调用Builder对象中的其它相关方法
    1. setMessage
    2. setItems
    3. setSingleChoiceItems
    4. setMultiChoiceItems
    5. setAdapter
    6. setView
  4. 调用setPositionButton、setNegativeButton、setNeutralButton方法设置按钮
  5. 调用create()方法创建AlertDialog对象
  6. 调用AlertDialog对象的show()方法将对话框显示出来

示例

DialogActivity

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
...
public class DialogActivity extends AppCompatActivity implements View.OnClickListener{
Button dialogbtn1;
Button dialogbtn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialog);
dialogbtn1=(Button) findViewById(R.id.dialogbutton1);
dialogbtn2=(Button) findViewById(R.id.dialogbutton2);
dialogbtn1.setOnClickListener(this);
dialogbtn2.setOnClickListener(this);
}

@Override
public void onClick(View view) {
AlertDialog.Builder dialog = new AlertDialog.Builder( DialogActivity.this);
if(view == dialogbtn1){
dialog.setTitle("对话框");
dialog.setIcon(R.drawable.gawr_gura);
dialog.setMessage("消息对话框示例");
dialog.setPositiveButton("确定",new okClick());
dialog.create();
dialog.show();
}
}
@Override
class okClick implements DialogInterface.OnClickListener{
public void onClick(DialogInterface dialog,int which){
dialog.cancel();
};
}
}

shift+alt+enter 补全包

Menu组件

三类菜单

  • 选项菜单(OptionsMenu)
  • 上下文菜单(ContextMenu)
  • 弹出菜单(PopupMenu)

菜单设计

涉及Menu菜单和MenuItem菜单项对象

使用add(int groupid,int itemid,int order,CharSequence title)添加菜单项

  • groupid:组别,如果不分组则为Menu.NONE
  • Itemid:系统根据该itemid来确定不同的菜单项
  • order:决定菜单项顺序
  • title:菜单项显示的文本

菜单可以在代码中动态生成,也可以使用布局文件通过inflate()函数映射到程序代码中。

如何实现呢?(本章最后一节)

选项菜单

相关方法

重写两个方法

  • onCreateOptionsMenu(Menu menu)
    • 用于初始化菜单,menu为Menu对象实例
  • onOptionsItemSelectd(Menu menu)
    • 用于相应菜单事件,即菜单项的监听方法

制作流程

  1. 重写onCreateOptionsMenu()方法

    • @Override

      public boolean onCreateOptionsMenu(Menu menu){

      super.onCreateOptionsMenu(menu);

      }

  2. 调用add()方法添加MenuItem菜单项

    • 调用MenuItem的setIcon()方法设置菜单图标
  3. 当菜单项被选中时,通过重写onOptionsItemSelected()方法响应事件

    • @Override
      public boolean onOptionsItemSelected(MenuItem menuItem){

      return true;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Menu1Activity extends AppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu1);
textView = (TextView) findViewById(R.id.menu1tw);
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
super.onCreateOptionsMenu(menu);

menu.add(1,1,1,"选项1");
menu.add(1,2,2,"选项2");
menu.add(1,3,3,"选项2");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem){
textView.setText("您选择了"+menuItem.getTitle().toString());
return true;
}

上下文菜单

类似于右键菜单,在手机中表现为长按

相关方法

  • 建立菜单,添加菜单项
1
2
3
4
5
@Override
public boolean onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info){
...
return true;
}
  • 用于响应菜单事件
1
2
3
4
5
@Override
public boolean onContextItemSelected(MenuItem menu){
...
return true;
}
  • 为视图注册上下文菜单
1
registerforContextMenu()

具体案例

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.lptexas.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class ContextMenuActivity extends AppCompatActivity {
ImageView imageView;
TextView textView;
private static final int item1 = Menu.FIRST;
private static final int item2 = Menu.FIRST+1;
private static final int item3 = Menu.FIRST+2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_context_menu);
imageView = (ImageView) findViewById(R.id.imgmenu);
textView = (TextView)findViewById(R.id.ContextMenuTV);

registerForContextMenu(imageView);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo info){
menu.add(0,item1,0,"你干嘛?");
menu.add(0,item2,0,"??");
menu.add(0,item3,0,"虾米?");
}
@Override
public boolean onContextItemSelected(MenuItem menu){
switch (menu.getItemId()){
case item1:
textView.setText(menu.getTitle().toString());
break;
case item2:
textView.setText("蛤?"+menu.getTitle().toString());
break;
case item3:
textView.setText(""+menu.getTitle().toString());
break;
}
return true;
}
}

弹出菜单

弹出菜单,一个模态形式展示的弹出风格的菜单,绑在在某个View上,一般出现在被绑定的View的下方(如果下方有空间)。

核心步骤

(1)通过PopupMenu的构造函数实例化一个PopupMenu对象,需要传递一个当前上下文对象以及绑定的View。

(2)调用PopupMenu.setOnMenuItemClickListener()设置一个PopupMenu选项的选中事件。

(3)使用MenuInflater.inflate()方法加载一个XML文件到PopupMenu.getMenu()中。

(4)在需要的时候调用PopupMenu.show()方法显示。

具体案例

PopupMenuActivity.java

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
package com.lptexas.myapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.PopupMenu;
import android.widget.Toast;



public class PopupMenuActivity extends AppCompatActivity implements View.OnClickListener, MenuItem.OnMenuItemClickListener {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popup_menu);

button=(Button) findViewById(R.id.button11);
button.setOnClickListener(this);
}

//点击按钮后,加载弹出式菜单
@Override
public void onClick(View view) {
//创建弹出式菜单对象(最低版本11)
PopupMenu popupMenu = new PopupMenu(this,view);
//获取菜单填充器
MenuInflater menuInflater=popupMenu.getMenuInflater();
//填充菜单
menuInflater.inflate(R.menu.popupmenu,popupMenu.getMenu());
//绑定菜单项的点击事件
popupMenu.setOnMenuItemClickListener(this::onMenuItemClick);
//显示
popupMenu.show();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.exit1:
Toast.makeText(this, "退出", Toast.LENGTH_SHORT).show();
break;
case R.id.set1:
Toast.makeText(this, "设置", Toast.LENGTH_SHORT).show();
break;
case R.id.account1:
Toast.makeText(this, "账号", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return false;
}
}

activity_popup_menu.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PopupMenuActivity">

<Button
android:id="@+id/button11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="弹出菜单"
tools:layout_editor_absoluteX="128dp"
tools:layout_editor_absoluteY="46dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

新建资源文件夹menu

image-20221021090047715

popupmenu.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

<item android:id="@+id/exit1"
android:title="退出"/>
<item android:id="@+id/set1"
android:title="设置"/>
<item android:id="@+id/account1"
android:title="账号"/>
</menu>

inflate()函数

在popupmenu的例子中我们应用到了这个函数

详情参阅:用Android MenuInflater创建菜单项的方法步骤


之前提到过了的

安卓内部存储与外部存储

安卓文件系统

内部存储(internal storage)

外部存储(external storage)

image-20221030095049175

1
2
3
4
5
6
7
8
/ - system
data - data - package_name
com.snakuai.meituan
storage - sdcard1
emulated - 0 - Android - data - package_name
com.snakuai.meituan
Download
...

安卓对内外部存储的划分是逻辑上的划分。

内部存储空间

data文件夹中需要关注两个文件夹

  1. app文件夹
    • 存放所有安装程序的apk文件
    • 调试时控制台输出的uploading就是上传至此文件夹中
  2. data文件夹
    • 包名,每个app系统都会在data/data目录下以应用包名为名字自动创建与之对应的文件夹
    • 这些文件夹是应用(APP)私有的。
      • 应用可以不需要任何系统权限即可读写和写入这些目录中的文件,其它应用无法访问。
    • 这些文件夹用于App中的WebView缓存页面信息,SharePreferences和SQLiteDatabase持久化应用相关数据等
      • 持久性文件根目录File:context.filesDir(),/data/data/包名/files/
      • 缓存性文件根目录File:context.cacheDir(),/data/data/包名/cache/

android提供了一些简便的api创建删除文件

1
2
3
4
5
context.openFileOutput(filename,Context.MODE_PRIVATE);
context.openFileInput(filename);
context.fileList();
context.getDir(dirName,Context.MODE_PRIVATE);
context.deleteFile(fileName);

注:卸载app后,系统自动删除data/data目录下对应包名的文件夹及其内容。

注:data/data目录很像C盘的programfile文件夹

外部存储空间

storage目录(也有的是mnt),平时操作多是外部存储。

私有目录

对应/storage/emulated/0/Android/data/包名

应用私有目录卸载之后,其文件也会被删除(类似于内部存储)。和内部存储不同的是这个目录可以被其它应用访问。

公共目录

对应/storage/emulated/0/中除Android文件夹以外的文件夹

目录可被自由访问,且其中数据对其他应用或者用户来说都是有意义的,当应用被卸载后,其卸载前创建的文件任然保留。

对比

image-20221030094609080

调用方法

image-20221030141626758

注:安卓10开启分区存储后,将无法直接通过File操作公共目录,只能通过MediaStore去操作。

MediaStore

参见:https://blog.csdn.net/LoneySmoke/article/details/108944485