主頁 > 區塊鏈 > Android記事本

Android記事本

2020-11-01 23:07:32 區塊鏈

目錄

  • 一、前言
  • 二、開發環境
  • 三、效果預覽
  • 四、應用介紹
    • 4.1 主界面
    • 4.2 新增界面
    • 4.3 編輯界面
    • 4.4 搜索界面
    • 4.5 資料庫
    • 4.6 黑夜模式
  • 五、檔案串列
  • 六、可能出現的問題
  • 七、關鍵功能
    • 7.1 RecyclerView的使用
    • 7.2 Material庫控制元件的使用
    • 7.3 FloatingActionButton的使用
    • 7.4 滑動選單
    • 7.5 TimePickerDialog的使用
    • 7.6 通知的使用
    • 7.7 服務的使用
    • 7.8 資料庫的使用
  • 八、后記

一、前言

上學期做了個簡單的Android的記事本APP(功能基本就是書里的雜糅),也是我第一次接觸Android,一時興起,趁還沒忘光先記錄下來,一直以來都在看別人的自己沒有分享過東西,如果能提供到一點點的幫助也是極好的,

教材選的是郭霖老師的《第一行代碼》,買了第二版回來以后,沒想到沒過幾周,在逛csdn的時候就看到第三版也出了,果斷也買了,第三版里根據Android版本的更新更新了很多控制元件的使用,但是全書使用的是Kotlin語言,我的做法是將第二、三版結合起來一起看,僅供參考,


二、開發環境

Android Studio3.4
JDK13.0.2

版本:
Android Q(10.0)
API 29
Gradle 6.2.2

在專案中的一些控制元件的參考與方法的使用都是基于上述版本的,可能會出現和其他版本中不一致的情況,


三、效果預覽


四、應用介紹

功能包括筆記的增刪查改和定時提醒之類,總體上將最主要的功能放在最顯眼的地方展示出來,而次要的功能放在選單里,應用總共有四個界面,每個界面都是一個Activity,

4.1 主界面

進入應用看到的界面,應用的所有界面都隱藏了原先自帶的標題欄ActionBar,改為使用自定義的Toolbar,向下滑動以后頂部的圖片會折疊起來,向上滑動會重新顯示,具體是使用CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout + ImageView

用RecyclerView顯示筆記,新建功能單獨放在下方的FloatingActionButton里,其他的功能放在標題欄的選單中,

活動模式在AndroidManifest里選用的是singleTop,這樣從其他界面回到主界面的時候就可以保證資料更新,

筆記顯示方式可以選用默認的垂直式(LinearLayoutManager)或者網格式(StaggeredGridLayoutManager),雖然上面寫著瀑布布局但不是真的瀑布式

CoordinatorLayout、AppBarLayout、CollapsingToolbarLayout

1、CoordinatorLayout可以監聽所有子控制元件的所有事件,可以回應滾動事件,加強版的FrameLayout;
2、AppBarLayout解決RecyclerView和Toolbar之間互相覆寫的問題,垂直方向的LinearLayout;
3、CollapsingToolbarLayout作用于Toolbar之上,可以實作折疊圖片的效果;
4、CollapsingToolbarLayout只能作為AppBarLayout的直接子布局,AppBarLayout只能作為CoordinatorLayout的子布局,
我對三者的嵌套關系認識是 :
< CoordinatorLayout>
?< AppbarLayout>
??< CollapsingToolbarLayout>
??< /CollapsingToolbarLayout>
?< /AppbarLayout>
< /CoordinatorLayout>

RecyclerView

滾動顯示內容的控制元件,可以自定義子項的布局,使用的時候需要為RecyclerView準備一個配接器以將資料傳遞給控制元件,通過泛型來指定要適配的資料型別,然后資料傳入,

FloatingActionButton

懸浮按鈕,可以自行調整位置和懸浮的高度,需要Material庫

其他

1.折疊圖片
在res - values - styles.xml中,將AppTheme改成

name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge"

在布局檔案中嵌套使用CoordinatorLayout、AppBarLayout、CollapsingLayout、ImageView

在build.gradle中添加Glide庫的依賴,Glide用來加載圖片

implementation 'com.github.bumptech.glide:glide:3.7.0

加載圖片

Glide.with(this).load(R.mipmap.圖片名稱).into(ImageView的id);

2.實作標題欄和狀態欄融為一體的效果
在CoordinatorLayout、AppBarLayout、CollapsingLayout都加上屬性

android:fitsSystemWindow="true"

styles.xml(res目錄New - Directory新建values-v21目錄,在values-v21中New - Values resource file)

<resources>
	<style name="MainActivityTheme" parent="AppTheme">
		<item name="android:statusBarColor">@android:color/transparent</item>
	</style>
</resources>

