当前位置: 首页 > news >正文

疯狂安卓入门,crayandroid

系列文章目录


文章目录

  • 系列文章目录
  • 第一组 ViewGroup 为基类
    • 帧布局
    • 约束布局
  • 第二组 TextView 及其子类
    • button
    • 时钟 AnalogClock 和 TextClock
    • 计时器
  • 第三组 ImageView 及其子类
  • 第四组 AdapterView 及其子类
    • AutoCompleteTextView 的功能和用法
    • ExapndaleListView
    • AdapterViewFlipper
    • RecyclerView 组件
  • 第五组UI ProgressBar及其子类
      • SeekBar
      • RatingBar
  • 第六组 ViewAnimator
  • 第七组UI对话框
  • android事件机制
    • 基于监听的事件处理
    • 基于回调的事件处理
    • 响应系统设置
      • Configuration类
    • 3.5 Handler消息传递机制
      • 3.5.1 Handler 类
      • 3.5.2 Handler, Loop, MessageQueue的工作原理
  • 4 Activity & Fragment
      • 包含多个Activity的Manifest
      • Activity的启动和关闭
      • 使用Bundle在Activity之间交换数据
    • 4.3 Activity生命周期
    • 4. android:launchMode=
      • 4.4.1 standard 模式 (默认模式)
      • 4.4.2 singleTop 模式
      • 4.4.3 singleTask 模式
      • 4.4.4 singleInstance 模式
    • 4.5 Fragment
      • 4.5.3 Fragment与Activity通讯
      • 4.5.4 Fragment管理与Fragment事务
  • chapter 5 Intent, IntentFilter
    • 5.1 Intent对象
    • 5.2 Intent属性及 intent-filter 配置
      • Compoent 属性
      • Action, Category属性
      • Data, Type 属性
        • 实例:使用Action, Data属性启动系统Activity
      • Extra 属性
      • Flag 属性
  • 6 Android 应用资源
    • 6.1 应用资源
    • 5.2 定义字符串 颜色 尺寸资源文件 数组
    • 6.4 Drawable资源
      • 6.4.2 StateListDrawable资源
      • 6.4.3 LayerDrawable 资源
      • 6.4.6 ShapeDrawable资源
      • 6.4.5 ClipDrawable 资源
      • 6.4.6 AnimationDrawable资源
    • 6.5 属性动画资源 Property Animation
    • 6.6 使用原始XML资源; Layout资源; Menu资源
    • 6.9 样式和主题 style theme
    • 6.10 属性资源
    • 6.11 使用原始资源
    • 6.12 国际化资源
    • 6.13 适应不同屏幕的资源
  • xxx
  • 9 使用ContentProvider实现数据共享
  • 10 Service和BroadcastReceiver
    • 10.1 Service
      • 10.1.5 IntentService
    • 10.2 跨进程调用 Service(AIDL Service)
  • 14 管理Android系统桌面
    • 14.1 动态壁纸 Live Wallpapers
  • xml
  • java



第一组 ViewGroup 为基类

ViewGroup继承自View类

View <- ViewGroup <- LinearLayout <- TableLayout

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

帧布局

ViewGroup <- FrameLayout

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};@Overridepublic 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));@Overridepublic 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() {@Overridepublic 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 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"><LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="fuck java"android:textSize="20pt"android:drawableEnd="@mipmap/ic_launcher_round"/><TextViewandroid: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"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="email xx@192.com"android:singleLine="true"android:autoLink="email|phone"/><TextViewandroid: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"/><CheckedTextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="checked text"android:textSize="20pt"android:checkMark="@drawable/ok"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="bounding text"android:textSize="24pt"android:background="@drawable/bg_border1"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="round bg"android:textSize="24pt"android:background="@drawable/bg_border2"/></LinearLayout><Buttonandroid: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" /><Buttonandroid: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" /><ImageButtonandroid: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" /><Buttonandroid: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

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};@Overridepublic 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 version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><ImageViewandroid:id="@+id/header"android:layout_width="100dp"android:layout_height="100dp"android:paddingLeft="10dp"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingLeft="10dp"android:textColor="#f0f"android:textSize="20dp"/><TextViewandroid:id="@+id/desc"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingLeft="10dp"android:textSize="14dp"/></LinearLayout></LinearLayout>
<?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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ListViewandroid: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

