Android development learning is continuously updated

Android development

Operations within a single Activity interface

Control 1 TextView control uses

It's a bit like html+css on the front end.

Control 2Button control uses

1 First of all, for the key format of android

Such as the background or the default button format and the format of the button after pressing
Specify the label of the button in the activity_main.xml file

<Button
        android:id="@+id/btn"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:background="@drawable/btn_selector"
        android:text="我是一个按钮"
        />

For the background color, you can specify the color or create a selector under the drowable file, specify the background image of the button, etc.
insert image description here

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!--如果被按下的画,就显示这个图片-->
    <item android:drawable="@drawable/ic_baseline_elderly_24" android:state_pressed="true"/>
    <!--默认的就是显示这个图片-->
    <item android:drawable="@drawable/ic_baseline_emoji_people_24"/>
</selector>
2 Bind the button monitoring event

First number the button label, and then get the button in the activity class, you can bind the button to listen to the event

protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取事件的按键id
        Button btn = findViewById(R.id.btn);
        //对这个按键进行绑定,如单击事件
        btn.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    

            }
        });
        //绑定一个长按的一个监听事件
        btn.setOnLongClickListener(new View.OnLongClickListener() {
    
    
            @Override
            public boolean onLongClick(View v) {
    
    
                return false;
            }
        });
        //绑定一个触摸事件
        btn.setOnTouchListener(new View.OnTouchListener() {
    
    
            @Override
            public boolean onTouch(View v, MotionEvent event) {
    
    
                return false;
            }
        });

    }

In the second method, you can directly specify the binding onclick event in the button tag, and then add a method with the same name in the main class

insert image description here
insert image description here

Control 3 EditText text box settings

Similar to the text attribute when logging in to a web form, some data can be entered in it, and the label used is
"EditText"
insert image description here

Control 4 ImageView

insert image description here

The most important thing is the zoom type of the picture
insert image description here
. In many cases, the size of the picture does not match the size of the imageview. In order to prevent the picture from being distorted or deformed, you can use the following automatic filling, which will match the corresponding picture frame according to the size of the picture. .
insert image description here

The use of control 5ProgressBar

This control is to display a progress, a refreshed small circle, or a progress bar. Can display the process of downloading or page loading.
insert image description here
1 Load in small circles

<!--显示进度,此时是一个小圈圈一直转-->
    <ProgressBar
        android:id="@+id/pb1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <!--来一个按钮来控制加载显示与消失-->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示或者隐形加载界面"
        android:onClick="pb1Change"/>

Add listener events to the main startup class

public class MainActivity extends AppCompatActivity {
    
    

    private ProgressBar pb1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pb1 = findViewById(R.id.pb1);
    }




    public void jumpToAnother(View view) {
    
    
        startActivity(new Intent(this,MainActivity2.class));
    }

    //按键来控制进度条的显示和隐藏
    public void pb1Change(View view) {
    
    
        //如果此时是隐藏的,就显示出来
        if(pb1.getVisibility()==View.GONE){
    
    
            pb1.setVisibility(View.VISIBLE);
        }else{
    
    
            pb1.setVisibility(View.GONE);
        }
    }
}

2 Loading in the form of a progress bar

style=“?android:attr/progressBarStyleHorizontal”

<!--以进度调的方式来显示-->
    <ProgressBar
        android:id="@+id/pb2"
        style="?android:attr/progressBarStyleHorizontal"
        android:max="100"
        android:layout_width="300dp"
        android:layout_height="wrap_content"/>
<!--模拟进度调在增加-->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="每点击一下就增加10"
        android:onClick="pb2Add"/>

Assign the loading process in the main startup class

/*模拟下载过程,每点击一下就增加10个单位*/
    public void pb2Add(View view) {
    
    
        int progress = pb2.getProgress();
        progress+=10;
        pb2.setProgress(progress);

    }

3 Let the progress bar show the progress imprecisely, loading like a small circle every time

