Android的备忘录demo(java)

要求

1:APK要运用到 Activity 和广播、服务 知识点

2:布局要求最优,UI不做要求

3:开发过程中,要学会使用log定位问题

4:此APK要有桌面小组件,功能入口不做要求

最终效果(登录页面用户名&密码有意写上):

MainActivity  

package com.example.memoapplication;

import static java.lang.Integer.parseInt;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;


import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;


import com.example.memoapplication.service.MemoService;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    RecyclerView recyclerView;
    private RecyclerViewAdapter recyclerViewAdapter;
    private ArrayList<String> memos = new ArrayList<>();
    private static final String TAG = "yx";
    public static final String ADD_MEMO = "com.example.myapplication.add";
    private int count = 1;
    private ArrayList<String> load;

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


        recyclerView = findViewById(R.id.recycler);
        recyclerViewAdapter = new RecyclerViewAdapter(MainActivity.this, memos);
        recyclerView.setAdapter(recyclerViewAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));

        findViewById(R.id.delAll_memo_button).setOnClickListener(this);
        findViewById(R.id.del_one_button).setOnClickListener(this);

        Log.d(TAG,"主线程线程ID:"+Thread.currentThread().getId());



        //加载历史备忘录数据
        Log.d(TAG, "开始加载历史数据");
        //开启线程  读取历史数据
        callAbleLoad callAbleLoad = new callAbleLoad();
        FutureTask<ArrayList<String>> arrayListFutureTask = new FutureTask<>(callAbleLoad);
        new Thread(arrayListFutureTask).start();
        try {
            load = arrayListFutureTask.get();
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        for (String s : load) {
            memos.add(s);
            //添加默认的分割线
            recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        }

        //若集合为不为空 则说明历史有数据    编号应该紧接历史数据
        if (!memos.isEmpty()) {
            Log.d(TAG, "编号应该紧接历史数据");
            count = parseInt(getNumber(load.get(load.size() - 1))) + 1;
        }

        //新增
        Button addMemoButton = findViewById(R.id.add_memo_button);
        addMemoButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //增加Dialog
                showAddMemoDialog();
            }
        });
    }


    //新增备忘录
    private void showAddMemoDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        final EditText input = new EditText(this);
        builder.setTitle("新增备忘录")
                .setCancelable(false)
                .setView(input)
                .setPositiveButton("新增", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //获取新增的备忘录    去除两端空白
                        String startMemo = input.getText().toString().trim();

                        //若输入为空,全是空格,提示输入为空,不添加
                        if (startMemo.replaceAll(" ", "").isEmpty()) {
                            Toast.makeText(MainActivity.this, "输入为空,添加失败!", Toast.LENGTH_SHORT).show();
                        } else {
                            String memo = count + "        " + startMemo;

                            //添加进集合
                            memos.add(memo);
                            //添加默认的分割线
                            recyclerView.addItemDecoration(new DividerItemDecoration(MainActivity.this, DividerItemDecoration.VERTICAL));

                            count++;
                            //通知数据发生更改
                            recyclerViewAdapter.notifyDataSetChanged();

                            //启动service  增加数据到文件
                            Intent intent = new Intent(MainActivity.this, MemoService.class);
                            intent.setAction(ADD_MEMO);
                            intent.putExtra("memo", memo);
                            startService(intent);
                        }
                    }
                });

        builder.setNegativeButton("取消", null);

        builder.show();
    }


    //清空所有备忘录数据
    @Override
    public void onClick(View v) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        if (v.getId() == R.id.delAll_memo_button) {
            //先查看备忘录是否有数据
            if (memos.isEmpty()) {
                Toast.makeText(MainActivity.this, "备忘录中暂无数据", Toast.LENGTH_SHORT).show();
            } else {
                builder.setTitle("警告!")
                        .setMessage("你确定要清空所有备忘录吗?")
                        .setCancelable(false)
                        .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                //清空
                                del();
                                //刷新页面
                                refresh();
                            }
                        });
                builder.setNegativeButton("取消", null);
                builder.show();
            }

        } else if (v.getId() == R.id.del_one_button) {
            //先查看备忘录是否有数据
            if (memos.isEmpty()) {
                Toast.makeText(MainActivity.this, "备忘录中暂无数据", Toast.LENGTH_SHORT).show();
            } else {
                final EditText edit = new EditText(this);
                builder.setView(edit)
                        .setTitle("删除备忘录")
                        .setMessage("请输入要删除的数据编号")
                        .setCancelable(false)
                        .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Log.d(TAG, "获取到的要删除的编号:" + edit.getText());
                                if (!memos.isEmpty()) {
                                    Log.d(TAG, "memos not null");
                                    //有无此编号的数据
                                    boolean flag = true;
                                    for (int i = 0; i < memos.size(); i++) {
                                        if (getNumber(memos.get(i)).equals(edit.getText() + "")) {
                                            //先将memos集合中的目标数据删除,再清空文件中的全部数据,再将memos中的数据写回到文件
                                            //将memos集合中的目标数据删除
                                            memos.remove(i);
                                            Log.d(TAG, "找到目标数据" + i + "            " + memos.size());
                                            //清空文件中的全部数据
                                            del();
                                            Log.d(TAG, "memos大小" + memos.size());

                                            for (int j = 0; j < memos.size(); j++) {
                                                Intent intent = new Intent(MainActivity.this, MemoService.class);
                                                intent.setAction(ADD_MEMO);
                                                intent.putExtra("memo", memos.get(j));
                                                startService(intent);
                                            }
                                            //刷新页面
                                            refresh();
                                            //找到编号数据
                                            flag = false;
                                            break;
                                        }
                                    }

                                    //若没找到此编号的数据则提示
                                    if (flag) {
                                        Toast.makeText(MainActivity.this, "输入的编号有误或不存在!", Toast.LENGTH_SHORT).show();
                                    }

                                }
                            }
                        });
                builder.setNegativeButton("取消", null);
                builder.show();
            }
        }
    }


    //创建线程读取文件中的数据 耗时操作
    class callAbleLoad implements Callable<ArrayList<String>> {

        @Override
        public ArrayList<String> call() throws Exception {
            Log.d(TAG,"callable线程ID:"+Thread.currentThread().getId());
            FileInputStream in = null;
            BufferedReader reader = null;
            ArrayList<String> list = new ArrayList<>();

            try {
                //找到名input的文件
                in = openFileInput("input");
                reader = new BufferedReader(new InputStreamReader(in));
                String line = "";
                //一行一行读取文件内容,放入ArrayList
                while ((line = reader.readLine()) != null) {
                    list.add(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            for (int i = 0; i < list.size(); i++) {
                Log.d(TAG, "读取到的第" + (i + 1) + "行数据:" + list.get(i));
            }
            return list;
        }
    }


    //清空所有备忘录数据
    private void del() {
        deleteFile("input");
    }


    //获取备忘录编号
    private String getNumber(String s) {
        int i = s.indexOf(" ");
        Log.d(TAG, "读取到的第:" + s.substring(0, i));
        return s.substring(0, i);

    }

    //刷新页面
    private void refresh() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        startActivity(intent);
    }


}

BootReceiver

package com.example.memoapplication.receiver;


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

import com.example.memoapplication.LoginActivity;

public class BootReceiver extends BroadcastReceiver {

    private static final String TAG = "yx";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.getAction().equals(LoginActivity.SEND_BROADCAST)){
            Log.d(TAG,"³É¹¦ÊÕµ½¹ã²¥");
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setTitle("¾¯¸æ!")
                    .setMessage("Õ˺ŻòÃÜÂë´íÎó£¡")
                    .setCancelable(false)
                    .setPositiveButton("OK",null);
            builder.show();
        }
    }
}