叠在一起的图片

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;@Overridepublic 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 version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><StackViewandroid:id="@+id/mStackView"android:layout_width="match_parent"android:layout_height="wrap_content"android:loopViews="false"/><LinearLayoutandroid:layout_width="226dp"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/button3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:onClick="prevfff"android:text="shangyige" /><Buttonandroid: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 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

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<>();@Overridepublic 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>() {// 创建列表项组件的方法,使用该方法所创建的组件会被自动缓存@Overridepublic PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);return new PersonViewHolder(view, this);}// 为列表项组件绑定数据的方法,每次组件重新显示出来时都会重新执行该方法@Overridepublic void onBindViewHolder(PersonViewHolder viewHolder, int i) {viewHolder.nameTv.setText(names[i]);viewHolder.descTv.setText(descs[i]);viewHolder.headerIv.setImageResource(imageids[i]);}// 该方法的返回值决定包含多少个列表项@Overridepublic 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 animationadapter.notifyItemRemoved(position);// rm data from basic modelMainActivity.this.personList.remove(position);// notify recyclerview exec rmadapter.notifyItemRangeChanged(position, adapter.getItemCount());return false;});}}public void prevfff(View v) {sv.showPrevious();}public void nextfff(View v) {sv.showNext();}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><androidx.recyclerview.widget.RecyclerViewandroid: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 version="1.0" encoding="utf-8"?><LinearLayoutxmlns: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"><ImageViewandroid:id="@+id/header"android:layout_width="100dp"android:layout_height="100dp"android:paddingLeft="10dp"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:paddingLeft="10dp"android:textColor="#f0f"android:textSize="20dp"/><TextViewandroid: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

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;}@Overridepublic  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));@Overridepublic 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