在res - values - styles.xml中加上

<style name="MainActivityTheme" parent="AppTheme">

在AndroidManifest.xml中的activity標簽里加上

android:theme="@style/MainActivityTheme"

activity_main.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:background="#FFFBF0">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        android:fitsSystemWindows="true">
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsingToolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:theme="@style/ThemeOverlay.AppCompat.DayNight.ActionBar"
            android:fitsSystemWindows="true"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
            <ImageView
                android:id="@+id/toolbarImageView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax"
                android:adjustViewBounds="true"
                android:contentDescription="This is picture of title"
                tools:ignore="HardcodedText"/>
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin" />
        </com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:layout_gravity="bottom|end"
        android:src="@drawable/pencil_48px"
        app:elevation="8dp"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

4.2 新增界面

功能簡單,就是創建新的筆記,整個界面只有一個Button和一個EditText,

圓角的卡片效果是使用CardView實作的,點擊保存按鈕以后,會生成一個亂數,并將筆記的內容、當前時間和這個亂數一起保存進資料庫中,
(為什么要生成亂數:詳見4.5)

NestedScrollView

可以滾動查看螢屏以外的資料,可以嵌套回應滾動事件,用在CoordinatorLayout內部,因為后者本身可以回應滾動事件,

CardView

實作卡片式布局效果的控制元件,

其他

1.使用toolbar匯入包的時候選

import androidx.appcompat.widget.Toolbar;

2.加上這段代碼可以防止NestedScrollView和EditText嵌套使用時出現滑動沖突:

editText.setOnTouchListener(new View.OnTouchListener(){
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent){
                if(motionEvent.getAction()==MotionEvent.ACTION_DOWN){
                    view.getParent().requestDisallowInterceptTouchEvent(true);
                }
                if(motionEvent.getAction()==MotionEvent.ACTION_MOVE){
                    view.getParent().requestDisallowInterceptTouchEvent(true);
                }
                if(motionEvent.getAction()==MotionEvent.ACTION_UP){
                    view.getParent().requestDisallowInterceptTouchEvent(false);
                }
                return false;
            }
        });

3.獲取當前時間:

private String getTime(){
        @SuppressLint("SimpleDateFormat") SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
        Date curDate = new Date(System.currentTimeMillis());
        return date.format(curDate);// 不需要賦值給中間變數再回傳
    }

4.生成亂數:

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private static int getRandom(){// 獲取亂數
        return ThreadLocalRandom.current().nextInt();
    }

activity_add.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout 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.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize">
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="#FFDAB9"
            android:theme="@style/ThemeOverlay.AppCompat.DayNight.ActionBar"
            tools:ignore="MissingConstraints"/>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <com.google.android.material.card.MaterialCardView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginTop="15dp"
                android:layout_marginBottom="20dp"
                android:layout_marginLeft="15dp"
                android:layout_marginStart="15dp"
                android:layout_marginRight="15dp"
                android:layout_marginEnd="15dp"
                app:cardBackgroundColor="#FFFBF0"
                app:cardCornerRadius="4dp"
                app:layout_constraintTop_toBottomOf="@+id/toolbar">
                <EditText
                    android:id="@+id/editText"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:gravity="top"
                    android:layout_margin="10dp"
                    android:inputType="textMultiLine"
                    android:lines="27"
                    android:importantForAutofill="no"
                    android:background="@null"
                    android:scrollbars="vertical"
                    android:hint="@string/add_hint"/>
            </com.google.android.material.card.MaterialCardView>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

4.3 編輯界面

風格和新增界面保持一致,除了保存功能,其他的小功能都放入了左上角的滑動選單中(NavigationView),小功能包括快速新建筆記、獲取靈感、定時提醒和洗掉筆記,

  • 快速新建筆記:
    免除回到主界面再新建的繁瑣,直接在編輯界面進入新增界面,

  • 獲取靈感:
    湊數的功能,主要是選單里只有三個功能不好看加上去的,實際是彈出一個dialog,里面隨機顯示一條金句,金句是事先放在一個陣列里的,

  • 定時提醒:
    系統在設定的時間發送一條通知,具體實作是在彈出的TimerPickerDialog里用AlarmManager設定提醒時間,將設好的時間傳遞給Service,到了設定的時間以后Service會啟動Notification進行通知,

  • 洗掉筆記:
    將當前的筆記從資料庫洗掉,

NavigationView
實作滑動選單的控制元件,分為上半部分的headerLayout和下半部分menu,

TimePickerDialog
時間對話框,

AlarmManager
Android中用來實作定時任務的其中一種方式,另一種是使用Timer類,

Service
服務,四大組件之一,一般負責一些后臺功能,不依賴任何用戶界面,適合一些不需要和用戶互動的任務,

