当前位置:   article > 正文

《黑马程序员Android移动应用基础教程》学习笔记(4)_andriod 开发 教程 黑马资料

andriod 开发 教程 黑马资料

Ch4 程序活动单元Activity

Android四大组件:Activity,Service,ContentProvider,BroadcastReceiver
Activity负责与用户交互

4.1 Activity的生命周期

4.1.1 生命周期状态

Activity的生命周期指Activity从创建到销毁的整个过程。

  1. 启动状态
    一般情况下,当Activity启动后便会进入运行状态
  2. 运行状态
    Activity在此状态时处于界面最前端,它是可见、有焦点的,可以与用户进行交互。
    当Activity处于运行状态时,Android会尽可能地保持这种状态。如果出现内存不足的情况,Android也会先销毁栈底的Activity来确保当前Activity正常运行。
  3. 暂停状态
    Activity对用户来说依然可见,但无法获取焦点,用户对它操作没有响应。(例如Activity上覆盖了一个透明或非全屏的界面)
  4. 停止状态
    当Activity完全不可见时处于停止状态。
  5. 销毁状态
    当Activity处于销毁状态时,将被清理出内存

Activity生命周期的启动状态和销毁状态是过渡状态,Activity不会在这两种状态停留

4.1.2 生命周期方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-42BfBpSk-1665301447462)(assets/Activity生命周期模型.png)]

  1. onCreat()
    Activity创建时调用
  2. onStart()
    Activity即将可见时调用
  3. onResume()
    Activity获取焦点时调用
  4. onPause()
    Activity被其他Activity覆盖或屏幕锁屏时调用
  5. onStop()
    Activity对用户不可见时调用
  6. onDestroy()
    Activity销毁时调用
  7. onRestart()
    Activity从停止状态到再次启动时调用
    如果程序中只有一个Activity,则程序无法进行从停止状态到再次启动状态的操作。

当手机横竖屏切换时,会根据AndroidManifest.xml文件中Activity的configChanges属性值的不同而调用相应的生命周期方法。
在进行横竖屏切换时,首先会调用onDestory()方法销毁Activity,之后调用onCreate()方法重建Activity。如果不希望在横竖屏切换时Activity被销毁重建,可以通过configChanges属性进行设置

<activity android:name".ManActivity"
          android:configChanges="orientation|KeyboardHidden">
  • 1
  • 2

如果希望某一个界面一直处于竖屏或者横屏状态,可以在清单文件中通过设置Activity的screenOrientation属性完成。

竖屏: android:screenOrientation="portrait"
横屏:android:screenOrientation="landscape"
  • 1
  • 2

4.2 Activity的创建、配置、开启和关闭

4.2.1 创建Activity

[右击包名]->[new]->[Activity]->[Empty Activity]->创建ActivityExample

4.2.2 配置Activity

创建一个SecondAcitvity类继承Activity,当在ActivityExample的onCreat()方法中启动ScondActivity时,会抛出异常信息

package com.milk.learnproject_activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //启动SecondActivity
        Intent intent= new Intent(this,SecondActivity.class);
        startActivity(intent);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DU4RAoOH-1665301447473)(assets/创建Activity抛出异常.png)]
每一个创建的Activity都必须在清单文件AndroidManifest.xml中配置才能生效。
配置SecondAcivity示例代码:

<activity 
    android:name="com.milk.learnproject_activity.SecondActivity"/>
  • 1
  • 2

如果Activity所在的包与AndroidManifest.xml文件的标签中通过package属性指定的包名一致,则android:name属性的值可以直接设置为".Activity名称"

<activity 
    android:name=".SecondActivity"
    android:exported="true"
</activity>
  • 1
  • 2
  • 3
  • 4

android:exported=“true”
这句代码的意思就是该activity允许外部应用调用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AaeqD7R8-1665301447475)(assets/编译器自动配置清单的功能.png)]
编译器有新建Activity时自动修改AndroidManifest.xml配置的功能

4.2.3 开启和关闭Activity

  1. 启动Activity
    可以通过startActivity()方法开启创建的Activity

    public void startActivity(Intend intent)
    
    • 1

    参数Intent为Android应用中各组件之间通信的桥梁,一个Activity通过Intent表达自己的“意图”。
    在MainActivity的onCreate()方法中启动SecondActivity实例代码

    Intent intent = new Intent(MainActivity.this,SecondActivity.class);
    startActivity(intent);
    
    • 1
    • 2
  2. 关闭Activity
    调用Activity的finish()方法关闭当前的Activity

    public void finish()
    
    • 1

    finish()方法既没有参数,也没有返回值,只需要在Activity的相应事件中调用该方法即可。

