疯狂安卓入门,crayandroid

系列文章目录


文章目录

  • 系列文章目录
  • [第一组 ViewGroup 为基类](#第一组 ViewGroup 为基类)
  • [第二组 TextView 及其子类](#第二组 TextView 及其子类)
    • button
    • [时钟 AnalogClock 和 TextClock](#时钟 AnalogClock 和 TextClock)
    • 计时器
  • [第三组 ImageView 及其子类](#第三组 ImageView 及其子类)
  • [第四组 AdapterView 及其子类](#第四组 AdapterView 及其子类)
  • [第五组UI ProgressBar及其子类](#第五组UI ProgressBar及其子类)
  • [第六组 ViewAnimator](#第六组 ViewAnimator)
  • 第七组UI对话框
  • android事件机制
  • [4 Activity & Fragment](#4 Activity & Fragment)
    • [4.3 Activity生命周期](#4.3 Activity生命周期)
    • [4. android:launchMode=](#4. android:launchMode=)
      • [4.4.1 standard 模式 (默认模式)](#4.4.1 standard 模式 (默认模式))
      • [4.4.2 singleTop 模式](#4.4.2 singleTop 模式)
      • [4.4.3 singleTask 模式](#4.4.3 singleTask 模式)
      • [4.4.4 singleInstance 模式](#4.4.4 singleInstance 模式)
    • [4.5 Fragment](#4.5 Fragment)
      • [4.5.3 Fragment与Activity通讯](#4.5.3 Fragment与Activity通讯)
      • [4.5.4 Fragment管理与Fragment事务](#4.5.4 Fragment管理与Fragment事务)
  • [chapter 5 Intent, IntentFilter](#chapter 5 Intent, IntentFilter)
    • [5.1 Intent对象](#5.1 Intent对象)
    • [5.2 Intent属性及 intent-filter 配置](#5.2 Intent属性及 intent-filter 配置)
      • [Compoent 属性](#Compoent 属性)
      • [Action, Category属性](#Action, Category属性)
      • [Data, Type 属性](#Data, Type 属性)
        • [实例:使用Action, Data属性启动系统Activity](#实例:使用Action, Data属性启动系统Activity)
      • [Extra 属性](#Extra 属性)
      • [Flag 属性](#Flag 属性)
  • [6 Android 应用资源](#6 Android 应用资源)
    • [6.1 应用资源](#6.1 应用资源)
    • [5.2 定义字符串 颜色 尺寸资源文件 数组](#5.2 定义字符串 颜色 尺寸资源文件 数组)
    • [6.4 Drawable资源](#6.4 Drawable资源)
      • [6.4.2 StateListDrawable资源](#6.4.2 StateListDrawable资源)
      • [6.4.3 LayerDrawable 资源](#6.4.3 LayerDrawable 资源)
      • [6.4.6 ShapeDrawable资源](#6.4.6 ShapeDrawable资源)
      • [6.4.5 ClipDrawable 资源](#6.4.5 ClipDrawable 资源)
      • [6.4.6 AnimationDrawable资源](#6.4.6 AnimationDrawable资源)
    • [6.5 属性动画资源 Property Animation](#6.5 属性动画资源 Property Animation)
    • [6.6 使用原始XML资源; Layout资源; Menu资源](#6.6 使用原始XML资源; Layout资源; Menu资源)
    • [6.9 样式和主题 style theme](#6.9 样式和主题 style theme)
    • [6.10 属性资源](#6.10 属性资源)
    • [6.11 使用原始资源](#6.11 使用原始资源)
    • [6.12 国际化资源](#6.12 国际化资源)
    • [6.13 适应不同屏幕的资源](#6.13 适应不同屏幕的资源)
  • xxx
  • [9 使用ContentProvider实现数据共享](#9 使用ContentProvider实现数据共享)
  • [10 Service和BroadcastReceiver](#10 Service和BroadcastReceiver)
    • [10.1 Service](#10.1 Service)
      • [10.1.5 IntentService](#10.1.5 IntentService)
    • [10.2 跨进程调用 Service(AIDL Service)](#10.2 跨进程调用 Service(AIDL Service))
  • [14 管理Android系统桌面](#14 管理Android系统桌面)
    • [14.1 动态壁纸 Live Wallpapers](#14.1 动态壁纸 Live Wallpapers)
  • xml
  • java


第一组 ViewGroup 为基类

ViewGroup继承自View类

View <- ViewGroup <- LinearLayout <- TableLayout

向TableLayout中添加 TableRow (容器) 就是插入了一行

帧布局

ViewGroup <- FrameLayout

java 复制代码
public class MainActivity extends AppCompatActivity {
    int [] names = new int[] {R.id.view01, R.id.view02, R.id.view03, R.id.view04, R.id.view05, R.id.view06};
    TextView[] views = new TextView[names.length];

    class MyHandler extends Handler {
        private WeakReference<MainActivity> activity;
        public MyHandler(WeakReference<MainActivity> activity) {
            this.activity = activity;
        }
        private int currentColor = 0;
        int[] colors = new int[]{R.color.red,
                R.color.green,
                R.color.blue,
                R.color.yellow,
                R.color.pink,
                R.color.teal};
        @Override
        public void handleMessage(@NonNull Message msg) {
            if (msg.what == 0x123) {
                for (int i = 0, len = activity.get().names.length; i < len; i++) {
                    activity.get().views[i].setBackgroundResource(
                            colors[(i + currentColor) % colors.length]
                    );
                }
                ++currentColor;
            }
            super.handleMessage(msg);
            Log.d("thid", "handleMessage:" + Thread.currentThread().getId());
        }
    }

    private Handler handler = new MyHandler(new WeakReference(this));
    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);
        for (int i = 0; i < names.length; i++) {
            views[i] = findViewById(names[i]);
        }
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                handler.sendEmptyMessage(0x123);
                Log.d("thid", "run:" + Thread.currentThread().getId());
            }
        }, 0, 500);

        Log.d("thid", "onCreate:" + Thread.currentThread().getId());
    }
}

约束布局

P100

第二组 TextView 及其子类

View <- TextView <- EditText / Button

rich text

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">


    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="fuck java"
            android:textSize="20pt"
            android:drawableEnd="@mipmap/ic_launcher_round"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:text="fuck java  fuck java  fuck java"
            android:textSize="20sp"
            android:ellipsize="middle"
            android:textAllCaps="true"
            />
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="email xx@192.com"
            android:singleLine="true"
            android:autoLink="email|phone"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="text word"
            android:shadowColor="@color/black"
            android:shadowDx="10.0"
            android:shadowDy="8.0"
            android:shadowRadius="3.0"
            android:textColor="#f00"
            android:textSize="18pt"/>
        <CheckedTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="checked text"
            android:textSize="20pt"
            android:checkMark="@drawable/ok"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="bounding text"
            android:textSize="24pt"
            android:background="@drawable/bg_border1"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="round bg"
            android:textSize="24pt"
            android:background="@drawable/bg_border2"/>
    </LinearLayout>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="212dp"
        android:shadowColor="#aa5"
        android:shadowDx="5"
        android:shadowDy="5"
        android:shadowRadius="1"
        android:text="Button"
        android:textSize="12pt"
        app:layout_constraintBottom_toTopOf="@+id/imageButton2"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="24dp"
        android:layout_marginBottom="48dp"
        android:background="@drawable/button_selector"
        android:text="ButtonbgXX"
        android:textSize="11sp"
        app:layout_constraintBottom_toTopOf="@+id/imageButton2"
        app:layout_constraintStart_toStartOf="parent" />

    <ImageButton
        android:id="@+id/imageButton2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="40dp"
        android:layout_marginBottom="84dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:srcCompat="?android:attr/fingerprintAuthDrawable" />

    <Button
        android:id="@+id/button2"
        android:layout_width="131dp"
        android:layout_height="74dp"
        android:layout_marginStart="48dp"
        android:layout_marginBottom="320dp"
        android:background="@drawable/chat_box"
        android:text="股的拉开"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button" />

</androidx.constraintlayout.widget.ConstraintLayout>

button

p109

时钟 AnalogClock 和 TextClock

TextView <- TextClock

View <- AnalogClock 重写了OnDraw方法

计时器

第三组 ImageView 及其子类

View <- ImageView <- ImageButton/ZoomButton/FloatingActionButton

第四组 AdapterView 及其子类

ViewGroup <- AdapterView

类似wechat通讯录界面

SimpleAdapter

java 复制代码
public class MainActivity extends AppCompatActivity {
    private String[] names = new String[]{"namesdsf1", "弄汤", "里打找", "是空间地方"};
    private String[] descs = new String[]{"[                ]", "sdf", "skdjf", "sjkdfj"};
    private int[] imageids = new int[]{R.drawable.dice_1, R.drawable.dice_2, R.drawable.dice_3, R.drawable.dice_4};
    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);

        List<Map<String, Object>> listitems = new ArrayList<>();
        for (int i = 0; i < names.length; i++) {
            Map<String, Object> listitem = new HashMap<>();
            listitem.put("header", imageids[i]);
            listitem.put("personName", names[i]);
            listitem.put("desc", descs[i]);
            listitems.add(listitem);
        }
        SimpleAdapter sa = new SimpleAdapter(this, listitems,
                R.layout.simple_item,
                new String[]{"header", "personName","desc"},
                new int[]{R.id.header, R.id.name, R.id.desc});
        ListView list = findViewById(R.id.list2xx);
        list.setAdapter(sa);
    }
}
xml 复制代码
<?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="wrap_content"
    android:orientation="horizontal">
    <ImageView
        android:id="@+id/header"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:paddingLeft="10dp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:textColor="#f0f"
            android:textSize="20dp"/>
        <TextView
            android:id="@+id/desc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:textSize="14dp"/>
    </LinearLayout>


</LinearLayout>
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <ListView
            android:id="@+id/list2xx"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="#0f0"
            android:dividerHeight="1dp"
            android:headerDividersEnabled="false" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

AutoCompleteTextView 的功能和用法

从 EditText 派生

当用户输入一定字符之后,自动完成文本框会显示一个下拉菜单,当用户选择某个菜单项之后,AutoCompleteTextView自动填写该内文本框

ExapndaleListView

增加可将ListView的内容分组功能

AdapterViewFlipper

AdapterViewAnimator <- AdapterViewFlipper

自动播放之图片库

P140

叠在一起的图片

java 复制代码
public class MainActivity extends AppCompatActivity {
    private int[] imageids = new int[]{R.drawable.dice_1,
            R.drawable.dice_2,
            R.drawable.dice_3,
            R.drawable.dice_4,
            R.drawable.dice_5,
            R.drawable.dice_6
    };
    private StackView sv;
    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);

        sv = findViewById(R.id.mStackView);

        List<Map<String, Object>> listitems = new ArrayList<>();
        for (int i = 0; i < imageids.length; i++) {
            Map<String, Object> litm = new HashMap<>();
            litm.put("image", imageids[i]);
            listitems.add(litm);
        }
        SimpleAdapter sa = new SimpleAdapter(this, listitems,
                R.layout.simple_item,
                new String[]{"image"},
                new int[]{R.id.stack_view_image});
        sv.setAdapter(sa);
    }
    public void prevfff(View v) {
        sv.showPrevious();
    }
    public void nextfff(View v) {
        sv.showNext();
    }
}
xml 复制代码
<?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="horizontal">
    <StackView
        android:id="@+id/mStackView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:loopViews="false"/>
    <LinearLayout
        android:layout_width="226dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="prevfff"
            android:text="shangyige" />
        <Button
            android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="nextfff"
            android:text="xiayige" />
    </LinearLayout>
</LinearLayout>
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/stack_view_image"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:paddingLeft="10dp"/>

RecyclerView 组件

P144

java 复制代码
package com.example.chapter1noactivity;

import android.app.Person;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SimpleAdapter;
import android.widget.StackView;
import android.widget.TextView;

//import androidx.activity.compose.setContent;
//import androidx.activity.enableEdgeToEdge;
//import androidx.compose.foundation.layout.fillMaxSize;
//import androidx.compose.foundation.layout.padding;
//import androidx.compose.material3.Scaffold;
//import androidx.compose.material3.Text;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//import com.example.chapter1noactivity.ui.theme.Chapter1NoActivityTheme;


public class MainActivity extends AppCompatActivity {
    private String[] names = new String[]{"namesdsf1", "弄汤", "里打找", "是空间地方"};
    private String[] descs = new String[]{"[   xxx    ]", "sdf", "skdjf", "sjkdfj"};

    private int[] imageids = new int[]{R.drawable.dice_1,
            R.drawable.dice_2,
            R.drawable.dice_3,
            R.drawable.dice_4,
            R.drawable.dice_5,
            R.drawable.dice_6
    };

    private StackView sv;
    private RecyclerView recyclerView;
    private  List<Person> personList = new ArrayList<>();
    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recycler);
        // 设置recyclerView保持固定大小,可优化其性能
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        // 设置滚动方向
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        // 为recyclerView设置布局管理器
        recyclerView.setLayoutManager(layoutManager);
        initData();
        RecyclerView.Adapter adapter = new RecyclerView.Adapter<PersonViewHolder>() {
            // 创建列表项组件的方法,使用该方法所创建的组件会被自动缓存
            @Override
            public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
                View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);
                return new PersonViewHolder(view, this);
            }
            // 为列表项组件绑定数据的方法,每次组件重新显示出来时都会重新执行该方法
            @Override
            public void onBindViewHolder(PersonViewHolder viewHolder, int i) {
                viewHolder.nameTv.setText(names[i]);
                viewHolder.descTv.setText(descs[i]);
                viewHolder.headerIv.setImageResource(imageids[i]);
            }
            // 该方法的返回值决定包含多少个列表项
            @Override
            public int getItemCount() {
                return personList.size();
            }
        };
        recyclerView.setAdapter(adapter);
    }
    private void initData() {
        for (int i = 0; i < names.length; i++)
            this.personList.add(new Person(names[i], descs[i], imageids[i]));
    }
    class PersonViewHolder extends RecyclerView.ViewHolder {
        View rootView;
        TextView nameTv;
        TextView descTv;
        ImageView headerIv;
        private RecyclerView.Adapter adapter;
        public PersonViewHolder(View itemView, RecyclerView.Adapter adapter) {
            super(itemView);
            this.nameTv = itemView.findViewById(R.id.name);
            this.descTv = itemView.findViewById(R.id.desc);
            this.headerIv = itemView.findViewById(R.id.header);
            this.rootView = itemView.findViewById(R.id.item_root);
            this.adapter = adapter;
            rootView.setOnClickListener(view -> {
                int i = (int)(Math.random() * (personList.size() + 1));
//                Person person = new Person(personList.get(i).name, personList.get(i).desc, personList.get(i).header);
                Person person = new Person(names[i], descs[i], imageids[i]);
                adapter.notifyItemInserted(2);
                personList.add(2, person);
                adapter.notifyItemRangeChanged(2, adapter.getItemCount());
            });
            rootView.setOnLongClickListener(view -> {
                int position = this.getAdapterPosition();
                // notify RecyclerView animation
                adapter.notifyItemRemoved(position);
                // rm data from basic model
                MainActivity.this.personList.remove(position);
                // notify recyclerview exec rm
                adapter.notifyItemRangeChanged(position, adapter.getItemCount());
                return false;
            });
        }
    }
    public void prevfff(View v) {
        sv.showPrevious();
    }
    public void nextfff(View v) {
        sv.showNext();
    }
}

activity_main.xml

xml 复制代码
<?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="horizontal">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

layout/item.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item_root"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <ImageView
        android:id="@+id/header"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:paddingLeft="10dp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:textColor="#f0f"
            android:textSize="20dp"/>
        <TextView
            android:id="@+id/desc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="10dp"
            android:textSize="14dp"/>
    </LinearLayout>
</LinearLayout>

RecyclerView.Adapter大致提供了如下方法来控制对列表项的修改

  • notifyItemChanged(int position): 当position位置的数据发生改变时,程序调用该方法通知Adapter更新界面--Adapter回调对应位置的onBindViewHolder()方法进行更新
  • notifyItemRangeChanged(int positonStart, int itemCount)
  • notifyItemInserted(int position)
  • notifyItemMoved(int fromPosition, int toPosition)
  • notifyItemRangeInserted(int positionStart, int itemCount)
  • notifyItemRemoved(int position)
  • notifyItemRangeRemoved(int positionStart, int itemCount)

第五组UI ProgressBar及其子类

ProgressBar <- AbsSeekBar <- SeekBar/RatingBar

java 复制代码
public class MainActivity extends AppCompatActivity {
    private int[] data = new int[100];
    private int hasData = 0;
    int status = 0;
    private ProgressBar bar;
    private ProgressBar bar2;
    static class MyHandler extends Handler {
        private WeakReference<MainActivity> activity;
        MyHandler(WeakReference<MainActivity> activity) {
            this.activity = activity;
        }
        @Override
        public  void handleMessage(Message msg) {
            if (msg.what == 0x111) {
                String val = String.valueOf(activity.get().status);
                Log.d("userinfo", val);
                activity.get().bar.setProgress(activity.get().status);
                activity.get().bar2.setProgress(activity.get().status);
            }
        }
    }
    MyHandler mHandler = new MyHandler(new WeakReference<>(this));
    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);

        bar = findViewById(R.id.bar);
        bar2 = findViewById(R.id.bar2);
        new Thread() {
            @Override public void run() {
                while (status < 100) {
                    status = doWork();
                    mHandler.sendEmptyMessage(0x111);
                }
            }
        }.start();
    }
    public int doWork() {
        data[hasData++] = (int)(Math.random() * 100);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return hasData;
    }
}

SeekBar

拖动滑块改变图片透明度

java 复制代码
    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);
        
        final  ImageView image = findViewById(R.id.imageView);
        SeekBar seekBar = findViewById(R.id.seekBar);
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) {
                image.setImageAlpha(progress);
            }
            @Override public void onStartTrackingTouch(SeekBar bar) {

            }
            @Override public void onStopTrackingTouch(SeekBar bar) {

            }
        });
    }

RatingBar

星条评分条

RatingBar通过星星来表示进度

第六组 ViewAnimator

FrameLayout <- ViewAnimator <- ViewSwitcher <- ImageSwitcher/TextSwitcher

FrameLayout <- ViewAnimator <- ViewFlipper

java 复制代码
public class MainActivity extends AppCompatActivity {


    public static final int NUMBER_PER_SCREEN = 4;
    private List<DataItem> items = new ArrayList<>();
    private int screenNo = -1;
    private int screenCount = 0;
    private ViewSwitcher switcher;
    private LayoutInflater inflater;
    private BaseAdapter adapter = new BaseAdapter() {
        @Override
        public int getCount() {
            if (screenNo == screenCount-1 && items.size() % NUMBER_PER_SCREEN != 0) {
                return items.size() % NUMBER_PER_SCREEN;
            } else {
                return NUMBER_PER_SCREEN;
            }
        }

        @Override
        public DataItem getItem(int i) {
            return items.get(screenNo * NUMBER_PER_SCREEN + i);
        }

        // 当点击当前页面的item是该函数会被调用,i为item在grid的idx
        @Override
        public long getItemId(int i) {
            return i;
        }

        // 当需要显示画面时,该函数会被自动调用,调用每个item调用一次,调用次数与getCount函数有关
        @Override
        public View getView(int i, View convertView, ViewGroup viewGroup) {
            View view;
            ViewHolder viewHolder;
            if (convertView == null) {
                view = inflater.inflate(R.layout.labelicon, null);
                ImageView imageView = view.findViewById(R.id.imageview);
                TextView textView = view.findViewById(R.id.textview);
                view.setTag(viewHolder);
            } else {
                view = convertView;
                viewHolder = (ViewHolder) view.getTag();
            }
            viewHolder.imageView.setImageDrawable(getItem(position).drawable);
            viewHolder.textView.setText(getItem(position).dataName);
            return null;
        }
    };
    public static class DataItem {
        String dataName;
        Drawable drawable;
        DataItem(String dataName, Drawable drawable) {
            this.dataName = dataName;
            this.drawable = drawable;
        }
    }
    public static class ViewHolder {
        ImageView imageView;
        TextView textView;
        ViewHolder(ImageView imageView, TextView textView) {
            this.imageView = imageView;
            this.textView = textView;
        }
    }
    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);

        inflater = LayoutInflater.from(this);
        for (int i = 0; i < 20; i++) {
            String label = "" + i;
            Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher, null);
            DataItem item = new DataItem(label, drawable);
            items.add(item);
        }
        screenCount = items.size() % NUMBER_PER_SCREEN == 0 ? items.size() / NUMBER_PER_SCREEN : items.size() / NUMBER_PER_SCREEN + 1;
        switcher = findViewById(R.id.viewSwitcher);
        switcher.setFactory(() -> {
            return inflater.inflate(R.layout.slidelistview, null);
        });
        next(null);
    }
    public void next(View v) {
        if (screenNo < screenCount - 1) {
            screenNo++;
            switcher.setInAnimation(this, R.anim.slide_in_right);
            switcher.setOutAnimation(this, R.anim.slide_out_left);
            ((GridView)switcher.getNextView()).setAdapter(adapter);
            switcher.showNext();
        }
    }
    public void prev(View v) {
        if (screenNo > 0) {
            screenNo--;
            switcher.setInAnimation(this, android.R.anim.slide_in_left);
            switcher.setOutAnimation(this, android.R.anim.slide_out_right);
            ((GridView)switcher.getNextView()).setAdapter(adapter);
            switcher.showPrevious();
        }
    }
}

第七组UI对话框

AlertDialog <- ProgressDialog/DatePickerDialog/TimePickerDialog

java 复制代码
public class MainActivity extends AppCompatActivity {

    @Override
    public void onCreate(Bundle savedInstanceStatus) {
        super.onCreate(savedInstanceStatus);
        setContentView(R.layout.activity_main);

        Button simple = findViewById(R.id.button);
        Button bn = findViewById(R.id.button2);
        Button bn3 = findViewById(R.id.button3);

        simple.setOnClickListener(view -> {
            Toast toast = Toast.makeText(this, "simple txt", Toast.LENGTH_SHORT);
            Log.d("userinfo", "be");
            toast.show();
            Log.d("userinfo", "af");
        });
        bn.setOnClickListener(view -> {
            Toast toast = new Toast(this);
            toast.setGravity(Gravity.CENTER, 0, 0);
            ImageView image = new ImageView(this);
            image.setImageResource(R.drawable.dice_1);
            LinearLayout l1 = new LinearLayout(this);
            l1.addView(image);
            TextView textView = new TextView(this);
            textView.setText("uu di coco ");
            textView.setTextSize(24f);
            textView.setTextColor(Color.MAGENTA);
            l1.addView(textView);
            toast.setView(l1);
            toast.setDuration(Toast.LENGTH_SHORT);
            toast.show();
        });
        bn3.setOnClickListener((view) -> {
            AlertDialog.Builder builder = new AlertDialog.Builder(this)
                    .setTitle("simple dialog")
                    .setIcon(R.mipmap.ic_launcher_round)
                    .setMessage("diag test\nsecond line").setView(R.layout.login);
            builder.setPositiveButton("yes", (dialog, which)-> {
                // get login info
                Toast toast = Toast.makeText(this, "sclicked yes button!", Toast.LENGTH_SHORT);
                toast.show();
            });
            builder.setNegativeButton("niga", (dialog, which)-> {
                Toast toast = Toast.makeText(this, "clicked niga button!", Toast.LENGTH_SHORT);
                toast.show();
            });
//            builder.setNeutralButton()
            builder.create().show();
        });
    }
}

android事件机制

基于监听的事件处理

内部类作为事件监听器

java 复制代码
// 2. 事件监听器
class MyClickListener implements View.onClickListener {
    // 事件处理函数
    @Override
    public void onClick(View v) {
        TextView txt = findViewById(R.id.txt); txt.setText("xxx");
    }
}
@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    // 1. 确定事件源
    Button bn = findViewById(R.id.bn);
    // 3. 注册事件处理器
    bn.setOnClickListener(new MyClickListener());
}

事件处理流程:

  1. 将事件监听器注册到事件源

  2. 外部动作触发事件源上的事件

  3. 事件源生成事件对象

  4. 该事件对象触发事件监听器,事件被作为参数传入事件处理器

  5. 调用事件处理器作出响应

    外部动作
    | 事件
    2 ↗
    | 3 4 5
    ᐯ / ↘ ↗ 事件处理器
    事件源 <--1--事件监听器-->事件处理器

各种类型的事件监听器:

View.OnClickListener: 单击事件

View.OnCreateContextMenuListener: 创建上下文菜单事件的事件监听器

View.onFocusChangeListener: 焦点改变的事件监听器

View.OnKeyListener: 按键事件的事件监听器

View.OnLongClickListener: 长按事件

View.OnTouchListener: 触摸事件的时间监听器

外部类作为事件监听器

public class MyClickListener implements View.onClickListener写在类的外部

Activity 本身作为事件监听器

java 复制代码
public class MainActivity extends Activity implements View.OnClickListener{
    @Override
    public void onCreate(xxx){

    }

    xxx

    @Override
    public void onClick(View v){
        show.setText("bn button!");
    }
}

lambda表达式作为事件监听器类

java 复制代码
bn.setOnClickListener(view -> show.setText("bn button"));

直接绑定到标签

xml 复制代码
<Button
    android:onClick="clickHandler"/>

基于回调的事件处理

重写GUI组件的相关方法

boolean onKeyDown(int keyCode, KeyEvent event)

boolean onKeyLongPress(int keyCode, KeyEvent event)

boolean onKeyShortcut(int keyCode, KeyEvent event)

boolean onKeyUp(int keyCode, KeyEvent event)

boolean onTouchEvent(MotionEvent event)

boolean onTrackballEvent(MotionEvent event)

java 复制代码
public class MyButton extends Button {
    public MyButton(Context context, AttributeSet set) {
        super(context, set);
    }
    @Override
    public  boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        Log.d("userinfo", "button true");
        return true;  // 该方法是否能完全处理该事件
        // true: 事件不会传播出去
        // false: 事件会传播到该事件所在activity的方法
    }
}

响应系统设置

Configuration类

java 复制代码
// Activity的方法
Configuration cfg = getResources().getConfiguration();

3.5 Handler消息传递机制

Android的UI操作不是线程安全的,只允许UI线程(主线程)修改Activity里的UI组件

3.5.1 Handler 类

  1. 在新启动的线程中发送消息
  2. 在主线程中获取\处理消息
java 复制代码
public class Handler {
  void handleMessage(@NonNull Message msg)  // 处理消息
  final boolean hasMessages(int what)  // 消息队列中是否包含what属性为指定值的消息
  final boolean hasMessages(int what, @Nullable Object object)
   final boolean sendEmptyMessage(int what)
   final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis)
}
java 复制代码
    int imgs[] = {R.drawable.dice_1,
            R.drawable.dice_2,
            R.drawable.dice_3,
            R.drawable.dice_4,
            R.drawable.dice_5,
            R.drawable.dice_6};
    class MyHandler extends Handler {
        private WeakReference<MainActivity> activity;
        int currid = 0;
        public MyHandler(WeakReference<MainActivity> activity) {
            this.activity = activity;
        }
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 0x1233) {
                activity.get().show.setImageResource(imgs[currid++ % imgs.length]);
            }
        }
    }
    MyHandler myHandler = new MyHandler(new WeakReference(this));
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        show = findViewById(R.id.imageView);

        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                myHandler.sendEmptyMessage(0x1233);
            }
        }, 0, 80);
    }

3.5.2 Handler, Loop, MessageQueue的工作原理

Handler把消息发给Looper管理的消息队列和处理消息;每个线程只有一个Looper,它负责管理MessageQueue(由Loop初始化),会不断的从MessageQueue中去取出消息并分给对应的Handler处理;

loop(){
  for(;;) {
    MesageQueue.next(); // 从队列中取出消息
    
    将消息分发给对应的handler处理
  }
}

4 Activity & Fragment

Activity <- ListActivity <- LauncherActivity
         \ FragmentActivity

PreferenceActivity & PreferenceFragment结合在一起,前者之负责加载选项设置头布局文件(跟元素是preference-headers),后者负责加载选项设置布局文件.

包含多个Activity的Manifest

含有intent-filter action.name=xxxMAIN actegory.name=xxxLAUNCHER的为程序的入口activity

xml 复制代码
       <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/title_activity_main"
            android:theme="@style/Theme.Chapter1NoActivity"
            android:configChanges="orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".ExpandableListActivityTest" android:label="查看星际兵种"></activity>
        <activity android:name=".PreferenceActivityTest" android:label="设置参数"></activity>

LauncherActivity包含@Override public Intent intentForPosition(int position),当屏幕上的内容被点击时该方法会被调用

Activity的启动和关闭

Activity启动其他Activity的方法:

  • startActivity(Intent intent)
  • startActivityForResult(Intent, int requestCode) 以指定的请求码启动Activity,而且程序将会获取新启动的Activity返回的结果(通过重写onActivityResult()方法获取)
    关闭:
  • finish()
  • finishActivity(int requestCode): 结束以startActivityForResult(Intent intent, int requestCode)方法启动的Activity
java 复制代码
        Intent intent = new Intent(SecondActivity.this, MainActivity.class);
        startActivity(intent);
        finish();

使用Bundle在Activity之间交换数据

Intent 对象和携带 Bundle

intent.putExtras(Bundle data);

Bundle intent.getExtras()

intent.putExtra(String key, Xxx value)

intent.getXxxExtra(String key)

bundle.putXxx(String key, Xxx value)

bundle.putSerializable(String key, Serializable data)

get...

java 复制代码
Bundle data = new Bundle();
        data.putSerializable("person", name.getText().toString() + " : " + passwd.getText().toString());
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtras(data);
startActivity(intent); / startActivityForResult(intent, requestCode:0);

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (requestCode == 0 && resultCode == 0) {
            Bundle data = intent.getExtras();
            Toast.makeText(this, data.getString("person"), Toast.LENGTH_SHORT).show();
        }
    }
_______________
intent = getIntent();
Bundle bui = intent.getExtras();
intent.getExtras();
Object data = bui.get("person");
Toast.makeText( this, data.toString(), Toast.LENGTH_LONG).show();

setResult(resultCode:0, intent);

4.3 Activity生命周期

                    加载Activity
                        |
                        ᐯ
        +----------> onCreate
        |               |
        |               ᐯ
        |           onStart <----------------------- onRestart   
        |               |                                |
    用户再次启动          ᐯ                                |
    该Activity      onResume <-----------------+         |
        |               |                      |         |  
        |               ᐯ                      |         |
    应用进程           运行状态                   |         |
     被终止              (其他Activity           |         |
       ↑                转入前台)                |         |
       |                |                      |         |
       |                ᐯ                  该Activity再   |
       |            onPause                次回到前台      |
       |                |                      |          |
       |                ᐯ                      |          |
    更高优先级的-------暂停状态--------------------+         |
    应用需要内存          |                                 |
        |               该Activity变为完全不可见             |
        |               |                                 |
        |               ᐯ                            用户再次启动该
        |               onStop                     Activity使之进入前台
        |               |                                 |
        |               ᐯ                                 |
        +-----------停止状态 ------------------------------+
                        |
                        该Activity结束或销毁
                        |
                        ᐯ
                    onDestroy
                        |
                        ᐯ
                     销毁状态
java 复制代码
public class MainActivity extends Activity
{
    private String TAG = "userinfo";
    @Override protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.layout_text);
        Log.d(TAG, "---onCreate---");
    }
    @Override public void onStart() {
        super.onStart();
        Log.d(TAG, "---onStart---");
    }
    @Override public void onResume() {
        super.onResume();
        Log.d(TAG, "---onResume---");
    }
    @Override public void onPause() {
        super.onPause();
        Log.d(TAG, "--onPause---");
    }
    @Override public void onStop() {
        super.onStop();
        Log.d(TAG, "---onStop---");
    }
    @Override public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "---onDestroy---");
    }
}

4. android:launchMode=

android中 Task 负责以栈的形式管理所有的 Activity

4.4.1 standard 模式 (默认模式)

为目标Activity创建一个新的实例,并将该Activity添加到当前Task栈中,该模式不会启动新的Task,新Activity将被添加到原有的Task中

java 复制代码
    protected void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        this.setContentView(layout);
        TextView tv = new TextView(this);
        tv.setText("Activity is :" + this.toString() + "\n" + ", Task ID is:" + this.getTaskId());
        Button bn = new Button(this);
        bn.setText("launch new MainActivity");
        layout.addView(tv);
        layout.addView(bn);
        bn.setOnClickListener(view -> {
            Intent intent = new Intent(MainActivity.this, MainActivity.class);
            startActivity(intent);
        });
    }

          |                   |
第三次启动: | MainActivity实例3 |
第二次启动: | MainActivity实例2 |
第一次启动: | MainActivity实例1 |
          +-------------------+
             Activity栈
当用户按下返回按钮时,系统将会"逐一"从Activity栈顶删除实例

4.4.2 singleTop 模式

当将要启动的目标Activity已经位于Task栈顶时,系统不会重新创建目标实例,而是直接复用已有的Activity实例

如果将要启动的Activity没有位于栈顶,此时系统会重新创建目标Activity的实例,并将它加载到Task盏顶

4.4.3 singleTask 模式

保证同一个Task内只有一个实例.

当要启动的Activity已经存在,但没有位于Task栈顶,系统将会把位于该Activity上面的所有Activity移除,从而使得目标Activity在栈顶.

4.4.4 singleInstance 模式

xml 复制代码
<activity android:name=".MainActivity"
    android:label="@string/title_activity_main"
    android:exported="true"
    android:launchMode="singleInstance"
    android:theme="@style/Theme.Chapter1NoActivity"
    android:configChanges="orientation|screenSize">
    <intent-filter>
        <!-- 指定该Activity能响应Action为指定字符串的Intent -->
        <action android:name="com.example.intent.action.XXACTION"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

exported属性为true表明允许通过其他程序来启动Activity

java 复制代码
Intent intent = new Intent(this, SecondActivity.class); 
startActivity(intent);

// 隐式Intent启动Activity
Intent intent = new Intent();
intent.setAction("com.example.intent.action.XXACTION");
startActivity(intent);

4.5 Fragment

  • Fragment总是作为Activity界面的组成部分.Fragmemt可调用getActivity()方法获取它所在的Activity, Activity可调用FragmentManager的findFragmentById()或findFragmentByTag()方法来获取Fragment

  • 在Activity运行过程中,可调用FragmentManager的add(), remove(), replace()方法动态地添加,删除或替换Fragment

  • 一个Activity可以同时组合多个Fragment;一个Fragment也可被多个Activity复用

  • Fragment可以响应自己的输入时间,并拥有自己的生命周期,但它们的生命周期直接被所属的Activity控制

    Fragment <-- DialogFragment / ListFragment / PreferenceFragment / WebViewFragment

开发Fragment与开发Activity非常相似.需要实现三个方法:onCreate, onCreateView(绘制界面组件是回调该方法,该方法返回的iew将作为该Fragment显示的View组件),onPause(当用户离开fragment时回调该方法)

4.5.3 Fragment与Activity通讯

为了在Activity中显示Fragment,还必须将Fragment添加到Activity中.将Fragment添加到Activity中有两种方式:

  • 在布局文件中使用<fragment/>元素, 该元素的android:name属性指定Fragment的实现类
  • 在代码中通过FragmentTransaction对象的add()方法添加Fragment

Activity的getSupportFragmentManager()方法可返回FragmentManager,FragmentManager对象的beginTransaction()方法即可开启并返回FragmentTransaction对象

xml 复制代码
 <fragment
        android:id="@+id/book_list"
        android:name="com.example.chapter1noactivity.BookListFragment"
        android:layout_width="100dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />
java 复制代码
    // 实现Callbacks接口必须实现的方法
    @Override
    public void onItemSelected(int id)
    {
        // 创建Bundle,准备向Fragment传入参数
        Bundle arguments = new Bundle();
        arguments.putInt(BookDetailFragment.ITEM_ID, id);
        // 创建BookDetailFragment对象
        Log.d("userinfo", "MainActivity, onItemSelected");
        BookDetailFragment fragment = new BookDetailFragment();
        // 向Fragment传入参数
        fragment.setArguments(arguments);
        // 使用fragment替换book_detail_container容器当前显示的Fragment
        getSupportFragmentManager().beginTransaction().replace(
                R.id.book_detail_container, fragment).commit(); // ①
    }

将Fragment添加到Activity之后,Fragment必须与Activity交互信息:1. Fragment获取它所在的Activity:调用Fragment的getActivity()方法即可返回它所在的Activity 2. Activity获取Fragment,调用Activity关联的FragmentManager的findFragmentById(int id)或findFragmentByTag(String tag)方法即可获取指定的Fragment

4.5.4 Fragment管理与Fragment事务

Activity管理Fragment主要依靠FragmentManager:

  • 使用findFragmentById()或findFragmentByTag()获取制定Fragment
  • 调用popBackStack()将Fragment从后台栈中弹出
  • 调用addOnBackStackChangeListener()注册一个监听器,用于监听后台栈的变化
java 复制代码
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

ExampleFragment newFragment = new ExampleFragment();
fragmentTransaction.replace(R.id.fragment_container, newFragment);
// 将事务(操作)添加到Back栈,允许用户按BACK键返回到替换Fragment之前的状态
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

chapter 5 Intent, IntentFilter

5.1 Intent对象

Activity, Service, BroadcastReceiver这三个组件都可依赖Intent来启动,Intent封装了程序想要启动程序的意图和通讯信息

类型 启动方法
Activity startActivity(Intent); startActivityForResult(Intent, int);
Service ComponentName startService(Intent); boolean bindService(Intent, ServiceConnection conn, int flags);
BroadcastReceiver sendBroadcast(Intent); sendBroadcast(Intent, String); sendOrderedBroadcast(Intent, String); ...

5.2 Intent属性及 intent-filter 配置

Compoent 属性

为Intent指定了Component属性

java 复制代码
@Override protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button bn = findViewById(R.id.bn);
    bn.setOnClickListener(view -> {
        ComponentName comp = new ComponentName(MainActivity.this, SecondActivity.class);
        Intent intent = new Intent();
        intent.setComponent(comp);
        // => new Intent(this, SecondActivity.class)
        startActivity(intent);
    });
}

SecondActivity

java 复制代码
ComponentName comp = getIntent().getComponent();
组件包名 comp.getPackageName()
组件类名 comp.getClassName()
String action = getIntent().getAction()
Set<String> cates = getIntent().getCategories()

Action, Category属性

Action和Category都是普通字符串,Action代表intent所要完成的一个抽象"动作",Category为Action添加额外信息. 具体启动哪个Activity由<intent-filter.../>配置.

java 复制代码
1个intent只能包含一个action,但可有多个category
Intent intent = new Intent();
intent.setAction("action is a string. com.chapter1")
startActivity(intent);
// 具体启动那个Activity由<intent-filter.../>配置
<activity android:name=".EmptyActivity" android:label="empty activity" android:exported="true">
    <intent-filter>
        表示该Activity响应 intent.action==xxx 的intent
        <action android:name="android.intent.action.YYYYY" /> 
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

Intent代表了启动某个程序组件的"意图",它不仅能启动本应用内的组件也可启动Android系统的其他应用的程序组件,包括系统自带的程序组件(只要权限允许)

返回HOME桌面

java 复制代码
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);

Data, Type 属性

Data属性用于向Action属性提供操作的数据.Data属性接受一个Uri对象

Uri字符串格式: scheme://host:port/path

Type属性用于指定该Data属性所制定Uri对应的MIME类型 abc/xyz

java 复制代码
intent.setData(Uri.parse("lee://www.abc:8888/test"));
intent.setType("abc/xyz");
intent.setDataAndType(Uri.parse("lee://www.abc:8888/test"), "abc/xyz");
xml 复制代码
<data android:mimeType=""
    android:scheme=""
    android:host=""
    android:port=""
    android:path=""
    android:pathPrefix=""
    android:pathPattern=""/>
实例:使用Action, Data属性启动系统Activity

一旦为Intent同时指定了Action属性,Data属性, Android就可根据指定的数据类型来启动特定的应用程序,并对制定数据执行相应的操作.

  • ACTION_VIEW content://com.android.contacts/contacts/1 : 显示标识为1的联系人的信息
  • ACTION_EDIT content://com.android.contacts/contacts/1 : 编辑标识为1的联系人的信息
  • ACTION_DIAL content://com.android.contacts/contacts/1 : 显示想标识为1的联系人拨号的界面
  • ACTION_VIEW tel:123 :显示向指定号码123拨号的界面
  • ACTION_DIAL tel:123 :显示向制定号码123拨号的界面
  • ACTION_VIEW content://contacts/people/ :显示所有联系人列表的信息
java 复制代码
detailIntent = new Intent();
detailIntent.setAction(Intent.ACTION_VIEW);
detailIntent.setData(Uri.parse("http://www.bing.com"));

detailIntent = new Intent();
detailIntent.setAction(Intent.ACTION_EDIT);
detailIntent.setData(Uri.parse("content://com.android.contacts/contacts/1"));

detailIntent = new Intent();
detailIntent.setAction(Intent.ACTION_DIAL);
detailIntent.setData(Uri.parse("tel:138000000"));

Extra 属性

用于在多个Action之间进行数据交换,应该是一个 Bundle 对象

Flag 属性

6 Android 应用资源

  • 界面布局文件:xml文件
  • 程序源文件:应用中的Activity, Service, BroadcastReceiver, ContentProvider四大组件
  • 资源文件:各种xml,包括png,jpj.gif等

将代码中用到的常量集中/统一存放在类/接口中,实现一定的解耦,但是仍可提高.Android允许把应用中用到的各种资源,如字符串,谈色,数组,菜单等都集中存放到/res/目录中定义,应用则直接使用这些资源中定义的值. assets目录下的资源代表应用无法直接访问,须通过AssetManager获取;/res/下的资源,androidSDK 会在编译时自动在R.java文件中为这些资源创建索引,程序可直接通过R资源清单类进行访问.

6.1 应用资源

  1. 在源程序中使用资源清单项

    [<package_name>.]R.<resource_type>.<resource_name>

    java 复制代码
    // 从drawable资源中加载图片,并设为该窗口的背景
    window.setBackgroundDrawableResource(R.drawable.back);
    // 从string资源中获取制定字符串资源,并设置该窗口的标题
    window.setTitle(resources.getText(R.string.main_title));
    // 获取制定的TextView组件,并设置该组件显示string资源中的指定字符串资源
    TextView msg = findViewById(R.id.msg);
    msg.setText(R.string.hello_message);
  2. 在源代码中访问实际资源

    R资源清单类的项只是一个int值,不是实际的资源对象,若想获取实际资源对象需通过Resources类他提哦那个了两类方法:

    • getXxx(int id);
    • getAssets();
    java 复制代码
    // 直接调用Activity的getResources()获取Resources对象
    Resources res = getResources();
    // 获取字符串资源
    String mainTitle = res.getText(R.string.main_title);
    // 获取drawable资源
    Drawable logo = res.getDrawable(R.drawable.logo);
    // 获取数组资源
    int[] arr = res.getIntArray(R.array.books);
  3. 在XML文件中使用资源

    @[<package_name:>]<resource_type>/<resource_name>

5.2 定义字符串 颜色 尺寸资源文件 数组

这些资源都位于/res/values/目录下

strings.xml

xml 复制代码
<resources>
    <string name="app_name">LaoliClock</string>
    <string name="title_activity_main">MainActivityxx</string>
    <string name="button_normal">normal</string>
    <string name="button_shrink">shrink</string>
    <string name="button_stretch">stretch</string>
</resources>

colors.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="red">#f00</color>
    <color name="green">#0f0</color>
    <color name="blue">#00f</color>
    <color name="yellow">#ff0</color>
    <color name="pink">#f0f</color>
    <color name="teal">#0ff</color>
    <color name="grey">#888</color>
</resources>

dimens.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<dimen name="spacing">8dp</dimen>
	<!-- 定义GridView组件中每个单元格的宽度、高度 -->
	<dimen name="cell_width">60dp</dimen>
	<dimen name="cell_height">66dp</dimen>
	<!-- 定义主程序标题的字体大小 -->
	<dimen name="title_font_size">18sp</dimen>
</resources>

integer

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<integer name="my_size">32</integer>
    <integer name="book_numbers">12</integer>
</resources>
[<package_name>.]R.integer.integer_name

@[<package_name>:]integer/integer_name

Resources res = getResources();
int mySize = res.getInterger(R.integer.my_size);

arrays.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<!-- 定义一个Drawable数组 -->
	<array name="plain_arr">
		<item>@color/c1</item>
		<item>@color/c2</item>
		<item>@color/c3</item>

	</array>
	<!-- 定义字符串数组 -->
	<string-array name="string_arr">
		<item>@string/c1</item>
		<item>@string/c2</item>
		<item>@string/c3</item>
	
	</string-array>
	<!-- 定义字符串数组 -->
	<string-array name="books">
		<item>Java</item>
		<item>前端开发</item>
		<item>Android</item>
	</string-array>
</resources>
java 复制代码
String[] texts = getResources().getStringArray(R.array.string_arr);
TypedArray icons = getResources().obtainTypedArray(R.array.plain_arr);

6.4 Drawable资源

该资源可以是png,jgp,gif,xml. 保存在/res/drawable/目录下 /res/drawable-ldpi/, /res/drawable-mdpi/ , /res/drawable-hdpi/ , /res/drawable-xhdpi/

java 复制代码
[<package_name>.]R.drawable.<file_name>
@[<package_name>:]drawable/file_name

getDrawable(int id);

6.4.2 StateListDrawable资源

高亮显示正在输入的文本框

my_image.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
	<!-- 指定获得焦点时的颜色 -->
	<item android:state_focused="true"
		android:color="#f44"/>
	<!-- 指定失去焦点时的颜色 -->
	<item android:state_focused="false"
		android:color="#ccf"/>
</selector>

定义能改变textcolor的文本框

xml 复制代码
<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    android:textColor="@drawable/my_image"/>

通过使用StateListDrawable不仅可以让文本框的文字颜色岁文本框状态的改变而切换,也可让按钮的北京前景随状态的改变而切换. StateListDrawable的功能非常灵活,可让各种组件的背景前景随状态的改变而切换

6.4.3 LayerDrawable 资源

定制拖动条的外观

drawable/my_bar.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background"
        android:drawable="@drawable/grow"/>
    <item android:id="@android:id/progress"
        android:drawable="@drawable/ok"/>
</layer-list>

drawable/layer_logo.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <bitmap android:gravity="center" android:src="@drawable/ic_logo"/>
    </item>
    <item android:left="40dp" android:top="40dp">
        <bitmap android:gravity="center" android:src="@drawable/ic_logo"/>
    </item>
    <item android:left="80dp" android:top="80dp">
        <bitmap android:gravity="center" android:src="@drawable/ic_logo"/>
    </item>
</layer-list>

layout/activit_main.xml

xml 复制代码
<?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:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    android:divider="?android:attr/dividerHorizontal"
    android:orientation="vertical"
    android:showDividers="middle">
    <!-- 添加一个拖动条 -->
    <SeekBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progressDrawable="@drawable/my_bar"/>
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/layer_logo"/>
</LinearLayout>

6.4.6 ShapeDrawable资源

drawable/my_shape_1.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:shape="rectangle">
	<!-- 设置填充颜色 -->
	<solid android:color="#fff"/>
	<!-- 设置四周的内边距 -->
	<padding android:left="7dp"
		android:top="7dp"
		android:right="7dp"
		android:bottom="7dp" />
	<!-- 设置边框 -->
	<stroke android:width="3dip" android:color="#ff0" />
</shape>

drawable/my_shape_2.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:shape="rectangle">
	<!-- 定义填充渐变颜色 -->
	<gradient
		android:startColor="#FFFF0000"
		android:endColor="#80FF00FF"
		android:angle="45"/>
	<!-- 设置内填充 -->
	<padding android:left="7dp"
		android:top="7dp"
		android:right="7dp"
		android:bottom="7dp" />
	<!-- 设置圆角矩形 -->
	<corners android:radius="8dp" />
</shape>

drawable/my_shape_3.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:shape="oval">
	<!-- 定义填充渐变颜色 -->
	<gradient
		android:startColor="#ff0"
		android:endColor="#00f"
		android:angle="45"
		android:type="sweep"/>
	<!-- 设置内填充 -->
	<padding android:left="7dp"
		android:top="7dp"
		android:right="7dp"
		android:bottom="7dp" />
	<!-- 设置圆角矩形 -->
	<corners android:radius="8dp" />
</shape>

6.4.5 ClipDrawable 资源

图片进度条

layout/activity_main.xml

xml 复制代码
<?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">
	<ImageView
		android:id="@+id/image"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:scaleType="fitStart"
		android:src="@drawable/my_clip" />
</LinearLayout>

drawable/my_clip.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:drawable="@drawable/background"
    android:gravity="center">
</clip>
java 复制代码
public class MainActivity extends Activity{
	@Override protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ImageView imageView = findViewById(R.id.image);
		// 获取图片所显示的ClipDrawable对象
		final ClipDrawable drawable = (ClipDrawable) imageView.getDrawable();
		class MyHandler extends Handler {
			@Override public void handleMessage(Message msg) {
				// 如果该消息是本程序所发送的
				if (msg.what == 0x1233) {
					// 修改ClipDrawable的level值
					drawable.setLevel(drawable.getLevel() + 200);
				}
			}
		}
		final Handler handler = new MyHandler();
		final Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override public void run() {
				Message msg = new Message();
				msg.what = 0x1233;
				// 发送消息,通知应用修改ClipDrawable对象的level值
				handler.sendMessage(msg);
				// 取消定时器
				if (drawable.getLevel() >= 10000) {
					timer.cancel();
				}
			}
		}, 0, 300);
	}
}

6.4.6 AnimationDrawable资源

6.5 属性动画资源 Property Animation

应用的初始化配置信息推荐使用xml保存,放在/res/xml/下

6.9 样式和主题 style theme

用于美化应用. 存放在/res/values/下

定义样式:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<resources>
	<!-- AS创建项目时原有的主题 -->
	<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
	</style>
	<!-- 定义一个样式,指定字体大小、字体颜色 -->
	<style name="style1">
		<item name="android:textSize">20sp</item>
		<item name="android:textColor">#00d</item>
	</style>
	<!-- 定义一个样式,继承前一个颜色 -->
	<style name="style2" parent="@style/style1">
		<item name="android:background">#ee6</item>
		<item name="android:padding">8dp</item>
		<!-- 覆盖父样式中指定的属性 -->
		<item name="android:textColor">#000</item>
	</style>
	<style name="CrazyTheme">
		<item name="android:windowNoTitle">true</item>
		<item name="android:windowFullscreen">true</item>
		<item name="android:windowFrame">@drawable/window_border</item>
		<item name="android:windowBackground">@drawable/star</item>
	</style>
</resources>

使用样式

xml 复制代码
<?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">
	<!-- 指定使用style1的样式 -->
	<EditText
		style="@style/style1"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:text="@string/style1" />
	<!-- 指定使用style2的样式 -->
	<EditText
		style="@style/style2"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:text="@string/style2" />
</LinearLayout>

主题与样式的区别:

  • 主题不能作用于单个的View组件,主题应该对整个应用中的所有Activity起作用,或对指定的Activity起作用
  • 主题定义的格式应该是改变窗口外观的格式,例如窗口标题,窗口边框等.

给所有的窗口添加边框,背景

/res/values/my_style.xml

xml 复制代码
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="TestTheme">
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowFullscreen">true</item>
    <item name="android:windowFrame">@drawable/window_border</item>
    <item name="android:windowBackground">@drawable/a_picture</item>
</style>
</resources>

window_border.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
	android:shape="rectangle">
	<!-- 设置填充颜色 -->
	<solid android:color="#0fff" />
	<!-- 设置四周的内边距 -->
	<padding android:bottom="7dp"
		android:left="7dp"
		android:right="7dp"
		android:top="7dp" />
	<!-- 设置边框 -->
	<stroke android:width="10dp"
		android:color="#f00" />
</shape>

使用:

1. manifest文件:<application android:theme="@style/TestTheme"
<activity android:theme="@style/TestTheme"

2. 代码中Activity的方法 setTheme(R.style.TestTheme);

安卓内定主题:@style/Theme.xxx

6.10 属性资源

如果用户开发的自定义View组件也需要指定属性,就需要属性资源的帮助了.

6.11 使用原始资源

类似于声音文件及其它各种类型的文件,只要android没有为之提供专门的支持,这种资源都被成为原始资源. Android的原始资源可放在如下两个地方:

  • /res/raw/,Android SDK会处理该目录下的原始资源,AndroidSDK会在R清单类中为该目录下的资源生成一个索引项.
  • 位于/assets/目录下,该目录下的资源是更彻底的原始资源. Android应用需要通过AssetManager来管理该目录下的原始资源.
java 复制代码
public class MainActivity extends Activity {
    private MediaPlayer player1, player2;
    @Override protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        player1 = MediaPlayer.create(this, R.raw.bomb);
        AssetManager am = getAssets();
        try{
            AssetFileDescriptor afd = am.openFd("shot.mp3");
            player2 = new MediaPlayer();
            player2.setDataSource(afd.getFileDescriptor());
            player2.prepare();
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        Button b1 = findViewById(R.id.button3);
        b1.setOnClickListener(view -> {
            player1.start();
        });
        Button b2 = findViewById(R.id.button5);
        b2.setOnClickListener(view -> player2.start());
    }
}

6.12 国际化资源

6.13 适应不同屏幕的资源

xxx

9 使用ContentProvider实现数据共享

10 Service和BroadcastReceiver

10.1 Service

Service组件也是可执行的程序,他也有自己的生命周期.创建,配置Service与创建,配置Activity的过程基本相似.

java 复制代码
public class FirstService extends Service {
    @Override
    public IBinder onBind(Intent intent)
    {
        //bindService时调用
        return null;
    }
    @Override
    public void onCreate()
    {
        super.onCreate();
        System.out.println("Service is Created");
        // 第一次启动时调用
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        System.out.println("Service is Started");
        return START_STICKY;
        // 每次调用 startService 时调用
    }
    @Override
    public void onDestroy()
    {
        super.onDestroy();
        System.out.println("Service is Destroyed");
    }
}

// 启动一个服务. 方法1
bn1.setOnClickListener(view -> {startService(intent);});
// stopService(intent)

// 启动一个服务. 方法2
        bn1.setOnClickListener(view -> {
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
            });
        bn3.setOnClickListener(view -> {
            unbindService(conn);
        });
        bn2.setOnClickListener(view -> {
            Toast.makeText(this, "Service count: "+binder.getCount(), Toast.LENGTH_SHORT).show();
        });
    private FirstService.MyBinder binder;
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.d(TAG, "MainActivity. onServiceConnected");
            binder = (FirstService.MyBinder)iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.d(TAG, "MainActivity onServiceDisconnected");
        }
    };
    ------------------------
    private int count;
    private MyBinder binder = new MyBinder();
    @Override
    public IBinder onBind(Intent intent)
    {
        return binder;
    }
    @Override
    public boolean onUnbind(Intent intent)
    {
        return true;
    }
    class MyBinder extends Binder
    {
        public int getCount() {
            return FirstService.this.count;
        }
    }
  • 通过Contenxt的startService()方法启动Service,访问者与Service之间没有关联,即使访问者退出了,Service也仍然运行
  • 通过Context的bindService()方法:访问者与之绑定在一起,访问者退出Service也退出

10.1.5 IntentService

@Deprecated

  • Service 不会专门启动一个单独的进程,Service与它所在应用位于同一个进程中.
  • Service 不是一条新的线程,因此不应该在Service中直接处理耗时任务
  • IntentService会创建单独的worker线程来处理所有的Intent请求.
  • IntentService会创建单独的worker线程来处理onHandleIntent()方法实现的代码,
  • 当所有请求处理完后,IntentService会自动停止
  • IntentService实现,只需重写onHandleIntent()方法即可

10.2 跨进程调用 Service(AIDL Service)

Android 需要AIDL(Android Interface Definition Language, Android接口定义语言)来定义远程接口.

先定义一个接口,然后为该接口提供一个实现类即可

使用方法:

  1. 定义.aidl文件
    在main目录上鼠标右键new->AILD(需要先在build.gradle中添加 android.buildFeatures.aidl 为true)

  2. 在IMyAidlInterface.aidl中添加接口文件

    java 复制代码
    package com.example.chapter1noactivity;
    interface IMyAidlInterface {
        String getColor();
        double getWeight();
    }
  3. 新建一个Service并将其添加入manifest文件中

Android系统本身提供了常见的远程服务

TelephonyManager是一个管理手机通话状态,电话网络信息的服务类,该类提供了大量的getXxx()方法获取电话网络的相关信息.

java 复制代码
TelephonyManager tManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

14 管理Android系统桌面

  • setBitmap(Bitmap bitmap): 将壁纸设置为bitmap所代表的位图
  • setResource(int resid): 将壁纸设置为resid资源所代表的图片
  • setStream(InputStream data): 将壁纸设置为data数据所代表的图片

14.1 动态壁纸 Live Wallpapers

动态壁纸的动画由程序实时绘制

  1. 开发一个子类继承WallpaperService基类
  2. 集成WallpaperService积累时必须重写onCreateEngine()方法,该方法返回WallpaperService.Engine子类对象
  3. 开发者需要实现WallpaperService.Engine子类,并重写其中的onVisibilityChanged(boolean visible), onOffsetsChanged()方法.

蜿蜒壁纸

xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <com.example.chapter1noactivity.draw.DrawView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:id="@+id/root_layout"
        android:layout_width="409dp"
        android:layout_height="736dp"
        android:layout_marginTop="4dp"
        android:orientation="vertical"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="MissingConstraints"
        tools:layout_editor_absoluteX="1dp">

        <TextView
            android:id="@+id/textView"
            android:layout_width="190dp"
            android:layout_height="52dp"
            android:layout_marginStart="116dp"
            android:layout_marginTop="236dp"
            android:text="" />

        <Space
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="144dp"
            android:layout_marginTop="28dp"
            android:text="Button Me" />


        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </FrameLayout>

    </LinearLayout>

    <TableLayout
        android:id="@+id/TableLayout01"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:shrinkColumns="1"
        android:stretchColumns="2">
        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name" />
        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/button3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_normal" />
            <Button
                android:id="@+id/button4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_shrink" />
            <Button
                android:id="@+id/button5"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_stretch" />
        </TableRow>
    </TableLayout>

    <TableLayout
        android:id="@+id/TableLayout02"
        android:layout_width="409dp"
        android:layout_height="385dp"
        android:collapseColumns="1,2"
        app:layout_constraintBottom_toBottomOf="parent"
        tools:ignore="MissingConstraints">

        <Button
            android:id="@+id/button6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name" />

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:id="@+id/button7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_normal" />

            <Button
                android:id="@+id/button8"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_shrink" />

            <Button
                android:id="@+id/button9"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_stretch" />
        </TableRow>
    </TableLayout>
    <TableLayout
        android:id="@+id/TableLayout03"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        android:stretchColumns="1,2">
        <Button
            android:id="@+id/button10"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/app_name" />
        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/button11"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_normal" />
            <Button
                android:id="@+id/button12"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_shrink" />
            <Button
                android:id="@+id/button13"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="333ff" />
        </TableRow>
        <TableRow>
            <Button
                android:id="@+id/button14"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/button_normal" />
            <Button
                android:id="@+id/button15"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="xxxxxxxxxxxxxxx" />
        </TableRow>
    </TableLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

java

MainActivity.java

java 复制代码
package com.example.chapter1noactivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

//import androidx.activity.compose.setContent;
//import androidx.activity.enableEdgeToEdge;
//import androidx.compose.foundation.layout.fillMaxSize;
//import androidx.compose.foundation.layout.padding;
//import androidx.compose.material3.Scaffold;
//import androidx.compose.material3.Text;
import androidx.appcompat.app.AppCompatActivity;
//import com.example.chapter1noactivity.ui.theme.Chapter1NoActivityTheme;

//import android.widget.


//public class MainActivity extends AppCompatActivity {
//    private int clickNum = 0;
//
//    @Override
//    public void onCreate(Bundle saveInstanceState) {
//        super.onCreate(saveInstanceState);
//        setContentView(R.layout.activity_main);
//
//        TextView tv = findViewById(R.id.textView);
//        tv.setText("hello android - [" + clickNum + "] " + new java.util.Date());
//
//
//        Button myButton = (Button) findViewById(R.id.button);
//        myButton.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                clickNum++;
//                tv.setText("hello android - [" + clickNum + "] " + new java.util.Date());
//            }
//        });
//    }
//
//
//    public void clickHandler(View source) {
//        TextView tv = findViewById(R.id.button);
//        clickNum++;
//        tv.setText("hello android - [" + clickNum + "] " + new java.util.Date());
//
//    }
//}

public class MainActivity extends AppCompatActivity {
    private int clickNum = 0;
    private int[] imageArr = new int [] {
            R.drawable.ic_launcher_background, R.drawable.ic_launcher_foreground
    };
    private int currentImg = 0;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        LinearLayout main = new LinearLayout(this);
        setContentView(R.layout.activity_main);
        LinearLayout main = findViewById(R.id.root_layout);
        ImageView image = new ImageView(this);
        main.addView(image);
        image.setImageResource(imageArr[0]);
        image.setOnClickListener(view -> { image.setImageResource(imageArr[++currentImg % imageArr.length]); });

        Button myButton = (Button) findViewById(R.id.button);
        TextView tv = findViewById(R.id.textView);
        myButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clickNum++;
                tv.setText("hello android - [" + clickNum + "] " + new java.util.Date());
            }
        });
    }
}