Notification
通知,應用會在上方的狀態欄顯示一個通知的圖示,可以設定通知圖示、是否有響聲,

activity_edit.xml

<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawerLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".EditActivity">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appBar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize">
            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolBar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="#FFDAB9"
                style="@style/ThemeOverlay.AppCompat.DayNight.ActionBar"
                tools:ignore="MissingConstraints"/>
        </com.google.android.material.appbar.AppBarLayout>

        <androidx.core.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <com.google.android.material.card.MaterialCardView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginTop="15dp"
                    android:layout_marginStart="15dp"
                    android:layout_marginLeft="15dp"
                    android:layout_marginEnd="15dp"
                    android:layout_marginRight="15dp"
                    android:layout_marginBottom="20dp"
                    app:cardBackgroundColor="#FFFBF0"
                    app:cardCornerRadius="4dp"
                    app:layout_constraintTop_toBottomOf="@id/toolBar">
                    <EditText
                        android:id="@+id/editText"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:gravity="top"
                        android:layout_margin="10dp"
                        android:inputType="textMultiLine"
                        android:lines="27"
                        android:importantForAutofill="no"
                        android:background="@null"
                        android:scrollbars="vertical"
                        android:hint="@null"
                        android:textColor="#232323"/>
                </com.google.android.material.card.MaterialCardView>
            </LinearLayout>
        </androidx.core.widget.NestedScrollView>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/nav_menu"
        app:headerLayout="@layout/nav_header"/>
</androidx.drawerlayout.widget.DrawerLayout>

4.4 搜索界面

點擊搜索按鈕以后進入的界面,根據關鍵字搜索已創建的筆記,點擊搜索顯示符合條件的筆記(RecyclerView),點擊取消回到主界面,界面包含一個EditText、兩個Button和一個RecyclerView,文本框的提示資訊在布局檔案里用hint屬性來實作,

activity_search.xml

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="#989795">
        <EditText
            android:id="@+id/editText"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:inputType="text"
            android:importantForAutofill="no"
            android:hint="@string/add_hint"/>
        <Button
            android:id="@+id/buttonSearch"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/search"/>
        <Button
            android:id="@+id/buttonBack"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/cancel"/>
    </LinearLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

4.5 資料庫

選擇了Android自帶的Sqlite資料庫,使用了LitePal來進行資料庫操作,

欄位型別含義
idint自帶的
textString筆記內容
timeString筆記創建時間
tagint筆記標識

說明:
id欄位好像是使用LitePal以后會自動生成的,我不會用
tag欄位用來代替id來唯一標識每一篇筆記,具體是在新建筆記的時候生成一個亂數給它,使用一個準確的時間(比如精確到秒)來作標識可能會更好,可以防止翻車,

打開在右下角邊欄的Device File Explorer,在data - data - 包名下可以找到生成的資料庫檔案(.db),

LitePal
開源的Android資料庫框架,將一些資料庫常用的功能進行了封裝,

4.6 黑夜模式

Android 10以后才能使用的功能,
colors.xml(res目錄New - Directory新建values-night,在values-night里New - Values resource file)

<resources>
	<color name="colorPrimary">#303030</color>
	<color name="colorPrimaryDark">#232323</color>
	<color name="colorAccent">#008577</color>
</resources>

剩下的我自己也沒整明白,就不提了,


五、檔案串列

主界面
MainActivity.java:活動
activity_main.xml:主界面布局
toolbar.xml:選單

新建界面
AddActivity.java:活動
activity_add.xml:新建界面布局
toolbar_add.xml:標題欄選單

編輯界面
EditActivity.java:活動
NoticeService.java:服務
activity_edit.xml:編輯界面布局
toolbar_add.xml:標題欄選單
nav_header.xml:滑動選單布局
nav_menu.xml:滑動選單

搜索界面
SearchActivity.java:活動
activity_search.xml:搜索界面布局

其他
(RecyclerView用的)
Note.java:自定義的泛型
NoteAdapter.java:自定義的配接器
note_item.xml:子項的布局
(資料庫用的)
NoteBook.java:資料庫表
litepal.xml:Litepal配置


六、可能出現的問題

報錯

Casued by:java.lang.reflect.InvocationTargetException

Casued by:java.lang.IllegalArgumentException:The style on this compoent requires your app theme to Theme

說明:
需要更新控制元件的主題到Theme.MaterialComponent

解決
在styles.xml中,將

<style name="AppTheme"parent="Theme.AppCompat.Light.NoActionBar">

改成

<style name="AppTheme"parent="Theme.MaterialComponents.Light.NoActionBar.Bridge">

報錯

java.lang.IllegalArgumentException:Unsupported class file major version 57

說明
version 57對應的JDK版本是13,如果是version 56對應的是12