MemoService

package com.example.memoapplication.service;

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

import androidx.annotation.Nullable;

import com.example.memoapplication.MainActivity;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class MemoService extends Service {
    private static final String TAG = "yx";


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null && intent.getAction().equals(MainActivity.ADD_MEMO)) {
            String memo = intent.getStringExtra("memo");
            if (memo != null) {
                Log.d(TAG,"添加");
                // 备忘录数据保存到本地
                save(memo);
            }
        }
        return START_NOT_STICKY;
    }


    private void save(String input){
        FileOutputStream outputStream = null;
        BufferedWriter writer = null;
        try {
            outputStream = openFileOutput("input", Context.MODE_APPEND);
            writer = new  BufferedWriter(new OutputStreamWriter(outputStream));
            writer.write(input);
            writer.write("\r\n");
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            if (writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

RecyclerViewAdapter备忘录主体滚动展示

package com.example.memoapplication;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {

    Context context;
    ArrayList<String> memosList;

    public  RecyclerViewAdapter(Context context, ArrayList<String> memosList) {
        this.context = context;
        this.memosList = memosList;
    }

    @NonNull
    @Override
    public RecyclerViewAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(this.context).inflate(R.layout.recycierview_item, parent, false);

        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        holder.textView.setText(memosList.get(position));

    }

    @Override
    public int getItemCount() {
        return this.memosList.size();
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder{
        TextView textView;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.memo);
        }
    }
}

NewAppWidget 桌面小组件

package com.example.memoapplication;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;

/**
 * Implementation of App Widget functionality.
 */
public class NewAppWidget extends AppWidgetProvider {

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {

        CharSequence widgetText = context.getString(R.string.appwidget_text);
        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
        views.setTextViewText(R.id.appwidget_text, widgetText);
        Intent intent = new Intent(context, LoginActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
        views.setOnClickPendingIntent(R.id.appwidget_text,pendingIntent);


        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // There may be multiple widgets active, so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
        
    }

    @Override
    public void onEnabled(Context context) {
        // Enter relevant functionality for when the first widget is created
    }

    @Override
    public void onDisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
    }
}

Loginctivity  登录

package com.example.memoapplication;

import androidx.appcompat.app.AppCompatActivity;

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

import com.example.memoapplication.receiver.BootReceiver;

public class LoginActivity extends AppCompatActivity implements View.OnClickListener {


    public static final String SEND_BROADCAST = "com.example.myapplication.send";

    private static final String TAG = "yx";

    private EditText usernameEdit;
    private EditText passwordEdit;
    private BootReceiver bootReceiver;

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

        usernameEdit = findViewById(R.id.username);
        passwordEdit = findViewById(R.id.password);
        findViewById(R.id.login).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        String username = usernameEdit.getText().toString();
        String password = passwordEdit.getText().toString();
        if (username.equals("1") && password.equals("1")){
            Log.d(TAG,"账号密码验证通过");
            Intent intent = new Intent(this, MainActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }else {
            Log.d(TAG,"账号密码验证失败,,发送广播,警告弹窗!");
            Intent intent = new Intent(SEND_BROADCAST);
            sendBroadcast(intent);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG,"广播注册");
        bootReceiver = new BootReceiver();
        IntentFilter filter = new IntentFilter(SEND_BROADCAST);
        registerReceiver(bootReceiver,filter);
    }


    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG,"广播注销");
        unregisterReceiver(bootReceiver);
    }
}

