这篇文章是我自己的《第一行代码Andorid》的阅读笔记,虽然大量参考了别人已经写好的一些笔记和代码但是也有自己的提炼和新的问题在里面,我也会放上参考文章链接。
Android系统的四大组件:
(1)活动(Activity):是所有Android应用程序的门面,凡是在应用中你看得到的东西,都是放在活动中的。
(2)服务(Service):你无法看到它,但它会一直在后台默默地运行,即使用户退出了应用,服务仍然是可以继续运行的。
(3)广播接收器(Broadcast Receiver):广播接收器允许你的应用接收来自各处的广播消息,比如电话、短信等,当然你的应用同样也可以向外发出广播消息。
(4)内容提供器(Content Provider):为应用程序之间共享数据提供了可能,比如你想要读取系统电话簿中的联系人,就需要通过内容提供器来实现。
https://www.cnblogs.com/1693977889zz/p/16256303.html
注意点:
注意点:

所有的活动都要在AndroidManifest.xml中进行注册才能生效,一般编辑器会帮我们自动注册。
android:label="This is FirstActivity"
Toast是Android系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,这些信息会在一段时间后自动消失,并且不会占用任何屏幕空间。
下面这段代码我们一般放在点击事件里面
Toast.makeText(FirstActivity.this,“You clicked Button 1”,Toast.LENGTH_SHORT).show();
makeText()方法需要传入3个参数。
效果是在标题栏的右侧多了一个三点的符号,这个就是菜单按钮。点击之后会显示多个我们定义好的菜单按键,使用方式如下:
上面的代码建了两个菜单项,其中标签就是用来创建具体的某一个菜单项,然后通过android:id给这个菜单项指定一个唯一的标识符,通过android:title给这个菜单项指定一个名称。
3. 给当前活动创建菜单:回到FirstActivity中来重写onCreateOptionsMenu()方法,重写的内容里面通过getMenuInflater()方法能够得到MenuInflater对象再调用它的inflate()方法就可以给当前活动创建菜单。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if(item.getItemId() == R.id.add_item)
Toast.makeText(this,"You clicked Add",Toast.LENGTH_SHORT).show();
if(item.getItemId() == R.id.remove_item)
Toast.makeText(this,"You clicked Remove",Toast.LENGTH_SHORT).show();
return true;
}
注意这里的代码和书上的不一样,因为现在好像不能使用 case R.id.add_item了,必须是一个静态常量才行,所以我换成了if语句判断。这样写完后点击菜单按钮就会有不同的处理回应了。
销毁活动的方式有两种,一种是按一下Back键,另一种是通过代码 finish();
Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent一般可被用于启动活动、启动服务以及发送广播等场景。
Intent大致可以分为两种:显式Intent和隐式Intent。
在FirstActivity的中按钮的点击事件中加入以下代码:
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
startActivity(intent);
第一个参数是FirstActivity.this作为上下文
第二个参数是SecondActivity这个活动
这样就会在点击按钮时运行这段代码启动SecondActivity活动
它并不明确指出我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。
这时候的FirstActivity中按钮的点击事件中的Intent 要这么写:
Intent intent=new Intent("com.example.activitytest.ACTION_START");
startActivity(intent);
注意:
Intent intent=new Intent("com.example.activitytest.ACTION_START");
intent.addCategory("com.example.activitytest.MY_CATEGORY");
startActivity(intent);
隐式Intent除了用于Activity跳转,还可以用于拨打电话、发送短信、访问网页、调用音乐播放器、调用视频播放器、发送邮件和打开地图等。
拨打电话:
//隐式Intent拨打电话
Intent intent=new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
发送短信:
//隐式发送短信
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra("这里填写短信收信人", "这里填写短信内容");
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);
访问网页:
//隐式Intent访问网页
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
调用音乐播放器:
//调用音乐播放器
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file://sdcard/demo.mp3");
intent.setDataAndType(uri, "audio/mp3");
startActivity(intent);
调用视频播放器:
//调用视频播放器
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file://sdcard/demo.mp4");
intent.setDataAndType(uri, "video/mp4");
startActivity(intent);
发送邮件:
//发送邮件
Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:xxx@gmail.com"));
intent.putExtra(Intent.EXTRA_SUBJECT, "这是标题");
intent.putExtra(Intent.EXTRA_TEXT, "这是内容");
startActivity(intent);
打开地图:
//打开地图查看某经纬度的地点(如:天安门)
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("geo:39.9073,116.3912"));
startActivity(intent);
Intent中提供了一系列putExtra()方法的重载,可以把想要传递的数据暂存在Intent中,启动了另一个活动后,只需要把这些数据再从Intent中取出就可以了。
比如在FirstActivity中:
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String data="Hello SecondActivity";
Intent intent= new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("extra data",data);
startActivity(intent);
}
});
使用显式Intent的方式来启动SecondActivity,并通过putExtra()方法传递了一个字符串。注意这里putExtra()方法接收两个参数,第一个参数是键,用于后面从Intent中取值,第二个参数才是真正要传递的数据。
然后在SecondActivity中将传递的数据取出,并打印出来,代码如下所示:
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_layout);
Intent intent = getIntent();
String data = intent.getStringExtra("extra data");
Log.d("SecondActivity",data);
}
注意:
这一部分的内容需要注意,书上给的例子是使用 startActivityForResult()但是在 Android 11(API 级别 30)及以后的版本中,方法 startActivityForResult(Intent, int) 已经被弃用。尽管它仍然可以使用,但为了确保兼容性和未来的应用程序发展,建议使用新的替代方案。现在,可以使用 ActivityResultLauncher API 来替代 startActivityForResult()。这个新的 API 提供了更灵活和现代的方式来处理活动结果。
ActivityResultContracts.StartActivityForResult())。
ActivityResultLauncher myLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
// 处理结果Intent data = result.getData();
// ...
}
}
);
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK,intent);
finish();
}
private final ActivityResultLauncher myLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK) {
Intent data = result.getData();//拿取传过来的数据
if (data != null) {
String returnedData = data.getStringExtra("data_return");
if (returnedData != null) {
// 弹出提示框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(returnedData)
.setTitle("Returned Data")
.setPositiveButton("OK", null);
AlertDialog dialog = builder.create();
dialog.show();
}
}
}
}
);
通过String returnedData = data.getStringExtra(“data_return”);拿到我们的数据再进行处理。
补充:如果通过按下Back键返回呢
如果用户在SecondActivity中并不是通过点击按钮,而是通过按下Back键回到FirstActivity,我们可以通过在SecondActivity中重写onBackPressed()方法来处理返回的数据。
@Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return","Hello FirstActivity");
setResult(RESULT_OK,intent);
finish();
}
在用户点击Back键的时候就会调用这个函数,那么我们的intent.putExtra存进去的数据仍然可以传回去。