<!--像小圈圈那样加载,但是不精确的显示-->
    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:max="100"
        android:indeterminate="true"/>

Control 6 Notification notification

insert image description here
insert image description hereThe following is to set some forms for the content of the notification
insert image description here
1 First create two buttons to bind the sending or canceling notification event

<Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送通知"
        android:background="@color/purple_200"
        android:onClick="sendNote"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="取消发送通知"
        android:textColor="@color/white"
        android:background="@color/black"
        android:onClick="cancelNote"/>

insert image description here2 Get the notification management first in the main class, and then get the notification

insert image description here

public class MainActivity extends AppCompatActivity {
    
    

    
    private NotificationManager manager;
    private Notification notification;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        

        //第一步先获取到通知管理对象
         manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

         //第二步,通过builder来链式的创建notification对象
        NotificationChannel channel = null;
        //是Android8版本之后推出的因此需要进行版本的判断
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
    
    
            //第一个参数就是id,第二个参数是通知的名字,可以随便设置,第三个参数是通知的等级,有很多的等级,具体可以参照本小节第二张图。
            channel = new NotificationChannel("hai", "测试通知", NotificationManager.IMPORTANCE_HIGH);
            manager.createNotificationChannel(channel);
        }

        //新建一个activity来点击通知时进行跳转到指定的界面或者app中
        Intent intent = new Intent(this, NotificationActivity.class);
        PendingIntent pendingIntend = PendingIntent.getActivity(this, 0, intent, 0);
//对通知的内容或者形式进行修饰
        notification = new NotificationCompat.Builder(this, "hai")
                .setContentTitle("正规通知(通知的姓名)")
                .setContentText("通知的内容,你的银行卡收入100元")
                //这里是通知的一个小图标的设定,不能是rgb图片
                .setSmallIcon(R.drawable.ic_baseline_person_24)
                //设置大图标的图片,但是因为是一个bitmap格式,所以需要将图片转成bitmap格式
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.yueyue))
                //设置小图标的颜色,
                .setColor(Color.parseColor("#ff0000"))
                //这个参数是指定点击到通知之后,跳转的界面或者app中,传入的是一个PendingIntent对象
                .setContentIntent(pendingIntend)
                //这个参数是当点击通知之后,就会将通知销毁
                .setAutoCancel(true)
                .build();

    }

    //发送通知的按钮
    public void sendNote(View view) {
    
    
        manager.notify(1,notification);
    }
    //点击次按钮可以将通知给取消掉,和setAutoCancel作用相同
    public void cancelNote(View view) {
    
    
        manager.cancel(1);
    }

Then it is to create an activity after the jump and register it in the list.
Then click the send notification button, which is the following interface

insert image description here

Control 7Toolbar The navigation bar at the top of the page

Common property settings
insert image description here

<androidx.appcompat.widget.Toolbar
        android:id="@+id/tb1"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/purple_200"
        app:navigationIcon="@drawable/ic_baseline_west_24"

        >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="微信"
            android:layout_gravity="center"
            android:gravity="center"
            android:textSize="30dp"
            android:textColor="@color/white"

            />

    </androidx.appcompat.widget.Toolbar>

Then go to the main class to bind the back and forward events in the navigation bar, and when the small icon is pressed, it will respond accordingly.
insert image description here

//先获取到标签,然后再对导航栏的监听事件进行绑定
Toolbar tb1 = findViewById(R.id.tb1);

        tb1.setNavigationOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                System.out.println("返回按钮被单机了");
            }
        });

Control 8AlertDialog notification dialog box

Generally, notifications are displayed at the top, and you need to pull down to view the specific content, and this alertDialog dialog box can display the content of the notification on the screen, similar to the interface after the message comes after the lock screen. alertDialog simple properties and use
insert image description here
Define a layout for displaying in the notification box

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <ImageView
        android:layout_width="300px"
        android:layout_height="200px"
        android:src="@drawable/yueyue" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="天气很好,你那边边天气怎么样啊"
        android:textSize="20dp"
        android:textColor="@color/black"
        />
