Apin

blogs

Android开发学习

此文章属于原创,如需使用请标明出处!

Android开发学习

记录我在学习开发 Android 时遇到的问题和解决方法,以及对一些小知识点进行汇总。

Android Studio 为程序构建了基本结构:

  • manifests:整个程序的配置文件;
  • java:存放程序的代码文件;
  • res:存放程序的资源文件;
  • build.gradle:程序或模块的 gradle 构建脚本等;

布局和控件

在 Android Studio 开发程序,所有的界面布局都可以在 layout 目录下的XML布局文件中定义。

Android 常见界面布局:

  • 线性布局 LinearLayout;
  • 相对布局 RelativeLayout;
  • 表格布局 TableLayout;
  • 帧布局 FrameLayout;

Android 常见界面控件:

  • TextView;
  • EditText;
  • Button;
  • ImageView;
  • RadioButton(单选);
  • CheckBox(多选);
  • Toast(轻量信息提醒);
  • ListView(列表形式展示数据内容);
  • RecyclerView(对 ListView 的扩展);

居中


控件居中

LinearLayout

(1)android:layout_gravity="center_horizontal" 表示该布局在父布局里水平居中,此时其父布局必须拥有 android:orientation="vertical" 属性;

(2)android:layout_gravity="center_vertical" 表示该布局在父布局里垂直居中,此时其父布局必须应设置成 android:orientation="horizontal" 属性(默认为该属性);

线性布局中不同时存在水平居中和垂直居中。

RelativeLayout

属性值为 true 或 false;

(1)android:layout_centerHrizontal 控件在父布局中 水平居中;

(2)android:layout_centerVertical 控件在父布局中 垂直居中;

(3)android:layout_centerInparent 控件相对于父元素完全居中;


文本居中

android:gravitu="center" 文字在控件的中心;


TextView 组合图片

当你想把文本和图片组合在一起显示,而且不想繁杂的设置图片位置,可以使用 TextView 的 android:drawableXxx="@drawable/xxx",便捷的在文本标签的四周添加一张图片;

例如:

1
2
3
4
<TextView
android:drawableTop="@drawable/qq_icon"
android:text="用QQ注册"
style="@style/tvOne"/>

设置 Button 点击事件

(1)在布局文件中指定 onClick 属性的值;

1
2
3
<Button
...
android:onClick="click" />

在 Activity 中定义专门的方法实现 Button 控件的点击事件;

(2)

使用匿名内部类;

1
2
3
4
5
6
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//实现点击事件的代码
}
})

setOnClickListener() 方法传递一个匿名内部类。

(3)使用 Activity 实现 OnClickListener 接口

1
2
3
4
5
6
7
8
9
10
11
public class Activity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
...
btn.setOnClickListener(this); //设置 Button 控件的点击监听事件
}
@Override
public void onClick(View view) {
//实现点击事件的代码
}
}

如果界面上的 Button 控件较多,建议使用第三种方式实现控件点击事件。


RecyclerView


内容不可见

布局 Layout XML 文件内容如下:

1
2
3
4
5
6
7
8
9
<?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">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lv"/>
</LinearLayout>

实际上,不管是使用 ListView 还是 RecyclerView,你都会发现列表视图的内容没有正确显示。

经过测试,发现这是布局的问题,而不是 Java 代码的问题:

我在 RecyclerView 的外面套了一层 LinearLayout 作为父容器,而 LinearLayout 默认方向是 Horizontal(横向),会与 RecyclerView 的垂直布局产生冲突,从而导致 RecyclerView 的内容无法显示。

因此,解决办法就是在 LinearLayout 的属性中设置方向为垂直方向:

1
android:orientation="vertical"

当然你也可以选择不在 RecyclerView 外面套一层 LinearLayout。

到目前为止,你已经可以成功解决 ListView 的显示问题,而 RecyclerView 还需要进一步的设置:为 RecyclerView 设置一个 LayoutManager:

例如:

1
2
rv_list.setAdapter(rightAdapter);
rv_list.setLayoutManager(new LinearLayoutManager(getActivity()));

最后,你就可以解决 RecyclerView 内容不显示的问题了!


Item 长宽错误

注意在上面的项目中,实际效果应该是如下图所示:

之所以会出现 Item 高度过长的问题,是应为我在 Item 布局文件中,将 RelativeLayout 布局的 layout_widthlayout_height 设置为了 match_parent

因此我们要注意 Item 布局的特殊性,它作为列表中的一项,应该将高度设置为 wrap_content,以防出现 Item 的不正常显示。当然具体问题具体分析,不过一般情况都是这样的。