拖动滑块改变图片透明度

    @Overridepublic 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

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() {@Overridepublic int getCount() {if (screenNo == screenCount-1 && items.size() % NUMBER_PER_SCREEN != 0) {return items.size() % NUMBER_PER_SCREEN;} else {return NUMBER_PER_SCREEN;}}@Overridepublic DataItem getItem(int i) {return items.get(screenNo * NUMBER_PER_SCREEN + i);}// 当点击当前页面的item是该函数会被调用,i为item在grid的idx@Overridepublic long getItemId(int i) {return i;}// 当需要显示画面时,该函数会被自动调用,调用每个item调用一次,调用次数与getCount函数有关@Overridepublic 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;}}@Overridepublic 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

public class MainActivity extends AppCompatActivity {@Overridepublic 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 infoToast 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事件机制

基于监听的事件处理

内部类作为事件监听器

// 2. 事件监听器
class MyClickListener implements View.onClickListener {// 事件处理函数@Overridepublic 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 本身作为事件监听器

public class MainActivity extends Activity implements View.OnClickListener{@Overridepublic void onCreate(xxx){}xxx@Overridepublic void onClick(View v){show.setText("bn button!");}
}

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

bn.setOnClickListener(view -> show.setText("bn button"));

直接绑定到标签

<Buttonandroid: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)

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

响应系统设置

Configuration类

// Activity的方法
Configuration cfg = getResources().getConfiguration();

3.5 Handler消息传递机制

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

3.5.1 Handler 类

  1. 在新启动的线程中发送消息
  2. 在主线程中获取\处理消息
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)
}
    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;}@Overridepublic void handleMessage(Message msg) {if (msg.what == 0x1233) {activity.get().show.setImageResource(imgs[currid++ % imgs.length]);}}}MyHandler myHandler = new MyHandler(new WeakReference(this));@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);show = findViewById(R.id.imageView);new Timer().schedule(new TimerTask() {@Overridepublic 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

       <activityandroid: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
        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…

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);@Overridepublic 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|ᐯ销毁状态
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中

    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 模式

<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

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对象

 <fragmentandroid:id="@+id/book_list"android:name="com.example.chapter1noactivity.BookListFragment"android:layout_width="100dp"android:layout_height="match_parent"android:layout_weight="1" />
    // 实现Callbacks接口必须实现的方法@Overridepublic 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容器当前显示的FragmentgetSupportFragmentManager().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()注册一个监听器,用于监听后台栈的变化
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封装了程序想要启动程序的意图和通讯信息

类型启动方法
ActivitystartActivity(Intent);
startActivityForResult(Intent, int);
ServiceComponentName startService(Intent);
boolean bindService(Intent, ServiceConnection conn, int flags);
BroadcastReceiversendBroadcast(Intent);
sendBroadcast(Intent, String);
sendOrderedBroadcast(Intent, String);

5.2 Intent属性及 intent-filter 配置

Compoent 属性

为Intent指定了Component属性

@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

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…/>配置.

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桌面

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

intent.setData(Uri.parse("lee://www.abc:8888/test"));
intent.setType("abc/xyz");
intent.setDataAndType(Uri.parse("lee://www.abc:8888/test"), "abc/xyz");
<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/ :显示所有联系人列表的信息
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>
    // 从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();
    // 直接调用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

<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 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 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 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_nameResources res = getResources();
int mySize = res.getInterger(R.integer.my_size);

arrays.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>
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/

[<package_name>.]R.drawable.<file_name>
@[<package_name>:]drawable/file_namegetDrawable(int id);

6.4.2 StateListDrawable资源

高亮显示正在输入的文本框
my_image.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的文本框

<EditTextandroid: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 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 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 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"><!-- 添加一个拖动条 --><SeekBarandroid:layout_width="match_parent"android:layout_height="wrap_content"android:max="100"android:progressDrawable="@drawable/my_bar"/><ImageViewandroid: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 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 version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><!-- 定义填充渐变颜色 --><gradientandroid: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 version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="oval"><!-- 定义填充渐变颜色 --><gradientandroid: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 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"><ImageViewandroid: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 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>
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

6.6 使用原始XML资源; Layout资源; Menu资源

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

6.9 样式和主题 style theme

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

定义样式:

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

<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 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来管理该目录下的原始资源.
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的过程基本相似.

public class FirstService extends Service {@Overridepublic IBinder onBind(Intent intent){//bindService时调用return null;}@Overridepublic void onCreate(){super.onCreate();System.out.println("Service is Created");// 第一次启动时调用}@Overridepublic int onStartCommand(Intent intent, int flags, int startId){System.out.println("Service is Started");return START_STICKY;// 每次调用 startService 时调用}@Overridepublic void onDestroy(){super.onDestroy();System.out.println("Service is Destroyed");}
}// 启动一个服务. 方法1
bn1.setOnClickListener(view -> {startService(intent);});
// stopService(intent)// 启动一个服务. 方法2bn1.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() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {Log.d(TAG, "MainActivity. onServiceConnected");binder = (FirstService.MyBinder)iBinder;}@Overridepublic void onServiceDisconnected(ComponentName componentName) {Log.d(TAG, "MainActivity onServiceDisconnected");}};------------------------private int count;private MyBinder binder = new MyBinder();@Overridepublic IBinder onBind(Intent intent){return binder;}@Overridepublic 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中添加接口文件
    package com.example.chapter1noactivity;
    interface IMyAidlInterface {String getColor();double getWeight();
    }
    
  3. 新建一个Service并将其添加入manifest文件中

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

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

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 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.DrawViewandroid:layout_width="match_parent"android:layout_height="match_parent" /><LinearLayoutandroid: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"><TextViewandroid:id="@+id/textView"android:layout_width="190dp"android:layout_height="52dp"android:layout_marginStart="116dp"android:layout_marginTop="236dp"android:text="" /><Spaceandroid:layout_width="wrap_content"android:layout_height="wrap_content" /><Buttonandroid: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" /><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"></FrameLayout></LinearLayout><TableLayoutandroid:id="@+id/TableLayout01"android:layout_width="match_parent"android:layout_height="match_parent"app:layout_constraintBottom_toBottomOf="parent"android:shrinkColumns="1"android:stretchColumns="2"><Buttonandroid:id="@+id/button2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/app_name" /><TableRowandroid:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_normal" /><Buttonandroid:id="@+id/button4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_shrink" /><Buttonandroid:id="@+id/button5"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_stretch" /></TableRow></TableLayout><TableLayoutandroid:id="@+id/TableLayout02"android:layout_width="409dp"android:layout_height="385dp"android:collapseColumns="1,2"app:layout_constraintBottom_toBottomOf="parent"tools:ignore="MissingConstraints"><Buttonandroid:id="@+id/button6"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/app_name" /><TableRowandroid:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button7"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_normal" /><Buttonandroid:id="@+id/button8"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_shrink" /><Buttonandroid:id="@+id/button9"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_stretch" /></TableRow></TableLayout><TableLayoutandroid:id="@+id/TableLayout03"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"android:stretchColumns="1,2"><Buttonandroid:id="@+id/button10"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/app_name" /><TableRowandroid:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button11"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_normal" /><Buttonandroid:id="@+id/button12"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_shrink" /><Buttonandroid:id="@+id/button13"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="333ff" /></TableRow><TableRow><Buttonandroid:id="@+id/button14"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button_normal" /><Buttonandroid: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

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;@Overridepublic 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() {@Overridepublic void onClick(View v) {clickNum++;tv.setText("hello android - [" + clickNum + "] " + new java.util.Date());}});}
}// 绘制跟随手指移动的小球
public class MainActivity extends AppCompatActivity {@Overridepublic 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

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);}// 当该组件将要绘制它的内容时触发@Overridepublic void onDraw(Canvas canvas) {super.onDraw(canvas);p.setColor(Color.RED);canvas.drawCircle(currentX, currentY, 15F, p);}// 为该组件的touch事件重写事件处理方法@Overridepublic boolean onTouchEvent(MotionEvent event) {// 获取触点位置并赋值currentX = event.getX();currentY = event.getY();// 通知组件重绘自己invalidate();// 返回true表明该处理方法已经处理该事件return true;}
}