4.3 Intent与IntentFilter

如果用户需要从一个Activity切换到另一个Activity,则必须使用Intent来进行切换。Intent用于相同或者不同应用程序组件间的绑定。

4.3.1 Intent(意图)

Intent是程序中各组件间进行交互的一种重要方式,它不仅可以指定当前组件要执行的动作,还可以在不同组件之间进行数据传递。

  1. 显示Intent
    显示Intent指直接指定目标组件
    使用Intent显示指定要跳转的目标Activity:

    Intent intent = new Intent(this,SecondActivity.class);
    startActivity(intent);
    
    • 1
    • 2

    第一个参数this表示当前的Activity,第二个参数SecondActivity.class表示要跳转到的目标Activity

  2. 隐式Intent
    隐式Intent不会明确指出需要激活的目标组件

  • action:表示Intent对象要完成的动作
  • data:表示Intent对象中传递的数据
  • category:表示为action添加的额外信息
    使用App1打开App2的SecondActivity:
    SecondActivity的配置代码
<activity
            android:name=".SecondActivity"
            android:exported="true" >
        <intent-filter>
            <action android:name="com.milk.learnproject_activity_secondapp.SE_APP_SE_ACT" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        </activity>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

App1打开SecondActivity的Button点击事件:

button1 = (Button) findViewById(R.id.Button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent();
                intent.setAction("com.milk.learnproject_activity_secondapp.SE_APP_SE_ACT");
                //可以写成Intent intent=new Intent().setAction("com.milk.learnproject_activity_secondapp.SE_APP_SE_ACT");
                startActivity(intent);
            }
        });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

打开bilibili应用