解決
安裝更低版本的JDK
(這個問題我忘了是什么時候遇到了,最后我沒有降低版本,可能是改用了別的控制元件,或者把其他什么地方的版本也升級了)

報錯

Casued by:org.codehaus.groovy.control.MultipleCompilationErrorsException:startup failed:

說明
原因不清楚

解決
升級Gradle到6.2.2版本可以解決,存在的缺陷是每次打開專案都要手動升級一次

報錯

You need to use a Theme.Appcompat.theme:

說明

解決
讓活動從繼承ActionBarActivity改成繼承Activity


七、關鍵功能

7.1 RecyclerView的使用

在build.gradle中添加依賴(根據版本不同選擇其中一個,上面是舊的,下面是新的)

implementation 'com.android.support:recyclerview-v7:29.1.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'

(忘了用不用這步了)

在File - project structure - dependencies - app - library dependency中搜索recyclerview,選擇“androidx.”的最新版本

在布局檔案中參考(根據版本不同選擇,上面是舊的,下面是新的)

<android.support.v7.widget.RecyclerView
	android:id=""
	android:layout_width=""
	android:layout_height=""/>
<androidx.recyclerview.widget.RecyclerView
	android:id=""
	android:layout_width=""
	android:layout_height=""/>

Note.java(泛型)

public class Note(){
	private String noteContent;// 筆記內容
	private String noteTime;// 筆記創建時間
	private int noteTag;// 筆記標識

	public Note(String noteContent, String noteTime, int noteTag){
		this.noteContent = noteContent;
		this.noteTime = noteTime;
		this.noteTag = noteTag;
	}

	public String getNoteContent(){ return noteContent; }
	public String getNoteTime(){ return noteTime; }
	public int getNoteTag(){ return noteTag; }
}

note_item.xml(子項的布局)

<com.google.android.material.card.MaterialCardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    app:cardCornerRadius="4dp">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/noteContent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginLeft="10dp"
            android:lines="2"
            android:background="#FFFEF0"
            android:textSize="24sp"
            android:textColor="#232323"/>
        <TextView
            android:id="@+id/noteTime"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginLeft="10dp"
            android:background="#FFDAB9"
            android:textColor="#008577"/>
    </LinearLayout>
</com.google.android.material.card.MaterialCardView>

NoteAdapter.java(配接器)
讓配接器繼承自RecyclerView.Adapter,將泛型指定為NoteAdapter.ViewHolder,內部類ViewHolder用于對控制元件的實體進行快取,

import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;

public class NoteAdapter extends RecyclerView.Adapter<NoteAdapter.ViewHolder>{
	private List<Note> mNoteList;

	static class ViewHolder extends RecyclerView.ViewHolder{// 內部類ViewHolder
		View noteView;
		TextView noteContent;
		TextView noteTime;

		public ViewHolder(View view){// 傳入子項的最外層布局
			super(view);
			noteView = view;
			noteContent = (TextView) view.findViewById(R.id.noteContent);// 獲取實體
			noteTime = (TextView) view.findViewById(R.id.noteTime);// 獲取實體
		}
	}

	public NoteAdapter(List<Note> noteList){// 傳入需要展示的資料
		mNoteList = noteList;
	}

	@Override
	public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){// 創建ViewHolder實體
		View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.note_item, parent, false);// 加載布局
		final ViewHolder holder = new ViewHolder(view);
		
		holder.noteView.setOnClickListener(new View.OnClickListener()){// 子項點擊事件
			@Override
			public void onClick(View v){
				int position = holder.getAdapterPosition();
				Note note = mNoteList.get(position);

				Intent intent = new Intent(v.getContext(), EditActivity.class);
				String contentData = note.getNoteContent();
				int tagData = note.getNoteTag();
				// intent.putExtra("鍵",資料)
				intent.putExtra("content_data", contentData);
				intent.putExtra("tag_data", String.valueOf(tagData));
				v.getContext.startActivity(intent);
			}
		});
		holder.noteTime.setOnClickListener(new View.OnClickListener(){// 子項點擊事件
			@Override
			public void onClick(View v){
				int position = holder.getAdapterPosition();
				Note note = mNoteList.get(position);

				String time = note.getNoteTime();
				Toast.makeText(v.getContext(), "筆記創建于" + time, Toast.LENGTH_LONG).show();
			}
		});
		return holder;
	}

	@Override
	public void onBindViewHolder(ViewHolder holder, int position){// 為子項賦值,子項被滾動到螢屏就執行
		Note note = mNoteList.get(position);
		holder.noteContent.setText(note.getNoteContent());
		holder.noteTime.setText(note.getNoteTime());
	}

	@Override
	public int getItemCount(){// 告訴RecyclerView一共有多少子項
		return mNoteList.size();
	}
}