相关文章:

疯狂安卓入门,crayandroid

系列文章目录 文章目录 系列文章目录第一组 ViewGroup 为基类帧布局约束布局 第二组 TextView 及其子类button时钟 AnalogClock 和 TextClock计时器 第三组 ImageView 及其子类第四组 AdapterView 及其子类AutoCompleteTextView 的功能和用法ExapndaleListViewAdapterViewFlipp…...

SQL Server查询计划操作符(7.3)——查询计划相关操作符(10)

7.3. 查询计划相关操作符 88&#xff09;Sequence Project&#xff1a;该操作符通过对一个排序集合增加字段来进行计算。其基于一个或多个字段的值将其输入的数据行分成多个段&#xff0c;这样&#xff0c;该操作符每次输出一个段&#xff0c;这些字段显示为该操作符的参数。该…...

【Matlab仿真】如何解决三相交流信号源输出波形失真问题?

问题描述 如标题所示&#xff0c;在搭建simulink模型过程中&#xff0c;明明模型搭建的没有问题&#xff0c;但是输出的波形却不是理想的正弦波&#xff0c;影响问题分析。 问题分析 以三相交流信号源输出波形为例&#xff0c;输出信号理应为三相正弦量&#xff0c;但是仿真…...

[含文档+PPT+源码等]精品基于Python实现的校园小助手小程序的设计与实现

基于Python实现的校园小助手小程序的设计与实现背景&#xff0c;可以从以下几个方面进行阐述&#xff1a; 一、技术背景 1. Python与Django框架的优势 Python作为一种高级编程语言&#xff0c;以其简洁的语法、丰富的库和强大的社区支持&#xff0c;在Web开发领域得到了广泛…...

Nginx(基础安装+配置文件)

目录 一.Nginx基础 1.基础知识点 2.异步非阻塞机制 二.Nginx安装 2.1安装nginx3种方式 1.包管理工具安装&#xff08;yum/apt&#xff09; 2.本地包安装&#xff08;rpm/dpkg&#xff09; 3.源码编译安装 3.1 源码编译安装nginx流程&#xff08;ubuntu&#xff09; 1.…...

el-table中slot=“header“和#header的区别

在<el-table>中&#xff0c;自定义表头单元格内容&#xff0c;可以用<templat slot"header">或者<templat #header>插入自定义表头内容&#xff0c;但如果表头中含有变量&#xff0c;比如<template slot"header">{{name}}</tem…...

S19文件格式详解:汽车ECU软件升级中的核心镜像格式