package com.milk.learnproject_activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
    Button button1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button1 = (Button) findViewById(R.id.Button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=getPackageManager().getLaunchIntentForPackage("tv.danmaku.bili");//获得bilibili app的启动包名
                startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在使用隐式Intent开启Activity时,系统会默认为该Intent添加"Android.intent.category.DEFAULT"的category,因此为了被开启的Activity能够接收隐式Intent,必须在AndroidManifest.xml文件的Activity标签下的<intent-filter>中为被开启的Activity指定catrgory为"android:intent.category.DEFAULT"

4.3.2 IntentFilter(过滤器)

当发送一个隐式Intent后,Android系统会将它与程序中每一个组件的过滤器进行匹配,匹配属性有action、data、category,需要三个属性都匹配成功才能唤起相应组件。

  1. action属性匹配规则
    action属性用来指定Intent对象的动作

    <intent-filter>
         <action android:name="android.intent.action.EDIT"/>
         ······
     <intent-filter>
    
    • 1
    • 2
    • 3
    • 4

    标签中间可以罗列多个action属性,但是当使用隐式Intent激活组件时,只要Intent携带的action与其中一个标签中action的声明相同,action属性就匹配成功。

    在清单文件中为Activity添加标签时,必须添加action属性,否则隐式Intent无法开启该Activity。

  2. data属性匹配规则
    data属性用来指定数据的URI或者数据MIME类型,它的值通常与Intent的action属性有关联。

    <intent-filter>
        <data android:mimeType="Video/mpeg" android:scheme="http..."/>
        ···
    </intent-filter>
    
    • 1
    • 2
    • 3
    • 4

    <intent-filter>标签中间可以罗列多个data属性,每个data属性可以指定数据的MIME类型和URI。其中MIME类型可以表示image/ipeg、video/*等媒体类型。
    隐式Intent携带的data与其中一个标签中data的声明相同,data属性就匹配成功。

  3. category属性匹配规则
    category属性用于为action添加额外信息,一个interFilter可以不声明category属性,也可以声明多个category属性。

    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"/>
        ······
    </intent-filter>
    
    • 1
    • 2
    • 3
    • 4

    隐式Intent中声明的category必须全部能够与某一个IntentFilter中的category匹配才算匹配成功。IntentFilter中罗列的category属性数量必须大于或者等于隐式Intent携带的category属性数量时,category属性才能匹配成功。如果一个隐式Intent没有设置category属性,那么它可以通过任何一个IntentFilter的category匹配。

4.4 Activity之间的跳转

4.4.1 在Activity之间数据传递

  1. 使用Intent的putExtra()方法传递数据
    通过putExtra()方法将传递的数据存储在Intent对象后,如果想获取该数据,可以通过getXxxExtra()方法来实现。
  2. 使用Bundle类传递数据
    Bundle类与Map接口比较类似,都是通过键值对的形式来保存数据。
Intent intent = new Intent();
intent.setClass(this,SecondActivity.class);
Bundle bundle = new Bundle();//创建Bundle对象
bundle.putString("account","Admin");//封装用户名信息
bundle.putString("password","123456");//封装密码信息
intent.putExtras(bundle);//将Bundle对象封装到Intent对象
startActivity(intent);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

SecondActivity获取传递数据:

Bundle bundle = getIntent().getExtras();//获取Bundle对象
String account = bundle.getString("account");
String password = bundle.getString("Password");
  • 1
  • 2
  • 3

4.4.2 Activity之间的数据回转

  1. startActivityForResult()方法

    startActivityForResult(Intent intent, int requestCode)
    
    • 1

    startActivityForResult()方法用于开启一个Activity,当开启的Activity销毁时,希望从中返回数据。
    requestCode表示请求码,用于标识请求来源。

  2. setResult()方法

    setResult(int resultCode, Intent intent)
    
    • 1

    resultCode表示返回码,用于标识返回的数据来自哪个Activity。
    intent用于携带数据并回传到上个界面。

  3. onActivityResult()

    onActivityResult(int requestCode, int resultCode, Intent data)
    
    • 1

    onActivityResult()方法用于接收回传的数据,并根据传递的参数requestCode、resultCode来识别数据来源

在MainActivity中点击button1控件跳转到SecondActivity示例代码:

button1.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View view){
    Intent intent = new Intent(MainActivity.this,SecondActivity.class);
    startActivityForResult(intent,1);
}
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在SecondActivity中点击button2控件返回数据到MainActivity的示例代码:

button2.setOnClickListener(new View.OnClickListener){
    @Override
    public void onClick(View view){
        Intent intent = new Intent();
        intent.putExtra("data","Hello MainActivity");
        setResult(2,intent);
        finish();
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

setResult()方法只负责返回数据,没有跳转功能,需要调用finish()方法关闭SecondActivity。

在MainActivity中调用startActivityForResult()方法启动SecondActivity,在SecondActivity被销毁后程序会回调MainActivity中的OnActivityResult()方法来接收回传的数据,因此需要在MainActivity中重写onActivityResult()方法。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
    super.onActivityResult(requestCode,resultCode,data);
    if(requestCode == 1 && resultCode == 2){
        String acquiredData = data.getStringExtra("data");
        Toast.makeText(MainActivity.this,acquiredData,Toast.LENGTH_SHORT).show();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在SecondActivity的EditView输入文字修改MainActivity的TextView:
MainActivity:

package com.milk.learnproject_activity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
    TextView tv1;
    Button button1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv1 = (TextView) findViewById(R.id.Main_TextView1);
        button1=(Button)findViewById(R.id.Main_Button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent(MainActivity.this,SecondActivity.class);
                startActivityForResult(intent,1);
            }
        });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        super.onActivityResult(requestCode,resultCode,data);
        if(requestCode == 1 && resultCode == 2){
            String acquiredData = data.getStringExtra("data");
            Toast.makeText(MainActivity.this,acquiredData,Toast.LENGTH_SHORT).show();
            tv1.setText(acquiredData);
        }
    }
}
  • 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

SecondActivity:

package com.milk.learnproject_activity;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class SecondActivity extends Activity {
    EditText edittext1;
    Button button1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        edittext1=(EditText)findViewById(R.id.Second_EditView1);
        button1=(Button)findViewById(R.id.Second_Button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String text=edittext1.getText().toString();
                Intent intent = new Intent();
                intent.putExtra("data",text);
                setResult(2,intent);
                finish();
            }
        });
    }
}

  • 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

1.在Fragment中使用startActivityForResult的时候,不要使用getActivity().startActivityForResult,而是应该直接使startActivityForResult()。
2.如果activity中重写了onActivityResult,那么activity中的onActivityResult一定要加上super.onActivityResult(requestCode, resultCode, data)。
如果违反了上面两种情况,那么onActivityResult只能够传递到activity中的,无法传递到Fragment中的。
没有违反上面两种情况的前提下,可以直接在Fragment中使用startActivityForResult和onActivityResult,和在activity中使用的一样。

4.5 Activity的任务栈和启动模式

4.5.1 Android中的任务栈

Android的任务栈是一种用来存放Activity实例的容器。任务栈最大的特点就是先进后出。主要有压栈和出栈两个操作。
用户操作的Activity永远都是栈顶的Activity。

4.5.2 Activity的启动模式

  1. standard模式
    standard是Activity的默认启动方式。当android:launchMode没有被指定属性时默认为standard。这种方式的特点是每启动一个Activity就会在栈顶创建一个新的实例(闹钟程序)。
    当Activity已经位于栈顶时,再次启动该Activity时还需要创建一个新的实例压入任务栈,不能直接复用。

  2. singleTop模式
    会判断要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例(浏览器书签)。
    如果Activity并未处于栈顶位置,则在栈中还会压入多个不相连的Activity实例
    在这里插入图片描述

  3. singleTask模式
    每次启动Activity时系统首先检查栈中是否存在当前Activity实例,如果存在则直接使用,并把当前Activity上面的所有实例全部弹出栈(浏览器主页面)。

  4. singleInstance模式
    Activity会启动一个新的任务栈来管理Activity实例,无论从哪个任务栈中启动该Activity,该实例在整个系统中只有一个(Android桌面)。

    1. 要启动的Activity实例在栈中不存在,则系统先创建一个新任务栈再压入Activity实例
    2. 要启动的Activity已经存在,系统会把Activity所在任务栈转移到前台,从而显示Activity(来电界面)。
      在这里插入图片描述

4.6 使用Fragment(碎片)

为了能够同时兼顾到手机和平板电脑的开发,自Android3.0版本开始提供了Fragment

4.6.1 Fragment简介

Fragment是一种嵌入在Activity中的UI片段,它可以用来描述Activity中的一部分布局。
一个Activity可以包含多个Fragment,一个Fragment也可以在多个Activity中使用。

4.6.2 Fragment的生命周期

当在Activity中创建Fragment时,Fragment处于启动状态,
当Activity被暂停时,其中的所有Fragment也被暂停,
当Activity被销毁时,其中的所有Fragment也被销毁,
当一个Activity处于运行状态时,可以单独地对每一个Fragment进行操作:添加时Fragment处于启动状态,删除时Fragment处于销毁状态。
Fragment生命周期相比Activity额外方法:

  • onAttach():Fragment和Activity建立关联时调用
  • onCreateView():Fragment创建视图(加载布局)时创建
  • onActivityCreate():Fragment相关联的Activity已经创建时调用
  • onDestroyView(): Fragment关联的视图被移除时调用
  • onDetach(): Fragment和Activity解除关联时调用
  • 在这里插入图片描述

4.6.3 创建Fragment

创建Fragment时必须创建一个类继承自Fragement。

public class NewListFragment extends Fragment{
    @Override
    public View on CreareView(LayoutInflater, inflater, ViewGroup container, Bundle savedInstanceState){
        View v = inflater.inflate(R.layout.fragment,container, false);
        return v;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4.6.4 在Activity中添加Fragment

Fragment创建完成后并不能单独使用,还需要将Fragment添加到Activity中。

  1. 在布局文件中添加Fragment
    需要在Activity引用的布局文件中使用标签,必须指定android:name属性,属性值为Fragment的全路径名称。

     <fragment
         android:name="cn.itcast.NewsListFragment"
         android:id="@+id/newslist"
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
  2. 在Activity中动态加载Fragment

    1. 创建一个Fragment实例
    2. 获取FragmentManager的实例
    3. 开启FragmentTransaction
    4. 向Activity的布局容器中添加Fragment
    5. 通过commit()提交事务
    public class MainActivity extends Activity{
        @SuppressLint("NewApi")
        @Override
        protected void onCreate(Bundle savedInstanceState){
            super.onCreate(saveInstanceState);
            setContentView(R.layout.activity_main);
            NewsListFragment fragment = new NewsListFragment();
            FragmentManage fm = getFragementManager();
            FragmentTransaction beginTransaction = fm.beginTransaction();
            beginTransaction.replace(R.id.ll,fragment);
            beginTransaction.commit();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    “getFragmentManager和android.app.Fragment在API 28中已弃用。
    现在,我们应该分别使用支持库中的Fragment和getSupportFragmentManager。
    但是,如果您担心这些弃用,则还应注意,API 28也弃用了PreferenceFragments。
    相反,您应该使用PreferenceFragmentCompat”

    应将getFragementManager替换为getSupportFragmentManager()

    //1.在Fragment中使用startActivityForResult的时候,不要使用getActivity().startActivityForResult,而是应该直接使startActivityForResult()。
    //2.如果activity中重写了onActivityResult,那么activity中的onActivityResult一定要加上super.onActivityResult(requestCode, resultCode, data)。
    //如果违反了上面两种情况,那么onActivityResult只能够传递到activity中的,无法传递到Fragment中的。
    //没有违反上面两种情况的前提下,可以直接在Fragment中使用startActivityForResult和onActivityResult,和在activity中使用的一样。
    
    • 1
    • 2
    • 3
    • 4
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/41214
推荐阅读
相关标签
  

闽ICP备14008679号