更新:
如果獲取點擊位置的介面被劃線不推薦使用了,可能是如下原因(翻譯摘自郭霖老師的文章)

這個方法當多個adapter嵌套時會存在歧義,如果你是在一個adapter的背景關系中呼叫這個方法,你可能想要呼叫的是getBindingAdapterPosition()方法,如果你想獲得的position是如同在RecyclerView中看到的那樣,你應該呼叫getAbsoluteAdapterPosition()方法,

這是我這幾天寫這篇文章的時候看到的,具體文章→ 什么?RecyclerView中獲取點擊位置的介面被廢棄了?

實體化

public class MainActivity extends AppCompatActivity{
	
	private List<Note> noteList = new ArrayList<>();// 
	private RecyclerView recyclerView;

	@Override
	protected void onCreate(bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		recyclerView = (RecyclerView) findViewById(R.id.recycler_view);// 獲取RecyclerView實體
		LinearLayoutManager layoutManager = new LinearLayoutManager(this);
		recyclerView.setLayoutManager(layoutManager);// 設定垂直式排列
		NoteAdapter adapter = new NoteAdapter(noteList);// 創建NoteAdapter實體
		recyclerView.setAdapter(adapter);// 完成配接器設定 
	}
}

從資料庫獲取資料

List<NoteBook> notes = DataSupport.findAll(NoteBook.class);

for(NoteBook note : notes){
	Note temp = new Note(note.getContent(), note.getTime(), note.getTag());
	noteList.add(temp);
}

7.2 Material庫控制元件的使用

build.gradle中添加依賴

implementation 'com.google.android.material:material:1.1.0'

7.3 FloatingActionButton的使用

布局檔案中參考
app:elevation屬性指定的是高度值

<com.google.android.material.floatingactionbutton.FloatingActionButton
	android:id="@+id/fab"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_margin="16dp"
	android:layout_gravity="bottom|end"
	android:src="@drawable/圖片名稱"
	app:elevation="8dp"/>

設定點擊事件

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

fab.setOnClickListener(new View.OnClickListener()){
	@Override
	public void onClick(View v){
		Intent intent = new Intent(MainActivity.this, AddActivity.class);
		startActivity(intent);
	}
});

7.4 滑動選單

android.support:desgin庫已棄用,如需使用在build.gradle中添加

compile 'com.android.support:design:24.2.1'

nav_header.xml(Layout檔案夾New - Layout resource file)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="180dp">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@string/headerText"
        android:scaleType="centerCrop"
        android:src="@mipmap/圖片名稱"/>
</RelativeLayout>

nav_menu.xml(menu檔案夾New - Menu resource file)

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_add"
            android:icon="@drawable/圖片名稱"
            android:title="@string/add"/>
        <item
            android:id="@+id/nav_notice"
            android:icon="@drawable/圖片名稱"
            android:title="@string/notice"/>
        <item
            android:id="@+id/nav_refresh"
            android:icon="@drawable/圖片名稱"
            android:title="@string/refresh"/>
        <item
            android:id="@+id/nav_delete"
            android:icon="@drawable/圖片名稱"
            android:title="@string/delete"/>
    </group>
</menu>

布局檔案中參考

<com.google.android.material.navigation.NavigationView
	android:id="@id/navView"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:layout_gravity="start"
	app:menu="@menu/nav_menu"
	app:headerLayout+"@layout/nav_header"/>

設定點擊事件

NavigationView navView = (NavigationView) findViewById(R.id.navView);
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener(){
	@Override
	public boolean onNavigationItemSelected(@NonNull MenuItem item){
		switch(item.getItemId()){
			case R.id.nav_add:
				...
			case R.id.nav_notice:
				...
			case R.id.nav_refresh:
				...
			case R.id.nav_delete:
				...
			default:
		}
		return true;
	}
});

7.5 TimePickerDialog的使用

RTC_WAKEUP表示讓定時任務的觸發時間從1970.1.1的0點開始算起,會喚醒CPU,AlertDialog.THEME_HOLO_LIGHT讓TimePickerDialog顯示滾動的效果

alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

Calendar calendar1 = Calendar.getInstance();// 獲取實體
int hour = calendar1.get(Calendar.HOUR_OF_DAY);// 獲取當前小時
int minute = calendar1.get(Calendar.MINUTE);// 獲取當前分鐘