文章目录 引言一、S19文件格式的起源与概述二、S19文件的核心结构三、S19在汽车ECU升级中的应用场景四、S19与其他格式的对比五、S19文件实例解析六、工具链支持与安全考量七、未来趋势与挑战结语引言 在汽车电子控制单元(ECU)的软件升级过程中,S19文件(也称为Motorola S-…...

鸿蒙跨平台框架ArkUI-X

01 引言 目前&#xff0c;移动端主流跨平台方案有Flutter、React Native、uni-app等等&#xff0c;还有刚推出不久的Compose-Multiplatform&#xff0c;真所谓是百花齐放。这些框架各有特点&#xff0c;技术实现各有差异&#xff0c;比如Flutter通过Dart编写的UI描述对接Flutte…...

群晖DS223 Docker搭建为知笔记

群晖DS223 Docker搭建为知笔记&#xff0c;打造你的专属知识宝库 一、引言 在数字化信息爆炸的时代&#xff0c;笔记软件成为了我们管理知识、记录灵感的得力助手。为知笔记&#xff0c;作为一款专注于工作笔记和团队协作的云笔记产品&#xff0c;以其丰富的功能和便捷的使用体…...

FPGA入门教程

引言 FPGA&#xff08;Field-Programmable Gate Array&#xff0c;现场可编程门阵列&#xff09;是一种灵活且强大的硬件设备&#xff0c;广泛应用于数字电路设计、信号处理、嵌入式系统等领域。与传统的ASIC&#xff08;专用集成电路&#xff09;不同&#xff0c;FPGA允许用户…...

DR和BDR的选举规则

在 OSPF&#xff08;开放最短路径优先&#xff09;协议中&#xff0c;DR&#xff08;Designated Router&#xff0c;指定路由器&#xff09; 和 BDR&#xff08;Backup Designated Router&#xff0c;备份指定路由器&#xff09; 的选举是为了在广播型网络&#xff08;如以太网…...

无需环境,直接用 Docker 来启动你的 Python 项目

大家好 我是洪峰 想象这样一种场景&#xff0c;你写好了代码&#xff0c;准备部署在新的服务器上&#xff0c;这台服务器只有 Python2 和 Python3.6&#xff0c;没有你代码适配好的 Python3.12&#xff0c;那怎么办&#xff1f; 1、编译安装 Python&#xff0c;我不推荐这种方…...

STM32之BKP

VBAT备用电源。接的时候和主电源共地&#xff0c;正极接在一起&#xff0c;中间连接一个100nf的电容。BKP是RAM存储器。 四组VDD都要接到3.3V的电源上&#xff0c;要使用备用电池&#xff0c;就把电池正极接到VBAT&#xff0c;负极跟主电源共地。 TEMPER引脚先加一个默认的上拉…...

【08】单片机编程核心技巧:变量命名规范

【08】单片机编程核心技巧&#xff1a;变量命名规范 &#xff08;基于单片机开发实践&#xff0c;适用于 C/C 语言&#xff09; &#x1f4cc; 核心原则 1️⃣ 清晰性&#xff1a;通过前缀、后缀、大小写区分变量类型、作用域、数据宽度等。 2️⃣ 一致性&#xff1a;同一项…...

JVM、MySQL常见面试题(尽力局)

JVM篇 一.谈一谈JDK、JRE、JVM分别是什么&#xff0c;有什么联系&#xff1f; 1.JDK是Java工具包&#xff0c;里面包含了JRE、Javac编译器等。 2.JRE是java运行环境&#xff0c;里面包含了JVM、JavaSE标准库类等。 3.JVM是Java虚拟机&#xff0c;运行编译后的.class的文件&am…...

Pytorch 转向TFConv过程中的卷积转换

转换知识基础 图像中使用的卷积一般为&#xff0c;正方形卷积核针对一个同等面积邻域的&#xff0c;进行相乘后邻域叠加到中心&#xff0c;相当于考虑中心像素的周围信息&#xff0c;做了一定的信息融合。 卷积相关参数 卷积前: input c1 卷积中: kernel 卷积核 stride 步…...

基于LabVIEW的伺服阀高频振动测试闭环控制系统

为实现伺服阀在设定位置上下快速移动&#xff08;1kHz控制频率&#xff09;的振动测试目标&#xff0c;需构建基于LabVIEW的闭环控制系统。系统需满足高速数据采集、实时控制算法&#xff08;如PID或自适应控制&#xff09;、高精度电流驱动及传感器反馈处理等需求。结合用户提…...

QQuick3D-Camera的介绍

QQuick3D-Camera的介绍 Camera的概述 Camera类继承于 Node&#xff1b;Camera定义了怎样将一个3D场景&#xff08;Scene&#xff09;投影到2D的表面上&#xff1b;一个场景至少需要一个Camera来可视化其内容。 Camera 可以像场景中任何节点一样&#xff0c;被定位和旋转&…...

django下防御race condition漏洞(竞争型漏洞)

目录 竞争型漏洞 概念 常见类型及示例 环境搭建 ​编辑漏洞复现 ucenter/1/ ucenter/2/ ucenter/3/ ucenter/4/ 总结 悲观锁 乐观锁 竞争型漏洞 概念 竞争型漏洞&#xff0c;也称为竞态条件漏洞&#xff08;Race Condition Vulnerability&#xff09;&#xff0c;…...

【测试框架篇】单元测试框架pytest(4):assert断言详解

一、前言 用例三要素之一就是对预期结果的断言。 何为断言&#xff1f;简单来说就是实际结果和期望结果去对比&#xff0c;符合预期就测试pass&#xff0c;不符合预期那就测试 failed。断言内容就是你要的预期结果。断言包含对接口响应内容做断言、也包含对落DB的数据做断言。…...

多视图几何--结构恢复--三角测量

三角测量 1. 核心公式推导 假设两个相机的投影矩阵为 P P P 和 P ′ P P′&#xff0c;对应的匹配图像点(同名点)为 ( u , v ) (u, v) (u,v) 和 ( u ′ , v ′ ) (u, v) (u′,v′)&#xff0c;目标是求解三维点 X [ X x , X y , X z , 1 ] T X [X_x, X_y, X_z, 1]^T X…...

【大模型】WPS 接入 DeepSeek-R1详解,打造全能AI办公助手

目录 一、前言 二、WPS接入AI工具优势​​​​​​​ 三、WPS接入AI工具两种方式 3.1 手动配置的方式 3.2 Office AI助手 四、WPS手动配置方式接入AI大模型 4.1 安装VBA插件 4.1.1 下载VBA插件并安装 4.2 配置WPS 4.3 WPS集成VB 4.4 AI助手效果测试 4.5 配置模板文…...

⭐算法OJ⭐N-皇后问题 II【回溯剪枝】(C++实现)N-Queens II

⭐算法OJ⭐N-皇后问题【回溯剪枝】&#xff08;C实现&#xff09;N-Queens 问题描述 The n-queens puzzle is the problem of placing n n n queens on an n n n \times n nn chessboard such that no two queens attack each other. Given an integer n, return the num…...

解锁 AI 量化新境界:Qbot 携手 iTick

在量化投资的汹涌浪潮中&#xff0c;你是否渴望拥有一个强大且便捷的工具&#xff0c;助你乘风破浪&#xff0c;驶向财富的彼岸&#xff1f;如今&#xff0c;Qbot 与 iTick 强强联合&#xff0c;为广大投资者和开发者打造出一个前所未有的 AI 量化生态系统。 Qbot&#xff1a;量…...

vue2设置横向滚动指令

图片横向滑动展示效果 创建directives.js文件 // 横向列表拖拽 const draggleScrollX {inserted(el, binding) {let isDragging false;let startX 0;let scrollLeft 0;el.classList.add("draggle-horizontal");// 添加监听事件-鼠标按下const onMouseDown (eve…...

Git和GitHub基础教学

文章目录 1. 前言2. 历史3. 下载安装Git3.1 下载Git3.2 安装Git3.3 验证安装是否成功 4. 配置Git5. Git基础使用5.1 通过Git Bash使用5.1.1 创建一个新的仓库。5.1.1.1 克隆别人的仓库5.1.1.2 自己创建一个本地仓库 5.1.2 管理存档 5.2 通过Visual Studio Code使用 6. Git完成远…...

【Linux docker】关于docker启动出错的解决方法。

无论遇到什么docker启动不了的问题 就是 查看docker状态sytemctl status docker查看docker日志sudo journalctl -u docker.service查看docker三个配置文件&#xff08;可能是配置的时候格式错误&#xff09;&#xff1a;/etc/docker/daemon.json&#xff08;如果存在&#xf…...

程序化广告行业(2/89):从程序化广告深挖数据处理技巧

程序化广告行业&#xff08;2/89&#xff09;&#xff1a;从程序化广告深挖数据处理技巧 大家好&#xff01;我一直希望能和大家在技术学习的道路上携手共进&#xff0c;这也是我写这一系列博客的初衷。上次我们一起学习了Python基础的数据处理知识&#xff0c;这次咱们借助一…...

第七课:Python反爬攻防战:Headers/IP代理与验证码

在爬虫开发过程中&#xff0c;反爬虫机制成为了我们必须面对的挑战。本文将深入探讨Python爬虫中常见的反爬机制&#xff0c;并详细解析如何通过随机User-Agent生成、代理IP池搭建以及验证码识别来应对这些反爬策略。文章将包含完整的示例代码&#xff0c;帮助读者更好地理解和…...

时序数据库TimescaleDB基本操作示例

好的&#xff01;以下是使用 TimescaleDB 的 Java 示例&#xff08;基于 JDBC&#xff0c;因为 TimescaleDB 是 PostgreSQL 的扩展&#xff0c;官方未提供独立的 Java SDK&#xff09;&#xff1a; 1. 添加依赖&#xff08;Maven&#xff09; <dependency><groupId&g…...

【CSS 】Class Variance Authority CSS 类名管理工具库

1.背景、什么是 CVA&#xff1f; Class Variance Authority (CVA) 是一个用于管理 CSS 类名 的工具库&#xff0c;特别适合在 React 或 Vue 等前端框架中使用。它可以帮助你更轻松地处理组件的 样式变体&#xff08;Variants&#xff09;&#xff0c;比如按钮的不同状态&#…...

【Linux】36.简单的TCP网络程序

文章目录 1. TCP socket API 详解1.1 socket():打开一个网络通讯端口1.2 bind():绑定一个固定的网络地址和端口号1.3 listen():声明sockfd处于监听状态1.4 accept():接受连接1.5 connect():连接服务器 2. 实现一个TCP网络服务器2.1 Log.hpp - "多级日志系统"2.2 Daem…...

Win 转 MacBook Pro 踩坑指南

前言 Window 和 macOS 系统的差异还是很大的&#xff0c;我从 Thinkpad 转用 M1 的 Macbook pro 已经一年了&#xff0c;几乎没有任何不适应&#xff0c;整体感受那是真的牛&#x1f443;&#xff0c;速度和续航惊艳到我了&#xff0c;同时开启 6个 vscode 加几十个浏览器标签…...

【模拟CMOS集成电路设计】带隙基准(Bandgap)设计与仿真(基于运放的电流模BGR)

【模拟CMOS集成电路设计】带隙基准&#xff08;Bandgap&#xff09;设计与仿真 前言工程文件&部分参数计算过程&#xff0c;私聊~ 一、 设计指标指标分析&#xff1a; 二、 电路分析三、 仿真3.1仿真电路图3.2仿真结果(1)运放增益(2)基准温度系数仿真(3)瞬态启动仿真(4)静态…...

手写一个Tomcat

Tomcat 是一个广泛使用的开源 Java Servlet 容器&#xff0c;用于运行 Java Web 应用程序。虽然 Tomcat 本身功能强大且复杂&#xff0c;但通过手写一个简易版的 Tomcat&#xff0c;我们可以更好地理解其核心工作原理。本文将带你一步步实现一个简易版的 Tomcat&#xff0c;并深…...

QT显示网页控件QAxWidget、QWebEngineView及区别

一.QT种显示网页控件QAxWidget 1.介绍 QAxWidget 属于 QtAxContainer 模块&#xff0c;ActiveX 是微软提出的一种组件对象模型&#xff08;COM&#xff09;技术&#xff0c;允许不同的软件组件在 Windows 操作系统上进行交互和集成。QAxWidget 为开发者提供了在 Qt 应用程序中…...

【AI智能体报告】开源AI助手的革命:OpenManus深度使用报告

一、引言&#xff1a;当开源智能体走进生活 2025年3月&#xff0c;MetaGPT团队用一场"开源闪电战"改写了AI Agent的竞争格局。面对商业产品Manus高达10万元的邀请码炒作&#xff0c;他们仅用3小时便推出开源替代品OpenManus&#xff0c;首日即登顶GitHub趋势榜。 …...

VS Code连接服务器教程

VS Code是什么 VS Code&#xff08;全称 Visual Studio Code&#xff09;是一款由微软推出的免费、开源、跨平台的代码编辑神器。VS Code 支持 所有主流操作系统&#xff0c;拥有强大的功能和灵活的扩展性。 官网&#xff1a;https://code.visualstudio.com/插件市场&#xff1…...

装饰器模式的C++实现示例

核心思想 装饰器设计模式是一种结构型设计模式&#xff0c;它允许动态地为对象添加额外的行为或职责&#xff0c;而无需修改其原始类。装饰器模式通过创建一个装饰器类来包装原始对象&#xff0c;并在保持原始对象接口一致性的前提下&#xff0c;扩展其功能。 装饰器模式的核…...

C 语言数据结构(二):顺序表和链表

目录 1. 线性表 2. 顺序表 2.1 概念及结构 2.1.1 静态顺序表&#xff08;不常用&#xff09; 2.1.2 动态顺序表&#xff08;常用&#xff09; ​编辑 2.2 练习 2.2.1 移除元素 2.2.2 删除有序数组中的重复项 2.2.3 合并两个有序数组 2.3 顺序表存在的问题 3. 链表 …...

TDengine 服务无法启动常见原因

taosd 是 TDengine 的核心服务进程&#xff0c;如果无法启动将导致整个数据库无法使用&#xff0c;了解常导致无法启动的原因&#xff0c;可以帮你快速解决问题。 1. 如何查找日志 无法启动的原因记录在日志中&#xff0c;日志文件默认在 /var/log/taos 的 taosdlog.0 或者 t…...

在 UniApp 中实现stream流式输出 AI 聊天功能,AI输出内容用Markdown格式展示

在 UniApp 中实现流式 AI 聊天功能 介绍 在现代 Web 开发中&#xff0c;流式 API 响应能够显著提升用户体验&#xff0c;尤其是在与 AI 聊天接口进行交互时。本文将介绍如何在 UniApp 中使用 Fetch API 实现一个流式响应的 AI 聊天功能&#xff0c;包括实时更新聊天内容和滚动…...

数据库SQL的配置和练习题

一、MySQL的安装 1.安装包下载 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 2.解压软件包 将MySQL软件包解压在没有中文和空格的目录下 3.设置配置文件 在解压目录下创建my.ini文件并添加内容如下&#xff1a; ​ [client] #客户端设置&…...

Pytorch的一小步,昇腾芯片的一大步

Pytorch的一小步&#xff0c;昇腾芯片的一大步 相信在AI圈的人多多少少都看到了最近的信息&#xff1a;PyTorch最新2.1版本宣布支持华为昇腾芯片&#xff01; 1、 发生了什么事儿&#xff1f; 在2023年10月4日PyTorch 2.1版本的发布博客上&#xff0c;PyTorch介绍的beta版本…...

AI+办公 Task1

作业 题目1&#xff1a;提示词除了三要素“角色”、“背景”、“要求”之外&#xff0c;还有哪些关键要素 提示词有一个框架叫CO-STAR框架&#xff0c;还有的关键要素有风格、任务、响应格式等。 要素适用场景实际案例​Context需要限定领域或场景的任务"作为医学助手&…...

文件系统调用─── linux第17课

目录 linux 中man 2和man 3的区别 文件内容介绍 C语言文件接口 示例: 输出信息到显示器&#xff0c;你有哪些方法 总结: 系统文件I/O 文件类的系统调用接口介绍 示例 open 函数具体使用哪个,和具体应用场景相关&#xff0c; write read close lseek ,类比C文件相关接…...

概念|RabbitMQ 消息生命周期 待消费的消息和待应答的消息有什么区别

目录 消息生命周期 一、消息创建与发布阶段 二、消息路由与存储阶段 三、消息存活与过期阶段 四、消息投递与消费阶段 五、消息生命周期终止 关键配置建议 待消费的消息和待应答的消息 一、待消费的消息&#xff08;Unconsumed Messages&#xff09; 二、待应答的消息…...

Javaweb后端文件上传@value注解

文件本地存储磁盘 阿里云oss准备工作 阿里云oss入门程序 要重启一下idea&#xff0c;上面有cmd 阿里云oss案例集成 优化 用spring中的value注解...

DeepSeek技术演进与发展前瞻

如果喜欢可以订阅专栏哟(^U^)ノ~YO,至少更新6年 以下DeepSeek未来发展的技术分析框架及核心内容示范 # -*- coding: utf-8 -*- """ DeepSeek技术演进模拟器(概念验证代码) 本代码展示动态架构调整的核心逻辑 """class DynamicArchitect…...

Java常见面试技术点整理讲解——后端框架(整理中,未完成)

前言&#xff1a; 对于后端常用框架的技术整理&#xff0c;其实框架在平时就是会用就行&#xff0c;但面试时多半需要描述实现原理&#xff0c;这个要靠自己理解&#xff0c;不推荐死记硬背。 这篇和另外几篇文章区分开&#xff0c;主要用于规整Java后端各种框架&#xff0c;…...