• Android -- Activity和Fragment


    ⒈简介

      我们在App上看到的每一个界面它就需要一个Activity,但Activity并不等同于界面,只是界面需要Activity。

      Fragment是碎片化的界面,每一个Activity可以包含很多个Fragment,Fragment不可以作为独立存在的,它必须依赖于Activity,它是受Activity管理的。

    ⒉Activity的创建三部曲

      1.新建类继承Activity或其子类

    package cn.coreqi.activity;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class TestActivity extends AppCompatActivity {
    }

      2.在AndroidManifest中声明

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="cn.coreqi.helloworld2">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name="cn.coreqi.activity.TestActivity"></activity>
            <activity android:name=".ButtonActivity"></activity>
            <activity android:name=".TextViewActivity" /> <!-- 注册 activity -->
            <activity android:name=".MainActivity"> <!-- .前面默认会加包名,上面声明了包名,此处为cn.coreqi.helloworld2.MainActivity -->
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <!-- 设置当前activity为应用启动的第一个activity -->
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

      3.创建layout文件(布局文件)并在Activity的onCreate中设置。  

      在res/layout下新建布局文件

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

      并且在Activity的onCreate方法中设置

    package cn.coreqi.activity;
    
    import android.os.Bundle;
    
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatActivity;
    
    import cn.coreqi.helloworld2.R;
    
    public class TestActivity extends AppCompatActivity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_test);
        }
    }

      一些小技巧

      设置Activity标题头

            <activity android:name=".MainActivity"
                android:label="启动页"> <!-- .前面默认会加包名,上面声明了包名,此处为cn.coreqi.helloworld2.MainActivity -->
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <!-- 设置当前activity为应用启动的第一个activity -->
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>

      取消标题头(单个Activity)

            <activity android:name=".MainActivity"
                android:theme="@style/Theme.AppCompat.Light.NoActionBar"> <!-- .前面默认会加包名,上面声明了包名,此处为cn.coreqi.helloworld2.MainActivity -->
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <!-- 设置当前activity为应用启动的第一个activity -->
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>

      取消标题头(全局Activity)

        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.AppCompat.Light.NoActionBar">

      设置Activity的屏幕方向

            <activity android:name="cn.coreqi.activity.TestActivity"
                android:screenOrientation="portrait"></activity><!--竖屏显示-->

      设置Activity的启动模式

            <activity android:name="cn.coreqi.activity.TestActivity"
                android:launchMode="singleInstance"></activity>

    ⒊Activity的生命周期

      一个Activity被部署到安卓应用之后跟随应用进程运行,它会在不同的状态之间进行切换,并且在切换状态的同时也会回调相应的方法,我们把Activity不同的状态称之为Activity的生命周期。

      

      

      当点击进入Activity时,执行三个Activity生命周期方法,分别是onCreate、onStart、onResume,点击返回按钮时,执行三个生命周期方法,分别是onPause(暂停)、onStop(停止)、onDestroy(摧毁)。

      停留界面切换到后台,这时候Activity将会运行到onPaue(暂停)及onStop(停止)方法中去,切换回来后,Activity将会运行onResume方法

      常用的生命周期方法,onCreate,onResume(数据刷新等),onPause(当前数据暂停)、onDestroy(当前页面摧毁需要做的事情)。

    ⒋Active的跳转和数据传递

      跳转

      • 显式跳转
            //显示跳转1
            Intent intent1 = new Intent(AActivity.this,BActivity.class); //Intent 意图
            startActivity(intent1);
    
            //显示跳转2
            Intent intent2 = new Intent();
            intent2.setClass(AActivity.this,BActivity.class);
            startActivity(intent2);
    
            //显示跳转3
            Intent intent3 = new Intent();
            intent3.setClassName(AActivity.this,"cn.coreqi.activity.BActivity");
            startActivity(intent3);
    
            //显示跳转4
            Intent intent4 = new Intent();
            intent4.setComponent(new ComponentName(AActivity.this,"cn.coreqi.activity.BActivity"));
            startActivity(intent4);
      • 隐式跳转
            <activity android:name="cn.coreqi.activity.BActivity">
                <intent-filter>
                    <action android:name="fanqi.BActivity"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </activity>
            //隐式调用
            Intent intent1 = new Intent();
            intent1.setAction("fanqi.BActivity");
            startActivity(intent1);

      Activity之间的数据传递

            //传递
            Intent intent = new Intent(AActivity.this,BActivity.class);
            //intent.putExtra("name","fanqi");
            Bundle bundle = new Bundle();   //数据的传递通过Bundle
            bundle.putString("name","fanqi");
            intent.putExtras(bundle);
            startActivity(intent);
            //接收
            Bundle bundle = getIntent().getExtras();
            String name = bundle.getString("name");
            Log.d("t",name);

      startActivityForResult:启动Activity,结束后返回结果。

            Intent intent = new Intent(AActivity.this,BActivity.class);
            //将请求码为0的数据携回
            startActivityForResult(intent,0);
            //返回数据
            Bundle bundle = new Bundle();
            bundle.putString("name","fanqi");
            Intent intent = new Intent();
            intent.putExtras(bundle);
            setResult(Activity.RESULT_OK,intent);
            finish();
        @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            Log.d("requestCode",String.valueOf(requestCode));
            Log.d("resultCode",String.valueOf(resultCode));
            Log.d("data",data.getExtras().getString("name"));
        }

    ⒌Activity的4种启动模式

      Activity的android:launchMode属性

      • standard:标准模式,默认【每启动一个Activity就会去创建这个Activity新的实例,不管这个Activity之前有没有启动过,是否存在,只要启动,就会创建新的实例】
      • singleTop:Task栈顶复用模式【当我们启动一个Activity,如果我们要启动的Activity位于栈的栈顶,那么就不会去创建新的实例,而是会直接复用这个栈顶的Activity,如果Activity实例不在栈顶或者实例根本不存在,那么还是会去创建一个新的实例】
      • singleTask:Task栈内复用模式【只要栈里面存在我们需要的Activity实例,就可以复用】
      • singleInstance:全局单例模式【全局复用模式,会在当前应用所有的栈里面复用。】

      Activity是由任务栈管理的,每启动一个Activity,就会被放入栈中,按返回键,就会从栈顶移除一个Activity。

      standard是默认的启动模式,即标准模式,每启动一个Activity,都会创建一个新的实例。

            <activity android:name="cn.coreqi.activity.BActivity"
                android:launchMode="standard">
                <intent-filter>
                    <action android:name="fanqi.BActivity"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </activity>

       singleTop:当要启动的目标Activity已经位于栈顶时,不会创建新的实例,会复用栈顶的Activity,并且其onNewIntent()方法会被调用;如果目标Activity不在栈顶,则跟standard一样创建新的实例。

      singleTask:在同一个任务栈中,如果要启动的目标Activity已经在栈中,则会复用该Activity,并调用其onNewIntent()方法,并且该Activity上面的Activity会被清除;如果栈中没有,则创建新的实例。

      **设置Activity任务栈名称

            <activity android:name="cn.coreqi.activity.BActivity"
                android:launchMode="standard"
                android:taskAffinity="fanqi.task">
            </activity>

      singleInstance:全局复用,不管哪个Task栈,只要存在目标Activity,就复用。每个Activity占有一个新的Task栈。【应用的相当少,如果我们的Activity需要频繁的被其他应用所调用】

    ⒍Fragment

      Fragment有自己的生命周期

      Fragment依赖于Activity【当Activity销毁的时候Fragment会同步被销毁】

      Fragment通过getActivity()可以获取所在的Activity;Activity通过FragmentManager的findFragmentById()或findFragmentByTag()获取Fragment

      Fragment和Activity是多对多的关系【一个Fragment可以存在于多个Activity当中,可以被多个Activity所包含,多个Fragment也可以在一个Activity当中】

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="#000000"
            android:textSize="20sp"
            android:text="我是AFragment"
            android:gravity="center"/>
    </LinearLayout>
    package cn.coreqi.fragment;
    
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import androidx.fragment.app.Fragment;
    
    import cn.coreqi.helloworld2.R;
    
    public class AFragment extends Fragment {
        private TextView mTvTitle;
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_a,container,false);
            return view;
        }
    
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            mTvTitle = view.findViewById(R.id.tv_title);
        }
    }
    package cn.coreqi.fragment;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    
    import cn.coreqi.helloworld2.R;
    
    public class ContainerActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_container);
    
            AFragment aFragment = new AFragment();
            //把AFragment添加到Activity指定的位置中,记得调用commit
            getSupportFragmentManager().beginTransaction().add(R.id.fl_container,aFragment).commitAllowingStateLoss();
    
        }
    }

     ⒎一些Fragment常见问题

      Fragment中getActivity()为null的问题

        1.使用if进行判断

        2.在Fragment子类中声明Activity变量并在Fragment的声明周期中赋值(可能内存泄漏,最好不要用)。

      如何向Fragment传递参数

        Fragment.setArguments()

        Fragment.getArguments()

    ⒏Fragment回退栈

      一个Activity它是由任务栈管理的,每启动一个Activity都会把它放到任务栈中,这时候每按下返回键,就会依次从栈顶弹出一个Activity,这是一个回退的过程。

      Fragment同样可以达到这样的一个过程,往一个Activity中and了多个Fragment,按下返回键时,把这些Fragment依次回退。

            AFragment aFragment = new AFragment();
            //把AFragment添加到Activity指定的位置中,记得调用commit
            getSupportFragmentManager().beginTransaction().add(R.id.fl_container,aFragment).commitAllowingStateLoss();
            //用BFragment替换AFragment,并添加到回退栈中去。这样按下返回键就不会回退到上一个Activity。
            //**虽然返回到AFragment还是以前的实例,但是AFragment的视图会被重新渲染,即会调用AFragment的onCreateView方法
    
            BFragment bFragment = new BFragment();
            getSupportFragmentManager().beginTransaction().replace(R.id.fl_container,bFragment).addToBackStack(null).commitAllowingStateLoss();
    
    
    
    
            //如果不要AFragment的视图被重新渲染,即不要调用replace方法,因为replace方法本质上是先remove然后再add
            AFragment aFragment = new AFragment();
            //把AFragment添加到Activity指定的位置中,记得调用commit
            getSupportFragmentManager().beginTransaction().add(R.id.fl_container,aFragment,"a").commitAllowingStateLoss();
            Fragment fragment = getSupportFragmentManager().findFragmentByTag("a");
            if(fragment != null){
                getSupportFragmentManager().beginTransaction().hide(fragment).add(R.id.fl_container,bFragment).addToBackStack(null).commitAllowingStateLoss();
            }else{
                getSupportFragmentManager().beginTransaction().replace(R.id.fl_container,bFragment).addToBackStack(null).commitAllowingStateLoss();
            }

     ⒐Fragment和Activity的通信

      在Activity中提供一个方法完成对私有字段(数据)的修改

        public void setData(String text){
            mTvTitle.setText(text);
        }

      在Fragment中使用getActivity

    ((ContainerActivity)getActivity()).setData("fanqi");

      

      还有一种更加推荐的方式

      在Acticity中去实现一个在Fragment中声明的接口,通过回调接口去实现数据的传递

      首先,在Fragment的实现类中去声明一个接口

        public interface IOnMessageClick{
            void onClick(String text);
        }

      然后,在Activity的子类中去实现它

        public void setData(String text){
            mTvTitle.setText(text);
        }

      其次,在Fragment的实现类中声明接口的私有变量,并重写onAttach(Context context)方法

        private IOnMessageClick listener;
    
        /**
         * 当Fragment被应用到Activity的时候,Fragment的onAttach方法会被调用
         * @param context 即应用的Activity
         */
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            try {
                listener = (IOnMessageClick) context;
            }catch (ClassCastException e){
                throw new ClassCastException("Activity 必须实现 IOnMessageClick接口");
            }
        }
    
        public void test(){
            //使用
            listener.onClick("fanqi");
        }
  • 相关阅读:
    java多线程基础(一)
    重构总体思路
    【Gearman学习笔记】分布式处理入门
    virtualbox安装提示出现严重错误解决办法
    驱动程序vmci.sys版本不正确。请尝试重新安装 VMware
    Gearman任务分布系统部署windows平台_使用Cygwin
    Fatal error: Class 'GearmanClient' not found解决方法
    header('Content-type:text/html;charset = utf-8');出现中文乱码
    heredoc和nowdoc的区别
    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
  • 原文地址:https://www.cnblogs.com/fanqisoft/p/12165145.html
Copyright © 2020-2023  润新知