// 設定時間對話框
TimePickerDialog timePickerDialog = new TimePickerDialog(EditActivity.this, android.app.AlertDialog.THEME_HOLO_LIGHT, new TimePickerDialog.OnTimeSetListener() {
	@RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
    	Calendar calendar2 = Calendar.getInstance();
        calendar2.set(Calendar.HOUR_OF_DAY, hourOfDay);// 獲取設定小時
        calendar2.set(Calendar.MINUTE, minute);// 獲取設定分鐘

        Intent intent2 = new Intent(EditActivity.this, NoticeService.class);
        PendingIntent pi = PendingIntent.getService(EditActivity.this, 0, intent2, 0);
        // (作業型別, 觸發時間, 意圖)
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar2.getTimeInMillis(), pi);
    }
}, hour, minute, true);// 初始顯示時間
timePickerDialog.show();

7.6 通知的使用

這個通知是寫在服務里的,PendingIntent可以理解為延遲執行的Intent,

	@RequiresApi(api = Build.VERSION_CODES.O)// NotificationChannel&IMPORTANCE_HIGH的版本要求
    private void initNotice(){
        // getSystemService:確定獲取系統的哪個服務
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        // API 26(Android8.0)以后需要自己設定NotificationChannel
        String channelId = "channel_01";
        String channelName = "channelName";
        String channelDescription = "this is default channel";
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
        channel.setDescription(channelDescription);
        assert notificationManager != null;
        notificationManager.createNotificationChannel(channel);

        Intent intentOut = new Intent(NoticeService.this, MainActivity.class);
        // (Context, 0, Intent物件, PendingIntent的行為)
        PendingIntent pi = PendingIntent.getActivity(NoticeService.this, 0, intentOut, 0);
        // API 26(Android8.0)以后需要在Builder中添加id
        Notification notification = new NotificationCompat.Builder(this, channelId)
                .setContentTitle("記事本")
                .setContentText("定時提醒")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.圖片名稱)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.圖片名稱))
                .setContentIntent(pi)
                .setAutoCancel(true)// 讓通知可以點擊以后自動取消
                .build();
        notificationManager.notify(1, notification);
    }

這個通知最終實作的效果是,到了設定的時間后,會在系統的頂部彈出一個橫幅通知,進行點擊可以消除通知并進入記事本應用的主界面,

7.7 服務的使用

NoticeService.java(New - Service - Service)

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;