每个活动在其生命周期中最多可能会有4种状态。
Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节,下面就来一一介绍这7个方法。
想象以下场景:应用中有一个活动A,用户在活动A的基础上启动了活动B,活动A就进入了停止状态,这个时候由于系统内存不足,将活动A回收掉了,然后用户按下Back键返回活动A,会出现什么情况呢?
其实还是会正常显示活动A的,只不过这时并不会执行onRestart()方法,而是会执行活动A的onCreate()方法,因为活动A在这种情况下会被重新创建一次。这样看上去好像一切正常,可是别忽略了一个重要问题,活动A中是可能存在临时数据和状态的。打个比方,MainActivity中有一个文本输入框,现在你输入了一段文字,然后启动NormalActivity,这时MainActivity由于系统内存不足被回收掉,过了一会你又点击了Back键回到MainActivity,你会发现刚刚输入的文字全部都没了,因为MainActivity被重新创建了。因此,我们引入了可以在活动回收后保存数据的方法onSaveInstanceState()回调方法,这个方法可以保证在活动被回收之前一定会被调用,因此我们可以通过这个方法来解决活动被回收时临时数据得不到保存的问题。
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
String tempData = "Something you just typed";
outState.putString("data_key",tempData);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG,"onCreate");
setContentView(R.layout.activity_main);
if (savedInstanceState!=null) {
String tempData = savedInstanceState.getString("data_key");
Log.d(TAG,tempData);
}
不过这里注意一点:
onSaveInstanceState()方法,它不是生命周期方法,它不同于生命周期方法,它并不会一定会被触发,它只有具备以下条件的时候才会触发:
活动的启动模式一共有4种,分别是standard、singleTop、singleTask和singleInstance,可以在AndroidManifest.xml中通过给标签指定android:launchMode属性来选择启动模式。
在 Android 中,“任务”(Task)是一种管理应用活动(Activity)的方式。一个任务通常包含一个或多个活动,并用于组织和管理这些活动的生命周期。
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity",getClass().getSimpleName());
}
用一个专门的集合类对所有的活动进行管理就可以随时随地都能退出程序,而不需要一个一个注销和退出。
public class ActivityCollector {
public static List activities = new ArrayList<>();
public static void addActivity(Activity activity){
activities.add(activity);
}
public static void removeActivity(Activity activity){
activities.remove(activity);
}
public static void finishAll(){
for (Activity activity : activities) {
if (!activity.isFinishing()){
activity.finish();
}
activities.clear();
}
}
}
在活动管理器中,我们通过一个List来暂存活动,然后提供了一个addActivity()方法用于向List中添加一个活动,提供了一个removeActivity()方法用于从List中移除活动,最后提供了一个finishAll()方法用于将List中存储的活动全部销毁掉。
2. 修改BaseActivity中的代码
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity",getClass().getSimpleName());
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
在BaseActivity的onCreate()方法中调用了ActivityCollector的addActivity()方法,表明将当前正在创建的活动添加到活动管理器里。然后在BaseActivity中重写onDestroy()方法,并调用了ActivityCollector的removeActivity()方法,表明将一个马上要销毁的活动从活动管理器里移除。
从此以后,不管你想在什么地方退出程序,只需要调用ActivityCollector.finishAll()方法就可以了。例如在ThirdActivity界面想通过点击按钮直接退出程序:
Button button3 = (Button) findViewById(R.id.button_3);
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ActivityCollector.finishAll();
}
});
当然你还可以在销毁所有活动的代码后面再加上杀掉当前进程的代码,以保证程序完全退出,杀掉进程的代码如下所示:
android.os.Process.killProcess(android.os.Process.myPid())
其中,killProcess()方法用于杀掉一个进程,它接收一个进程id参数,我们可以通过myPid()方法来获得当前程序的进程id。需要注意的是,killProcess()方法只能用于杀掉当前程序的进程,我们不能使用这个方法去杀掉其他程序。
当我们启动一个活动需要两个特别重要的参数时,可以使用以下办法
假设SecondActivity中需要用到两个非常重要的字符串参数,在启动SecondActivity的时候必须要传递过来,
public class SecondActivity extends BaseActivity {
public static void actionStart(Context context, String data1, String data2){
Intent intent = new Intent (context,SecondActivity.class);
intent.putExtra("param1",data1);
intent.putExtra("param2",data2);
context.startActivity(intent);
}
......
}
在SecondActivity中添加了一个actionStart()方法,在这个方法中完成了Intent的构建,另外所有SecondActivity中需要的数据都是通过actionStart()方法的参数传递过来的,然后把它们存储到Intent中,最后调用startActivity()方法启动SecondActivity。
这样写的好处就是SecondActivity所需要的数据在方法参数中全部体现出来了,这样即使不用阅读SecondActivity中的代码,不去询问负责编写SecondActivity的同事,你也可以非常清晰地知道启动SecondActivity需要传递哪些数据。另外,这样写还简化了启动活动的代码,现在只需要一行代码就可以启动SecondActivity,如下所示:
在FirstActivity中:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("FirstActivity","Task id is "+getTaskId());
setContentView(R.layout.first_layout);
Button button1=(Button) findViewById(R.id.button_1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
//startActivity(intent);
SecondActivity.actionStart(FirstActivity.this,"data1","data2");
}
});
}