Android后退堆栈

修改代码

现在的ItemClick使得用户单击其中一个项目时就会跳转,现在要修改其使得在一个小屏幕设备上才会这样做,在一个大屏幕设备上运行用户选择一个训练项目时在右边的片段显示响应的信息。

希望片段处理后退的方式:假设用户在手机上运行这个应用,单击一个训练项目时,会在另一个活动中显示这个训练项目的详细信息。如果用户单击后退按钮,他们会回到训练项目列表。在平板上后退时则希望回到之前选择的第一个项目,回到前一个片段的状态。

后退堆栈

在应用中从一个活动访问到另一个活动时,Android会把各个活动增加到一个后退堆栈,来跟踪你访问过的所有活动,后退堆栈是一个日志,记录了你在设备上访问过的所有地方,每个地方记录为一个单独的事务。
后退堆栈不止适用于活动,还适用于任何类型的事务,包括对片段的改变。

如何将片段的变化作为单独的事务记录到后退堆栈呢?
每次用户选择一个不同的训练项目时,我们都要把整个WorkoutDetailFragment替换为一个新实例,WorkoutDetailFragment的各个新实例将显示用户选择的训练项目的详细信息。这样我们就能把各个片段替换作为单独的事务增加到后退堆栈。每次用户单击后退按钮时,最近的事务就会从栈顶退出,用户会看到他们选择的前一个训练项目的信息。

使用帧布局替换片段

将activity_main.xml(large)中的代码替换如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:name="com.hfad.workout.WorkoutListFragment"
        android:id="@+id/list_frag"
        android:layout_width="0dp"
        android:layout_weight="2"
        android:layout_height="match_parent"/>

    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="match_parent" />
</LinearLayout>

然后我们可以通过布局差别区分设备使用的布局,通过检查布局是否包含上一页我们增加的帧布局来区分所使用的布局版本,代码如下:

 View fragmentContainer = findViewById(R.id.fragment_container);
 if (fragmentContainer != null){
     
 }else {

使用片段事务

只要活动在允许,可以通过编程向活动的布局增加一个片段。为此只需要一个用来放置片段的视图组,如帧布局。可以使用片段事务在运行时增加、替换或删除片段。片段事务是与片段有关的一组连续的片段。
创建一个片段事务时,需要做三件事:
1、开始事务
这会告诉Android你要启动一系列改变,这些改变要记录在一个事务中。
2、指定改变
这些是事务中要包含的所有动作。这可能包括增加、替换或删除一个片段、更新它的数据,以及把它增加到后退堆栈。
3、提交事务
这会完成事务,并应用所做的改变。
1、开始事务
开始一个事务时,首先得到活动的片段管理器的一个引用。从上一章可以知道,片段管理器用于管理活动使用的所有片段。如果你使用了支持库片段,要使用以下方法得到片段管理器的引用:

getSupportFragmentManager()

一旦有了片段管理器的引用,可以调用它的beginTransaction()方法开始事务:

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

2、指定改变
开始事务后,需要指出这个事务包括哪些片段。
如果想为活动的布局增加一个片段,可以调用片段事务的add()方法。这个方法有两个参数,要加入片段的那个视图组的资源ID,以及你想要增加的片段。代码如下:

//创建片段
WorkoutDetailFragment fragment = new WorkoutDetailFragment();
//将片段添加到ViewGroup
transaction.add(R.id.fragment_container, fragment);
//替换片段
transaction.replace(R.id.fragment_container, fragment);
//删除片段
transaction.remove(fragment);
//设置事务过渡动画(非必需)
transaction.setTransition(transaction);
//将事务增加到后退堆栈中,其参数是一个String类,可以作为事务的标签,大多数情况下都不需要指定事务的标签传入null
transaction.addToBackStack(null);

3、提交事务

//提交事务
transaction.commit();

更新MainActivity中的itemClicked方法

package com.hfad.workout;

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity implements WorkoutListFragment.Listener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void itemClicked(long id) {
        View fragmentContainer = findViewById(R.id.fragment_container);
        if (fragmentContainer != null){
            WorkoutDetailFragment details = new WorkoutDetailFragment();
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            details.setWorkoutId(id);
            //每次用户单击一个训练项目时,要把这个片段替换为它的一个新实例
            //这是WorkoutDetailFragment的一个新实例,它会显示用户选择的那个训练项目的详细信息。
            ft.replace(R.id.fragment_container, details);
            //设置片段淡入淡出
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            //将这个事务增加到后退堆栈
            ft.addToBackStack(null);
            ft.commit();
        }else {
            Intent intent = new Intent(this, DetailActivity.class);
            intent.putExtra(DetailActivity.EXTRA_WORKOUT_ID, (int)id);
            startActivity(intent);
        }

    }
}

试着运行一下,可以达到预期效果了
在这里插入图片描述

旋转屏幕时会出问题

选装设备时,Android会撤销然后重新创建活动,如果该活动使用了一个片段,这个片段会随着这个活动撤销和重建。所以仍然需要更新onSaveInstance保存信息,在onreate中取出。
更新WorkoutDetailFragment.java

package com.hfad.workout;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import android.os.PersistableBundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class WorkoutDetailFragment extends Fragment {

    //用来表示用户选择的训练项目的ID
    private long workoutId;

    @Override
    //Android需要这个片段的布局时会调用这个方法
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 这会告诉Android这个片段使用哪个布局
        return inflater.inflate(R.layout.fragment_workout_detail, container, false);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState != null){
            workoutId = savedInstanceState.getLong("workoutId");
        }
    }

    public void onStart() {
        super.onStart();
        //得到片段的根视图,然后使用这个根视图得到两个文本视图的引用
        View view = getView();
        if (view != null) {
            TextView title = (TextView) view.findViewById(R.id.textTitle);
            Workout workout = Workout.workouts[(int)workoutId];
            title.setText(workout.getName());
            TextView description = (TextView) view.findViewById(R.id.textDescription);
            description.setText(workout.getDescription());
        }
    }

    public void setWorkoutId(long id) {
        this.workoutId = id;
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putLong("workoutId", workoutId);
    }
}

自此、大功告成!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android开发中,打印堆栈信息可以提供调试和错误排查的有力工具。以下是一种常用的方法来打印堆栈信息。 在代码中,我们可以使用Throwable类的printStackTrace方法来获得堆栈信息。例如: ``` try { // 可能会引发异常的代码 } catch (Exception e) { e.printStackTrace(); } ``` 这段代码会将异常的堆栈信息输出到Logcat中。如果你在IDE中运行你的代码,可以在Logcat窗口中查看到完整的堆栈信息,包括异常类型、异常出现的位置以及调用栈。 另外,我们也可以通过Log类的相关方法来打印堆栈信息。例如,在catch块中使用Log.e来输出异常的信息: ``` try { // 可能会引发异常的代码 } catch (Exception e) { Log.e("TAG", "出现异常:", e); } ``` 这样,异常信息会作为日志信息输出到Logcat中。通过指定TAG,你可以将这些日志筛选出来,方便查看和分析。 除了在Java代码中打印堆栈信息外,你还可以在任何时候使用adb命令来获取堆栈信息。例如,在终端中输入以下命令: ``` adb logcat -d | grep "Exception" ``` 这个命令会输出所有包含"Exception"关键字的日志信息,包括堆栈信息。 总结起来,打印堆栈信息是Android开发中非常有用的调试工具。通过在代码中使用printStackTrace或Log类的相关方法,以及使用adb命令,我们可以获取到异常发生的位置和调用栈信息,便于排查和定位错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值