public class NoticeService extends Service {
    public NoticeService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){
        new Thread(new Runnable() {// 創建和啟動子執行緒
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void run() {// 處理具體邏輯
                initNotice();// 實作通知的函式

                stopSelf();// 執行完畢后自動停止
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

	private void initNotice(){// 見上文
		...
	}
}

7.8 資料庫的使用

build.gradle中添加依賴(我寫文章的時候看到的最新版本好像是3.2.0)

implementation 'org.litepal.android:core:1.3.2'

在AndroidManifest.xml中

<application
	android:name="org.litepal.LitePalApplication"
	...>
</application>

NoteBook.java(資料庫表)

import org.litepal.crud.DataSupport;

public class NoteBook extends DataSupport(){
	private int id;
	private String content;
	private String time;
	private int tag;

	public int getId(){ return id; }
	public void setId(int id){ this.id = id; }
	
	public String getContent(){ return content; }
	public void setContent(String content){ this.content = content; }

	public String getTime(){ return time; }
	public void setTime(String time){ this.time = time; }

	public int getTag(){ return tag; }
	public void setTag(int tag){ this.tag = tag; }
}

litepal.xml(在包名 - app - src下創建assets檔案夾,在assets檔案夾下創建litepal.xml)

dbname是資料庫的名字,version的值一開始是1,每次更新了資料庫表(改了欄位、新增了表等等)這個值就加1,list標簽里是資料庫的表,有幾個表就寫幾個< mapping >< /mapping >,

<?xml version="1.0" encoding="utf-8"?>
<litepal>
	<dbname value="NoteBook"></dbname>
	<version value="1"></version>

	<list>
		<mapping class="com.example.notebook.NoteBook"></mapping>
	</list>
</litepal>

連接資料庫

SQLiteDataBase db = Connector.getDataBase();

NoteBook note = new NoteBook();
String inputContent = editText.getText().toString();// 筆記的內容
String inputTime = getTime();// 筆記的創建時間
int inputTag = getRandom();// 筆記的標識

note.setContent(inputContent);
note.setTime(inputTime);
note.setTag(inputTag);

DataSupport.deleteAll(NoteBook.class, "tag = ?", tag);// 根據標識洗掉對應的筆記

String orderContent = editText.getText().toString();// 從文本框獲取想要查找的關鍵字

List<NoteBook> notes = DataSupport.where("content like ?", "%"+orderContent+"%").find(NoteBook.class);// 根據關鍵字在“內容”里查找

NoteBook note = new NoteBook();
String inputContent = editText.getText().toString();// 從文本框獲取更改后的筆記內容

note.setContent(inputContent);
note.updateAll("tag = ?", tag);

八、后記

文章寫得比較匆忙,可能會出現很多紕漏和錯誤,歡迎交流與學習,可能答不上來問題,后續如果想起了遺忘的東西可能會編輯,

程式是一邊學一邊寫的,想到什么就加了什么進去,應該還有很多不合理的地方或者可以優化的地方,

Android的東西更新得比較快,經常過一兩年又不一樣了,而這個變化的東西恰好沒有人發文章提到的時候,個人經驗,這個時候去Android Developers查看一下參考檔案(REFERENCE)會是個不錯的選擇,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/198640.html

標籤:區塊鏈

上一篇:專案實戰:Qt+Android模擬操作器(模擬操作app,打開,點擊,輸入,獲取驗證碼等等)

下一篇:【小技巧】怎樣保存ins里的圖片?一鍵下載,簡單方便

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • JAVA使用 web3j 進行token轉賬

    最近新學習了下區塊鏈這方面的知識,所學不多,給大家分享下。 # 1. 關于web3j web3j是一個高度模塊化,反應性,型別安全的Java和Android庫,用于與智能合約配合并與以太坊網路上的客戶端(節點)集成。 # 2. 準備作業 jdk版本1.8 引入maven <dependency> < ......

    uj5u.com 2020-09-10 03:03:06 more
  • 以太坊智能合約開發框架Truffle

    前言 部署智能合約有多種方式,命令列的瀏覽器的渠道都有,但往往跟我們程式員的風格不太相符,因為我們習慣了在IDE里寫了代碼然后打包運行看效果。 雖然現在IDE中已經存在了Solidity插件,可以撰寫智能合約,但是部署智能合約卻要另走他路,沒辦法進行一個快捷的部署與測驗。 如果團隊管理的區塊節點多、 ......

    uj5u.com 2020-09-10 03:03:12 more
  • 谷歌二次驗證碼成為區塊鏈專用安全碼,你怎么看?

    前言 谷歌身份驗證器,前些年大家都比較陌生,但隨著國內互聯網安全的加強,它越來越多地出現在大家的視野中。 比較廣泛接觸的人群是國際3A游戲愛好者,游戲盜號現象嚴重+國外賬號安全應用廣泛,這類游戲一般都會要求用戶系結名為“兩步驗證”、“雙重驗證”等,平臺一般都推薦用谷歌身份驗證器。 后來區塊鏈業務風靡 ......

    uj5u.com 2020-09-10 03:03:17 more
  • 密碼學DAY1

    目錄 ##1.1 密碼學基本概念 密碼在我們的生活中有著重要的作用,那么密碼究竟來自何方,為何會產生呢? 密碼學是網路安全、資訊安全、區塊鏈等產品的基礎,常見的非對稱加密、對稱加密、散列函式等,都屬于密碼學范疇。 密碼學有數千年的歷史,從最開始的替換法到如今的非對稱加密演算法,經歷了古典密碼學,近代密 ......

    uj5u.com 2020-09-10 03:03:50 more
  • 密碼學DAY1_02

    目錄 ##1.1 ASCII編碼 ASCII(American Standard Code for Information Interchange,美國資訊交換標準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際標準ISO/IE ......

    uj5u.com 2020-09-10 03:04:50 more
  • 密碼學DAY2

    ##1.1 加密模式 加密模式:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html ECB ECB : Electronic codebook, 電子密碼本. 需要加密的訊息按照塊密碼的塊大小被分為數個塊,并對每個塊進 ......

    uj5u.com 2020-09-10 03:05:42 more
  • NTP時鐘服務器的特點(京準電子)

    NTP時鐘服務器的特點(京準電子) NTP時鐘服務器的特點(京準電子) 京準電子官V——ahjzsz 首先對時間同步進行了背景介紹,然后討論了不同的時間同步網路技術,最后指出了建立全球或區域時間同步網存在的問題。 一、概 述 在通信領域,“同步”概念是指頻率的同步,即網路各個節點的時鐘頻率和相位同步 ......

    uj5u.com 2020-09-10 03:05:47 more
  • 標準化考場時鐘同步系統推進智能化校園建設

    標準化考場時鐘同步系統推進智能化校園建設 標準化考場時鐘同步系統推進智能化校園建設 安徽京準電子科技官微——ahjzsz 一、背景概述隨著教育事業的快速發展,學校建設如雨后春筍,隨之而來的學校教育、管理、安全方面的問題成了學校管理人員面臨的最大的挑戰,這些問題同時也是學生家長所擔心的。為了讓學生有更 ......

    uj5u.com 2020-09-10 03:05:51 more
  • 位元幣入門

    引言 位元幣基本結構 位元幣基礎知識 1)哈希演算法 2)非對稱加密技術 3)數字簽名 4)MerkleTree 5)哪有位元幣,有的是UTXO 6)位元幣挖礦與共識 7)區塊驗證(共識) 總結 引言 上一篇我們已經知道了什么是區塊鏈,此篇說一下區塊鏈的第一個應用——位元幣。其實先有位元幣,后有的區塊 ......

    uj5u.com 2020-09-10 03:06:15 more
  • 北斗對時服務器(北斗對時設備)電力系統應用

    北斗對時服務器(北斗對時設備)電力系統應用 北斗對時服務器(北斗對時設備)電力系統應用 京準電子科技官微(ahjzsz) 中國北斗衛星導航系統(英文名稱:BeiDou Navigation Satellite System,簡稱BDS),因為是目前世界范圍內唯一可以大面積提供免費定位服務的系統,所以 ......

    uj5u.com 2020-09-10 03:06:20 more
