Andorid学习记录(十一)

1.服务

1.1 基础知识

服务是一个后台运行的组件,执行长时间运行且不需要用户交互的任务。即使应用被销毁也依然可以工作。服务基本上以下包含两种状态

状态 描述
Started Android的应用程序组件,如活动,通过startService()启动了服务,则服务是Started状态。一旦启动,服务可以在后台无限期运行,即使启动它的组件已经被销毁。
Bound 当Android的应用程序组件通过bindService()绑定了服务,则服务是Bound状态。Bound状态的服务提供了一个客户服务器接口来允许组件与服务进行交互,如发送请求,获取结果,甚至通过IPC来进行跨进程通信。

服务拥有生命周期方法,可以实现监控服务状态的变化,可以在合适的阶段执行工作。

1.1.1 A started service

被开启的service通过其他组件调用 startService()被创建。

这种service可以无限地运行下去,必须调用stopSelf()方法或者其他组件调用stopService()方法来停止它。

当service被停止时,系统会销毁它。

1.1.2 A bound service

被绑定的service是当其他组件(一个客户)调用bindService()来创建的。

客户可以通过一个IBinder接口和service进行通信。

客户可以通过 unbindService()方法来关闭这种连接。

一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。

1.2 服务案例演示

关于服务的案例,我将使用启动以及停止服务作为案例,进行演示

1.2.1 创建【StartStopService】

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2.2 添加背景图片

在每个项目中,我们都可以选择添加自己喜欢的图片作为该程序的背景图片。
在这里插入图片描述
在这里插入图片描述

1.2.3 主布局文件activity_main.xml

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">

    <Button
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="@string/explicitly_start_service"
        android:onClick="doExplicitlyStartService"
        android:textSize="20sp"
        android:id="@+id/btnExplicitlyStartService"/>

    <Button
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:id="@+id/btnImplicitlyStartService"
        android:text="@string/implicitly_start_service"
        android:onClick="doImplicitlyStartService"
        android:textSize="20sp"/>

    <Button
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:text="@string/stop_service"
        android:onClick="doStopService"
        android:textSize="20sp"
        android:id="@+id/btnStopService"/>

</LinearLayout>

1.2.4 字符串文件strings.xml

在这里插入图片描述

<resources>
    <string name="app_name">StartStopService</string>
    <string name="explicitly_start_service">显示启动服务</string>
    <string name="implicitly_start_service">隐式启动服务</string>
    <string name="stop_service">停止服务</string>
</resources>

1.2.5 创建自定义服务类

在这里插入图片描述
在这里插入图片描述

package net.nell.startstopservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

public class CustomService extends Service {
    
    

    private final String TAG = "start_stop_service";//标记
    private Thread thread;//线程
    private boolean isRunning;//线程循环控制变量

    @Override
    public void onCreate(){
    
    
        super.onCreate();
        Log.d(TAG,"CustomService.onCreate() invoked.");
    }

    @Override
    public int onStartCommand(Intent intent,int flags , final int startId){
    
    
        Log.d(TAG,"CustomService.onStartCommand() invoked.");
        //设置线程循环控制变量为真
        isRunning = true;
        //判断意图是否为空
        if (intent != null){
    
    
            //创建线程
            thread = new Thread(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    while(isRunning){
    
    
                        Log.d(TAG,"服务正在进行中·····startId:" + startId + ", hashCode" + CustomService.this.hashCode());
                        try {
    
    
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
    
    
                            e.printStackTrace();
                        }
                    }
                }
            });
            //启动线程
            thread.start();
        }
        return Service.START_NOT_STICKY;
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    
    
        return null;
    }

    @Override
    public void onDestroy(){
    
    
        super.onDestroy();
        Log.d(TAG,"CustomService.onDestroy() invoked.");
        isRunning = false;
        thread = null;//销毁线程
        stopSelf();//停止服务
    }
}

1.2.6 项目清单文件

在这里插入图片描述

1.2.7 主界面类

在这里插入图片描述

package net.nell.startstopservice;

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

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    
    

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

        /**
         * 显示启动服务
         * @param view
         */
        public void doExplicitlyStartService(View view){
    
    
            //创建启动指定服务的意图
            Intent intent = new Intent(this,CustomService.class);
            //按照意图启动指定服务
            startService(intent);
        }

    /**
     * 隐式启动服务
     *
     * @param view
     */
    public void doImplicitlyStartService(View view){
    
    
        //创建意图
        Intent intent = new Intent();
        //设置意图动作
        intent.setAction("custom_service");
        //设置意图包名
        intent.setPackage(getPackageName());
        //按照意图启动服务
        startService(intent);

    }

    /**
     * 停止服务
     *
     * @param view
     */
    public void doStopService(View view){
    
    
        //创建启动指定服务的意图
        Intent intent = new Intent(this,CustomService.class);
        //按意图停止服务
        stopService(intent);
    }

}