</LinearLayout>
public void alertNode(View view) {
    
    
        //先获取到builder
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        //准备自定义一个布局,来给view作为参数,自定义一个布局
        View view1 = getLayoutInflater().inflate(R.layout.notification_mian, null);
        //然后通过builder进行链式的设计
        builder.setIcon(R.mipmap.ic_launcher)
                //设置通知对话框的主题
                .setTitle("通知对话框")
                //通知的内容
                .setMessage("今天是5月16号,你那边天气怎么样啊?")

                .setPositiveButton("确定按钮", new DialogInterface.OnClickListener() {
    
    
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
    
    
                        System.out.println("确定按钮被点击");
                    }
                })
                .setPositiveButton("取消按钮", new DialogInterface.OnClickListener() {
    
    
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
    
    
                        System.out.println("取消按钮被点击");
                    }
                })
                .setNeutralButton("中间按钮", new DialogInterface.OnClickListener() {
    
    
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
    
    
                        System.out.println("中间按钮被点击");
                    }
                })
                //传入自定义的布局
                .setView(view1)
                .create()
                .show();
    }

insert image description here

Control 8PopupWindow After clicking the button, it does not jump to other activities, and displays a window in this interface, and the window can be regarded as a new layout.

Introduction to use and properties
insert image description hereFirst create a new layout for the window to use

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/ic_launcher"
    android:orientation="vertical">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/purple_200"

        android:text="按钮1" />
    <Button
        android:id="@+id/button2"
        android:layout_marginTop="20px"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/purple_200"
        android:text="按钮2" />
</LinearLayout>

insert image description here

Create a button in a page, and create a listening event for the button, when the button is clicked, the window will be displayed.

public void showWindow(View view) {
    
    
        //获取到窗口的布局,作为对象传入到窗口中
        View windowView = getLayoutInflater().inflate(R.layout.window_view, null);
        //获取到窗口内部的按钮,并且为其创建监听事件
        Button bt1 = windowView.findViewById(R.id.button1);
        Button bt2 = windowView.findViewById(R.id.button2);
        
        //设置窗口内的布局和窗口的大小,最后一个参数是当点击空白处时,会退出弹出的window
        PopupWindow window = new PopupWindow(windowView, ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT,true);
        //k而已设置窗口的背景图
        window.setBackgroundDrawable(getResources().getDrawable(R.drawable.yueyue));
        //指定展示窗口的位置,显示在按钮的下方,或者其他的构造方法进行窗口的偏移
        window.showAsDropDown(view);
        //创建监听事件
        bt1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                System.out.println("按钮1被点击");
                //当点击后,让其退出,可以调用dismiss方法来退出窗口
                window.dismiss();
                
            }
        });
        bt1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                System.out.println("按钮2被点击");
                window.dismiss();
            }
        });

    }

layout

After understanding the basic controls, you need to understand the layout, which is to specify the placement and form of elements on the page

Layout 1_LinearLayout

basic operation
insert image description here
insert image description here

Layout 2 - RelativeLayout

The main function is to specify the location of the added module. If not specified, it will be placed in the upper left corner by default. Common location attribute settings
insert image description here

insert image description hereinsert image description here
insert image description here

Layout 3_FrameLayout

Each new layout will place the new one in front of the previous layout.
insert image description hereinsert image description here

4——TableLayout form display

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:collapseColumns="1"
    >
    <TableRow >
        <Button
            android:id="@+id/button01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮1" 
        ></Button>
        <Button
            android:id="@+id/button02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮2"      
        ></Button>
        <!-- android:text="按钮2" --> 
        <Button
            android:id="@+id/button03"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮3"      
        ></Button>
    </TableRow>

    <TableRow >
        <Button
            android:id="@+id/button04"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮4"      
        ></Button>
        <Button
            android:id="@+id/button05"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮5"      
        ></Button>
        <Button
            android:id="@+id/button06"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮6"      
        ></Button>
    </TableRow>

    <TableRow >
        <Button
            android:id="@+id/button07"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮7"      
        ></Button>
        <Button
            android:id="@+id/button08"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮8"      
        ></Button>
        <Button
            android:id="@+id/button09"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="按钮9"      
        ></Button>
    </TableRow>    