修改后的部分布局代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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="wrap_content">
<ImageView
.../>
<TextView
.../>
<TextView
.../>
<TextView
.../>
</RelativeLayout>

Activity

Android 中的四大组件分别是 Activity、Service、ContentProvider 和 BroadcastReceiver。其中,Activity 是一个负责与用户交互的组件。每个Android 应用程序中都会用 Activity 来显示界面以及处理界面上一些控件的事情。


数据回传

如果项目中的 appcompat 库是1.3.0或更高的版本,你会发现 startActivityForResult() 方法已经被放弃了,现在更建议使用 Activity Result API 来实现在两个 Activity 之间交换数据的功能。

注意:registerForActivityResult 只能在 onCreate() 中注册。onstart() 之后就不能注册了。

registerForActivityResult() 方法不要放在 setOnClickListener() 里面,要放在 onCreate 里。

例如:

1
2
3
4
5
6
7
8
9
10
ActivityResultLauncher launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if(result.getResultCode()==1){
int count = result.getData().getIntExtra("count",0);
totalCount += count;
tv_count.setText("摘到"+totalCount+"个");
}
}
});
  1. 两个参数:

    • 第一个参数,需要传入 ActivityResultContract,指返回数据的类型;
    • 第二个参数,需要传入一个回调 ActivityResultCallback,数据返回时调用这个方法获取并处理数据;
  2. 返回值:它返回一个 ActivityResultLauncher 对象;

  3. 用法:调用 ActivityResultLauncher 的 launch() 方法可以跳转到另一个 Activity 或者发起权限请求;

注意:使用 startActivityForResult() 方法,可以传入 requestCode 用于区分请求来源;而 Activity Result API 不存在这个参数,实际上也不需要这个 requestCode 参数;

1
2
private ActivityResultLauncher actionViewLauncher = registerForActivityResult(...);
private ActivityResultLauncher actionDialLauncher = registerForActivityResult(...);
1
2
3
4
5
6
7
8
firstButton.setOnClickListener {
Intent intent = Intent(Intent.ACTION_VIEW);
actionViewLauncher.launch(intent);
}
secondButton.setOnClickListener {
Intent intent = Intent(Intent.ACTION_DIAL);
actionDialLauncher.launch(intent);
}

给每个需要数据回传的控件创建一个 ActivityResultLauncher 实例可以完美解决定位请求来源的问题,而且一切都更加简单和清晰。


添加 Fragment

Fragment(碎片)是一种嵌入在 Activity 中的 UI 片段,它可以用来描述 Activity 中的一部分布局(相当于控件容器)。

在 Activity 中添加 Fragment 有两种方法:

  1. 在布局文件中添加 Fragment

    使用 <fragment></fragment> 标签,必须指定其 android:name 属性,其属性值为 Fragment 类的路径全名称。

    示例如下:

    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
        <fragment
    android:id="@+id/right_frag"
    android:name="com.itcast.menu.RightFragment"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="3" />

    2. **在 Activity 中动态加载 Fragment**

    在 Activity 运行时,可以将 Fragment 动态添加到 Activity 中,具体步骤如下:

    (1)创建 Fragment 对象;

    (2)获取 FragmentManager(Fragment 管理器)的实例;

    (3)开启 FragmentTransaction(事务);

    (4)向 Acticity 的布局容器中添加 Fragment;

    (5)通过 `commit()` 方法提交事务;

    示例代码如下:

    ```java
    public void switchData(List<FoodBean> list){
    rightFragment = new RightFragment().getInstance(list); //创建 Fragment 对象
    fragmentManager = getFragmentManager();
    fragmentTransaction = fragmentManager.beginTransaction(); //开启事务
    fragmentTransaction.replace(R.id.right_frag,rightFragment); //添加 Fragment
    fragmentTransaction.commit(); //提交事务
    }

注意:如果 Fragment 是静态无变化的,只需要在布局文件中添加标签和创建相应的 Fragment 类,就可以显示 Fragment。

如果你还需要与该 Fragment 进行通信或者控制该Fragment的行为,你可以在 Activity 中获取 Fragment 对象(确保布局加载完成),并对其进行操作(允许不进行操作)。虽然你可以不获取 Fragment,但可能会导致应用程序出现错误或不可预测的行为。

因此,在添加静态 Fragment 后,建议在 Activity 中获取 Fragment 对象,并在必要时与 Fragment 进行交互,以确保应用程序正常运行并提供正确的用户体验。

注意:添加动态 Fragment 时,虽然通过事务改变 Fragment,但是动态 Fragment 会需要有一个初始状态,即动态 Fragment 的 android:name 属性是必须的。