1.2.8 运行效果

在这里插入图片描述
在这里插入图片描述

2.广播接受器

2.1 基础知识

广播接收器用于响应来自其他应用程序或者系统的广播消息。这些消息有时被称为事件或者意图。例如,应用程序可以初始化广播来让其他的应用程序知道一些数据已经被下载到设备,并可以为他们所用。这样广播接收器可以定义适当的动作来拦截这些通信。

有以下两个重要的步骤来使系统的广播意图配合广播接收器工作。

1.创建广播接收器
2.注册广播接收器
还有一个附加的步骤,要实现自定义的意图,你必须创建并广播这些意图。

无论什么时候Android设备被启动,都将被广播接收器MyReceiver所拦截,并且在onReceive()中实现的逻辑将被执行。

有许多系统产生的事件被定义为类Intent中的静态常量值。下面的表格列举了重要的系统事件。

2.2 广播案例演示

2.2.1 创建应用【SendReceiveBroadcast】

在这里插入图片描述
在这里插入图片描述

2.2.2 添加背景图片

在这里插入图片描述

2.2.3 主布局资源文件

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="20dp"
    android:background="@drawable/background"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/edtMessage"
        android:hint="@string/input_message"
        android:singleLine="true"
        android:textSize="20sp"/>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btnSendBroadcast"
        android:onClick="doSendBroadcast"
        android:text="@string/send_broadcast"
        android:textSize="20sp"/>

</LinearLayout>

2.2.4 字符串文件

在这里插入图片描述

<resources>
    <string name="app_name">SendReceiveBroadcast</string>
    <string name="input_message">请输入要广播的消息</string>
    <string name="send_broadcast">发送广播的消息</string>
</resources>

2.2.5 创建广播接收者

在这里插入图片描述

package net.nell.sendreceivebroadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class CustomReceiver extends BroadcastReceiver {
    
    
    private final String TAG = "send_receive_broadcast";//标记
    private final String TNTENT_ACTION_SEND_MESSAGE = "net.nell.intent.action.SEND_MESSAGE";

    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        //按照频道获取广播信息
        if (intent.getAction().equals(TNTENT_ACTION_SEND_MESSAGE)){
    
    
            //获取广播信息
            String message = intent.getStringExtra("message");
            //输出广播信息
            Log.d(TAG,message);
        }

    }
}

2.2.6 项目清单文件

在这里插入图片描述

2.2.7 主界面类

在这里插入图片描述

package net.nell.sendreceivebroadcast;

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

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    
    
    private final String TAG = "send_receive_broadcast";//标记
    private final String INTENT_ACTION_SEND_MESSAGE = "net.nell.intent.action.SEND_MESSAGE";
    private EditText edtMessage;//消息编辑框
    private int broadcastCount;//发送广播次数


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

        edtMessage = findViewById(R.id.edtMessage);
    }
    /**
     * 发送广播
     *
     * @param view
     */
    public void doSendBroadcast(View view){
    
    
        //统计发送广播次数
        broadcastCount++;
        //获取用户输入到广播的信息
        String message = edtMessage.getText().toString();
        //创建意图
        Intent intent = new Intent();
        //设置意图动作
        intent.setAction(INTENT_ACTION_SEND_MESSAGE);
        //设置意图携带的附加内容
        intent.putExtra("message","第"+broadcastCount+"次广播信息:"+message);
        //按照意图发送广播
        sendBroadcast(intent);

    }
}

2.2.8 运行效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.弹窗

Android在开发中经常会遇到有弹框的需求。经常使用的有Dialog 弹框,Window弹框,Activity伪弹框这三种。
由于所涉及内容较多,在此,我们就详细介绍Dialog 弹框。

3.1 Dialog 弹框的常见用法

项目 Value
setTitle 为对话框设置标题
setIcon 为对话框设置图标
setMessage 为对话框设置内容
setView 给对话框设置自定义样式
setItems 设置对话框要显示的一个list,一般用于显示几个命令时
setMultiChoiceItems 用来设置对话框显示一系列的复选框
setSingleChoiceItems 用来设置对话框显示一系列的单选框
setNeutralButton 普通按钮
setPositiveButton 给对话框添加"Yes"按钮
setNegativeButton 对话框添加"No"按钮
create 创建对话框
show 显示对话框

3.2 常见形式

以下所有方式,使用的activity_main.xml文件都相同,具体代码如下:
在这里插入图片描述

<?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/idtatabHost"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">
        <Button
            android:id="@+id/send"
            android:onClick="send"
            android:text="点我一下 有惊喜(吓) 。。。"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