最新发布
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:46:47 more
  • Hyperledger Fabric 使用 CouchDB 和復雜智能合約開發

    在上個實驗中,我們已經實作了簡單智能合約實作及客戶端開發,但該實驗中智能合約只有基礎的增刪改查功能,且其中的資料管理功能與傳統 MySQL 比相差甚遠。本文將在前面實驗的基礎上,將 Hyperledger Fabric 的默認資料庫支持 LevelDB 改為 CouchDB 模式,以實作更復雜的資料... ......

    uj5u.com 2023-04-16 07:28:31 more
  • .NET Core 波場鏈離線簽名、廣播交易(發送 TRX和USDT)筆記

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. PM> Install-Package Tron.Wallet.Net 配置 public reco ......

    uj5u.com 2023-04-14 08:08:00 more
  • DKP 黑客分析——不正確的代幣對比率計算

    概述: 2023 年 2 月 8 日,針對 DKP 協議的閃電貸攻擊導致該協議的用戶損失了 8 萬美元,因為 execute() 函式取決于 USDT-DKP 對中兩種代幣的余額比率。 智能合約黑客概述: 攻擊者的交易:0x0c850f,0x2d31 攻擊者地址:0xF38 利用合同:0xf34ad ......

    uj5u.com 2023-04-07 07:46:09 more
  • Defi開發簡介

    Defi開發簡介 介紹 Defi是去中心化金融的縮寫, 是一項旨在利用區塊鏈技術和智能合約創建更加開放,可訪問和透明的金融體系的運動. 這與傳統金融形成鮮明對比,傳統金融通常由少數大型銀行和金融機構控制 在Defi的世界里,用戶可以直接從他們的電腦或移動設備上訪問廣泛的金融服務,而不需要像銀行或者信 ......

    uj5u.com 2023-04-05 08:01:34 more
  • solidity簡單的ERC20代幣實作

    // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "hardhat/console.sol"; //ERC20 同質化代幣,每個代幣的本質或性質都是相同 //ETH 是原生代幣,它不是ERC20代幣, ......

    uj5u.com 2023-03-21 07:56:29 more
  • solidity 參考型別修飾符memory、calldata與storage 常量修飾符C

    在solidity語言中 參考型別修飾符(參考型別為存盤空間不固定的數值型別) memory、calldata與storage,它們只能修飾參考型別變數,比如字串、陣列、位元組等... memory 適用于方法傳參、返參或在方法體內使用,使用完就會清除掉,釋放記憶體 calldata 僅適用于方法傳參 ......

    uj5u.com 2023-03-08 07:57:54 more
  • solidity注解標簽

    在solidity語言中 注釋符為// 注解符為/* 內容*/ 或者 是 ///內容 注解中含有這幾個標簽給予我們使用 @title 一個應該描述合約/介面的標題 contract, library, interface @author 作者的名字 contract, library, interf ......

    uj5u.com 2023-03-08 07:57:49 more
  • 評價指標:相似度、GAS消耗

    【代碼注釋自動生成方法綜述】 這些評測指標主要來自機器翻譯和文本總結等研究領域,可以評估候選文本(即基于代碼注釋自動方法而生成)和參考文本(即基于手工方式而生成)的相似度. BLEU指標^[^?88^^?^]^:其全稱是bilingual evaluation understudy.該指標是最早用于 ......

    uj5u.com 2023-02-23 07:27:39 more
  • 基于NOSTR協議的“公有制”版本的Twitter,去中心化社交軟體Damus

    最近,一個幽靈,Web3的幽靈,在網路游蕩,它叫Damus,這玩意詮釋了什么叫做病毒式營銷,滑稽的是,一個Web3產品卻在Web2的產品鏈上瘋狂傳銷,各方大佬紛紛為其背書,到底發生了什么?Damus的葫蘆里,賣的是什么藥? 注冊和簡單實用 很少有什么產品在用戶注冊環節會有什么噱頭,但Damus確實出 ......

    uj5u.com 2023-02-05 06:48:39 more