布局文件:

activity_main.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">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="25dp"
        android:text="备忘录"
        android:gravity="center"
        android:textSize="20sp"
        android:textStyle="bold"
        android:background="#b9b900"
        android:textColor="@color/white"
        tools:ignore="MissingConstraints" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:layout_marginStart="10dp"
        android:layout_marginTop="30dp"
        android:layout_marginEnd="10dp"
        android:layout_marginBottom="60dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />





    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:ignore="MissingConstraints"
        android:paddingTop="680dp">

        <Button
            android:id="@+id/delAll_memo_button"
            android:layout_height="wrap_content"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:textColor="#f81c00"
            android:textSize="17sp"
            android:textStyle="bold"
            android:text="清空所有" />

        <Button
            android:id="@+id/del_one_button"
            android:layout_height="wrap_content"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:textColor="#fdff26"
            android:textSize="17sp"
            android:textStyle="bold"
            android:text="删除" />

        <Button
            android:id="@+id/add_memo_button"
            android:layout_height="wrap_content"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:textColor="#00f10a"
            android:textSize="17sp"
            android:textStyle="bold"
            android:text="新增" />
    </LinearLayout>



</androidx.constraintlayout.widget.ConstraintLayout>

recycierview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:background="@drawable/item_background"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="10dp">


    <TextView
        android:id="@+id/memo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="20sp" />

</LinearLayout>

new_app_widget.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/Widget.MemoApplication.AppWidget.Container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:theme="@style/Theme.MemoApplication.AppWidgetContainer">

    <TextView
        android:id="@+id/appwidget_text"
        style="@style/Widget.MemoApplication.AppWidget.InnerView"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_margin="8dp"
        android:contentDescription="@string/appwidget_text"
        android:text="@string/appwidget_text"
        android:textSize="24sp"
        android:textStyle="bold|italic" />
</RelativeLayout>

activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LoginActivity"
    android:orientation="vertical"
    android:paddingTop="100dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="登录备忘录"
        android:gravity="center"
        android:textSize="25sp"/>


    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:paddingRight="25dp">

        <TextView
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="用户名:"
            android:paddingLeft="25dp"/>

        <EditText
            android:id="@+id/username"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>


    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:paddingRight="25dp">

        <TextView
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:textSize="18sp"
            android:text="密    码:"
            android:paddingLeft="25dp"/>

        <EditText
            android:id="@+id/password"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"
            android:inputType="textPassword"/>
    </LinearLayout>

    <Button
        android:id="@+id/login"
        android:layout_width="200dp"
        android:layout_height="60dp"
        android:text="登    录"
        android:layout_gravity="center"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="用户名:1      密码:1"
        android:gravity="center"/>

</LinearLayout>

drawable/item_background.xml

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

    <solid android:color="#ffc10e"/>

    <corners android:radius="4dp"/>

</shape>

总结:

主要功能:登录备忘录、历史备忘录展示、展示台滚动、新增备忘录、删除指定编号备忘录,清空所有备忘录、不允许新增空文本、桌面小组件

运用知识:Activity、Broadcast、Service、RecyclerView、文件的读取和写入、Callable、字符串的操作、AlertDialog、Widge

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薅你一根头发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值