</TableLayout>

GridLayout is the same as the table above, but more flexible

insert image description here

Jump between activities

I temporarily understand that an activity is a page, but how to realize the mutual jump between multiple activity pages is a problem.
1 First, create an activity interface, that is, create a new class, and must inherit AppCompatActivity

public class MainActivity2 extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        //重写父类的方法
        super.onCreate(savedInstanceState);
    }
}

2 After creating the main class, you need to create a layout for this class, that is, the content that needs to be displayed on the current interface
insert image description here3 After creating the layout, you need to introduce the layout in the main class

public class MainActivity2 extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        //重写父类的方法
        super.onCreate(savedInstanceState);
        //引入布局
        setContentView(R.layout.activity_main2);
    }
}

4 Note that after creating a new activity, the component needs to be registered in the list, which is AndroidManifest.xml.
insert image description here5 In the first interface, create a button, and bind the listening event to the button, and jump to the second target interface when clicked.

<Button
        android:id="@+id/btn"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:background="@color/white"
        android:text="点我跳转到第二个activity"
        android:onClick="jumpToAnother"
        />

6Create a listening event in the main startup class

public void jumpToAnother(View view) {
    
    
//指定要跳转的界面
        startActivity(new Intent(this,MainActivity2.class));
    }

Animation: There are three types, namely frame-by-frame animation, tween animation and attribute animation

Frame-by-frame animation is used to add a group of pictures to a collection, so that the pictures can be switched quickly, so as to achieve an animation effect.
insert image description here
Then the entire selector can be directly regarded as a picture, which can be directly added to the page as a background picture to achieve dynamic effects. Note that when using it, you need to use the relativeLayout tag to use the selector as a picture, and then start it in the main class.
insert image description here

Then start it in the main startup class
insert image description here

Tween animation: set the initial value and end value and change time in the configuration file

Android will automatically complete the animation. There are four main attributes, namely alpha transparency, rotate rotation, scale zoom translate translation, etc. To use, first
create the corresponding xml file, and then import it in the main method.
insert image description here

The first type of alpha tag displays dynamic effects through transparency changes.

insert image description here

The second type of rotate tag achieves dynamic effects through rotation

insert image description here

The third type of scale tag achieves dynamic effects by adjusting the size of the image

insert image description here

The fourth type of translate tag achieves dynamic effects through translation

insert image description here
How animations are used in the main startup class. First, bind a listening event to a target picture, and use the listening event to start the animation.

insert image description here

3 attribute animation: adjust the display process by setting some attribute parameters in the main class

insert image description here
There is also an event monitoring method for the created objectAnimator object, and at the same time, you can bind a listener to the animation, and specify what will happen when an event such as the start or end of the animation occurs.
insert image description here

ViewPage realizes sliding left and right to switch between different layout layouts.

1 Prepare different layouts first, and then use ViewPage in the activity configuration file to tell the current interface that other viewPages need to be added

<androidx.viewpager.widget.ViewPager
        android:id="@+id/vp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

2 Get all the layout layouts in the main class and put them in the collection

LayoutInflater inflater = getLayoutInflater().from(this);
        View view1 = inflater.inflate(R.layout.layout1, null);
        View view2 = inflater.inflate(R.layout.layout2, null);
        View view3 = inflater.inflate(R.layout.layout3, null);
        ArrayList<View> view = new ArrayList<>();
        view.add(view1);
        view.add(view2);
        view.add(view3);
        MyAdapter myAdapter = new MyAdapter(view);

3 You need to use PagerAdpater to pass in the created layout. Because there is more than one layout, you need to create a collection as a constructor and pass in the layout. When inheriting PagerAdapter, you need to rewrite the method and add some other methods, as shown in the figure below.
insert image description here