3.2.1 显示消息提示的对话框

(1)建立 FirstService类 用于写静态方法

在这里插入图片描述

package net.nell.dialog;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.Toast;

public class FirstService extends MainActivity{
    
    
    public static void simple(View scource ){
    
    
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.mMainActivity)
                .setTitle("你好呀~")//设置对话框 标题
                .setIcon(R.mipmap.ic_launcher)//设置图标
                .setMessage("the sentences you want to say");

        setPositiveButton(builder);//add 'yes' Button to AlertDialog
        setNegativeButton(builder)//add 'no' Button to AlertDialog
                .create()
                .show();
    }
    private static AlertDialog.Builder setPositiveButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setPositiveButton("yes", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                Toast.makeText(MainActivity.mMainActivity,"you click 'yes' button ",Toast.LENGTH_SHORT).show();
            }
        });
    }

    private static AlertDialog.Builder setNegativeButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setNegativeButton("no", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                Toast.makeText(MainActivity.mMainActivity,"you click 'no' button ",Toast.LENGTH_SHORT).show();
            }
        });
    }

}

(2)主界面类

在这里插入图片描述

package net.nell.dialog;

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

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    
    
    public static MainActivity mMainActivity;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMainActivity = this;
    }
    public void send(View source){
    
    
        FirstService.simple(getWindow().getDecorView());
    }



}

(3)运行效果

在这里插入图片描述

在这里插入图片描述

3.2.2 列表项对话框

在这里插入图片描述

package net.nell.dialog;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.Toast;

public class FirstService extends MainActivity{
    
    
    private static String[] items = new String[]{
    
    
            "I believe I can fly",
            "Sunshine brightly",
            "I love study Java",
            "Wiw cool Dialog",
    };
    public static void simple(View scource ){
    
    
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.mMainActivity)
                .setTitle("set your list Dialog's title here")//设置对话框 标题
                .setIcon(R.mipmap.ic_launcher)//设置图标
                .setItems(items, new DialogInterface.OnClickListener() {
    
    
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
    
    
                        Toast.makeText(MainActivity.mMainActivity,"you click '" + items[which] + "' button ",Toast.LENGTH_SHORT).show();
                        return;
                    }
                });

        setPositiveButton(builder);//add 'yes' Button to AlertDialog
        setNegativeButton(builder)//add 'no' Button to AlertDialog
                .create()
                .show();
    }
    private static AlertDialog.Builder setPositiveButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setPositiveButton("yes", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                Toast.makeText(MainActivity.mMainActivity,"you click 'yes' button ",Toast.LENGTH_SHORT).show();
            }
        });
    }

    private static AlertDialog.Builder setNegativeButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setNegativeButton("no", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                Toast.makeText(MainActivity.mMainActivity,"you click 'no' button ",Toast.LENGTH_SHORT).show();
                return;
            }
        });
    }

}

主页面中的调用与第一个类似,在此便不进行展示

运行效果

在这里插入图片描述
在这里插入图片描述

3.2.3 单选列表对话框

在这里插入图片描述
上方框起来的部分便是与第二个弹窗代码不同的部分,在此便不进行全部代码的展示。

运行效果

在这里插入图片描述
在这里插入图片描述

3.2.4 多选列表对话框

在这里插入图片描述

package net.nell.dialog;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.Toast;

public class FirstService extends MainActivity{
    
    
        private static String[] items = new String[]{
    
    
                "I believe I can fly",
                "Sunshine brightly",
                "I love study Java",
                "Wiw cool Dialog",
        };
        private static boolean[] multiDialog = new boolean[]{
    
    false , true , false , true};
        public static void simple(View scource ){
    
    
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.mMainActivity)
                    .setTitle("单选列表对话框")//设置对话框 标题
                    .setIcon(R.mipmap.ic_launcher)//设置图标
                    .setMultiChoiceItems(items, multiDialog ,null);

            setPositiveButton(builder);//add 'yes' Button to AlertDialog
            setNegativeButton(builder)//add 'no' Button to AlertDialog
                    .create()
                    .show();
        }
        private static AlertDialog.Builder setPositiveButton(AlertDialog.Builder builder){
    
    
            // use 'setPositiveButton' method to add 'yes' Button
            return builder.setPositiveButton("yes", new DialogInterface.OnClickListener() {
    
    
                @Override
                public void onClick(DialogInterface dialog, int which) {
    
    
                    for ( int i = 0 ; i < items.length ; i++ ){
    
    
                        if (multiDialog[i]){
    
    
                            Toast.makeText(MainActivity.mMainActivity,"you click '"  + items[i] +  "' button ",Toast.LENGTH_SHORT).show();
                        }
                    }
                }
            });
        }

        private static AlertDialog.Builder setNegativeButton(AlertDialog.Builder builder){
    
    
            // use 'setPositiveButton' method to add 'yes' Button
            return builder.setNegativeButton("no", new DialogInterface.OnClickListener() {
    
    
                @Override
                public void onClick(DialogInterface dialog, int which) {
    
    
                    Toast.makeText(MainActivity.mMainActivity,"you click 'no' button ",Toast.LENGTH_SHORT).show();
                    return;
                }
            });
        }
    }