// 绘制跟随手指移动的小球
public class MainActivity extends AppCompatActivity {


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

        // 可将下面的绘制小球放入xml中,实现代码和layout解耦
        // <com  />
        LinearLayout main = findViewById(R.id.root_layout);
        DrawView draw = new DrawView(this);
        draw.setMinimumWidth(300);
        draw.setMinimumHeight(500);
        main.addView(draw);

    }
}

DrawView.java

java 复制代码
package com.example.chapter1noactivity.draw;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class DrawView extends View {
    private float currentX = 40f;
    private float currentY = 50f;
    // 创建并定义画笔
    private final Paint p = new Paint();

    public DrawView(Context context) {
        super(context);
    }

    public DrawView(Context context, AttributeSet set) {
        super(context, set);
    }

    // 当该组件将要绘制它的内容时触发
    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        p.setColor(Color.RED);
        canvas.drawCircle(currentX, currentY, 15F, p);
    }

    // 为该组件的touch事件重写事件处理方法
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 获取触点位置并赋值
        currentX = event.getX();
        currentY = event.getY();
        // 通知组件重绘自己
        invalidate();
        // 返回true表明该处理方法已经处理该事件
        return true;
    }
}
相关推荐
ADFVBM几秒前
Spring Boot拦截器(Interceptor)详解
java·spring boot·后端
故事与他6455 分钟前
upload-labs-master通关攻略(13~16)
java·服务器·前端·安全·网络安全
Cache技术分享6 分钟前
17. Java 复制数组
java·前端
Lx3527 分钟前
《从头开始学java,一天一个知识点》之:输入与输出:Scanner与System类
java·后端
Andy.Zeng10 分钟前
《Android应用性能优化全解析:常见问题与解决方案》
android·性能优化
南山不太冷16 分钟前
Spring(3)—— 获取http头部信息
java·spring·http
码农研究僧18 分钟前
深入浅出Bearer Token:解析工作原理及其在Vue、Uni-app与Java中的实现Demo
java·vue.js·uni-app
kfepiza21 分钟前
android用java设置button之间的间距 笔记250311
android·java·前端
liujingtech22 分钟前
拒绝重复进程!Android开发者必须掌握的单实例设计全攻略
android
XT462523 分钟前
opencv 图片颜色+轮廓识别
java·opencv