public class MyAdapter extends PagerAdapter {
    
    
    private List<View> list;
    public MyAdapter(List<View> list){
    
    
        this.list=list;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
    
    
        container.addView(list.get(position),0);
        return list.get(position);
    }

    @Override
    public int getCount() {
    
    
        return list.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
    
    
        return view==object;
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
    
    
        container.removeView(list.get(position));
    }
}

Finally bind the two

ViewPager vp = findViewById(R.id.vp);
        vp.setAdapter(myAdapter);

Finally, set the set adapter to ViewPage for display.

insert image description hereAfter completing the above, you can achieve the effect of sliding left and right

Use of Fragments

Fragment can be intuitively understood as a small activity, which can have its own life cycle, and then the fragment can be placed in the activity for display and the same operation as the activity.

1 Create a layout to display in the fragment
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textv"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:textColor="@color/purple_200"
        android:text="今天是什么日子"
        android:layout_gravity="center"
        android:gravity="center"/>
    <Button
        android:id="@+id/lovewho"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="点我显示日期"/>

</LinearLayout>
2 After creating the fragment layout, create a fragment class to get some elements in the layout, and modify and obtain the elements in the layout
public class BlankFragment1 extends Fragment {
    
    
    private View root;
    private TextView textView;
    private Button btn;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
    
    
        // Inflate the layout for this fragment
        if(root==null){
    
    
            root = inflater.inflate(R.layout.fragment1, container, false);

        }
        textView = root.findViewById(R.id.textv);

        btn =root.findViewById(R.id.lovewho);
        btn.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                textView.setText("2022年5月20日,是和爱的人在一起的日子");
            }
        });
        return root;
    }
}
3 In the target activity that needs to be displayed, add the fragment tag, and only when the class corresponding to this fragment can complete the display
<fragment android:name="com.njupt.helloandroid.BlankFragment1"
        android:id="@+id/frag1"
        android:layout_width="match_parent"
        android:layout_height="80dp"/>

The above is just a static display of a fragment, if you want to switch between multiple fragments,

You need to dynamically switch fragments, the steps are as follows:

First create a fragmentLayout in the activity you want to display. Because you need to switch between fragments, you need to prepare more fragments. And you need to open up a space in the main activity to put the fragments that need to be displayed, and add them to the main activity as follows

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:background="@color/purple_500"
        android:id="@+id/fragmentch">//这个id就是在主程序中获取并且将其替换的标志
    </FrameLayout>

The second part is to obtain the monitoring event of the button in the main class. When the button is switched, different fragments can appear.

//准备对动态的fragment进行操作
        Button chang1 = findViewById(R.id.chang1);
        chang1.setOnClickListener(this);
        Button chang2 = findViewById(R.id.chang2);
        chang2.setOnClickListener(this);

        //准备两个fragment进行切换
    }
    @Override
    public void onClick(View v) {
    
    
        switch(v.getId()){
    
    
            case R.id.chang1:
                changeFragment(new BlankFragment());
                //传入不同的准备的fragment类即可关联到不同的fragment页面
            case R.id.chang2:
                changeFragment(new BlankFragment2());

        }

    }
    //将fragment看成一个事务
    public void changeFragment(Fragment fragment){
    
    
    //有一个fragment事务来控制事务的替换,删除和添加的操作
        FragmentManager fragManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragmentch,fragment);
        fragmentTransaction.addToBackStack(null);//这里是为了在返回时可以返回之前的那个fragment,
        fragmentTransaction.commit();

    }
How to realize the communication between Activity and Fragment==Bundle class

The data is stored through the bundle, and then the bundle storing the data is passed to the fragment,
insert image description here
insert image description here
and then the fragment acquires the transmitted data
insert image description here

Fragment life cycle

insert image description here

Guess you like

Origin blog.csdn.net/m0_56184347/article/details/124780828