主界面中的代码与上文相同。

运行效果

在这里插入图片描述
在这里插入图片描述

3.2.5 自定义列表项对话框

在这里插入图片描述

package net.nell.dialog;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast;

public class FirstService  extends MainActivity{
    
    
    private static String[] items = new String[]{
    
    
            "I believe I can fly",
            "Sunshine brightly",
            "I love study Java",
            "Wiw cool Dialog",
    };
    public static void simple(View scource ){
    
    
        AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.mMainActivity)
                .setTitle("单选列表对话框")//设置对话框 标题
                .setIcon(R.mipmap.ic_launcher)//设置图标
                .setAdapter(new ArrayAdapter<String>(mMainActivity,R.layout.cell,items),null);

        setPositiveButton(builder);//add 'yes' Button to AlertDialog
        setNegativeButton(builder)//add 'no' Button to AlertDialog
                .create()
                .show();
    }
    private static AlertDialog.Builder setPositiveButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setPositiveButton("yes", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                Toast.makeText(MainActivity.mMainActivity,"you click 'yes' button ",Toast.LENGTH_SHORT).show();
            }
        });
    }

    private static AlertDialog.Builder setNegativeButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setNegativeButton("no", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                Toast.makeText(MainActivity.mMainActivity,"you click 'no' button ",Toast.LENGTH_SHORT).show();
                return;
            }
        });
    }
}

(1)新建cell.xml文件

在这里插入图片描述

(2)运行效果

在这里插入图片描述

3.2.6 自定义 View 对话框

在这里插入图片描述

package net.nell.dialog;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.View;
import android.widget.TableLayout;
import android.widget.Toast;

public class FirstService  extends MainActivity{
    
    
    private static TableLayout tableLayout;
    public static void simple(View scource ){
    
    
        tableLayout = (TableLayout) mMainActivity.getLayoutInflater().inflate(R.layout.cell,null);
        AlertDialog.Builder builder = new AlertDialog.Builder(mMainActivity)
                .setTitle("单选列表对话框")//设置对话框 标题
                .setIcon(R.mipmap.ic_launcher)//设置图标
                .setView(tableLayout);

        setPositiveButton(builder);//add 'yes' Button to AlertDialog
        setNegativeButton(builder)//add 'no' Button to AlertDialog
                .create()
                .show();
    }
    private static AlertDialog.Builder setPositiveButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setPositiveButton("yes", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                //do login operations here
                Toast.makeText(MainActivity.mMainActivity,"you info:" + tableLayout.toString(),Toast.LENGTH_SHORT).show();
            }
        });
    }

    private static AlertDialog.Builder setNegativeButton(AlertDialog.Builder builder){
    
    
        // use 'setPositiveButton' method to add 'yes' Button
        return builder.setNegativeButton("no", new DialogInterface.OnClickListener() {
    
    
            @Override
            public void onClick(DialogInterface dialog, int which) {
    
    
                //do nothing here
                Toast.makeText(MainActivity.mMainActivity,"you click 'no' button ",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<TableLayout
    android:id="@+id/cell"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <TableRow>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="用户名"
            android:textSize="10pt"/>
        <!--Users can input personal info in here-->
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="please input your account:"
            android:selectAllOnFocus="true"/>
        <!--if you set selectAllOnFocus 'true' your keyboard will open-->
    </TableRow>
    <TableRow>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Code"
            android:textSize="10pt"/>
        <!--Users can input personal info in here-->
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="please input your Code:"
            android:selectAllOnFocus="true"/>
    </TableRow>
    <TableRow>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Phone"
            android:textSize="10pt"/>
        <!--Users can input personal info in here-->
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="please input your Phone number:"
            android:selectAllOnFocus="true"/>
    </TableRow>
</TableLayout>

运行效果

在这里插入图片描述

在这里插入图片描述
以上有一些弹窗,由于我未进行标题的修改,所以全都显示为单选列表对话框,在以后使用时可根据需要进行修改

以上所有内容为今天的学习内容,明天我们讲解和今天的知识,来完成第四个任务。

猜你喜欢

转载自blog.csdn.net/weixin_46705517/article/details/112780004