最近因为想自己做个桌面宠物所以自己研究写了些基础功能 简单设置开机启动、闹钟模块等。 做个记录贴小模块小功能整理发布出来方便有 也想做相关程序的人做个参考。
首先说一下设计思路。 我的设计是模仿手机闹钟做的。然后还做了一个整点报时的功能。
闹钟模块
我细分了设定闹钟的几种类型(设定闹钟的基本时间几点几分提醒是必须的但是 我又细分了提醒类型。 )
- 按次数提醒例如我设定 10 : 30分提醒 我可以设定3次。就会连续提醒3天。
- 按设定循环提醒同样设定 10: 30分提醒 我可以选择星期一, 星期二, 星期三。这样就每周前三天提醒。
- 按法定工作日提醒同样设定好时间以后只有 工作的日期才会提醒。
在设计的时候还做一个类似手机闹钟的再次提醒功能。如果设定闹钟的时候设定了再次响铃时间和次数,就会重复提醒。例如:设定10:30分提醒,再响间隔10分钟,再响次数为3次。会自动多创建10:40,10:50,11:00,三个闹钟,如果不需要可以手动关闭。
既然是有循环提醒的功能数据肯定是要存储的因为是比较小型的项目, 我就没有动用大型的 Sql Service 或者 Oracle 数据
库。而是选择了 SQLite。引用了两个 SQLite 的 dll 然后网上参考了一些SQLite的公共方法加上自 己应用过成中碰到的问题优化
了 SQLiteHelper 类。如果有想看的或者有需要的可以私聊我。后面我也会新开一个帖子发出来。
至于引用可以直接从 NuGet 包中添加。
这个就可以实现相关功能。相关引用的 dll 是这两个 using System.Data; using System.Data.SQLite;
有数据库做支持以后我们就要考虑数据存储的数据结构问题了。关于这个数据结构我是这么设计的:
- Guid(唯一主键)
- SettingTime(设置的提醒时间)
- RemindNumber(提醒次数)
- RemindType(提醒类型)主要是上面说的3种类型
- WhetherRemind(是否提醒)次数小于等于 0 则关闭提醒。或者设置者主动关闭,也将不在提醒。
- CreateTime (创建时间)
- Ring (铃声)
- IntervalTime(间隔响铃时间)
- Frequency(再响次数)
下面数据结构定好了。就是界面和入库,调用方法了。因为这个功能是要用在别的项目里的。所以我把大部分代码写在类里。有些地方简单封装过了。界面就简单用 winform 画了一个。所以有点简陋,甚至有点丑。
要提一下的是这里有用到一个下拉多选框,是从网上找的大佬写的工具。十分感谢!
然后设定闹钟的时候法定工作日、提醒次数和设定星期几循环3种模式是冲突的。所以选了一种剩下的控件隐藏。这都比较简单就不贴代码了。这里贴一下设定入库的代码。
//首先是 Model
#region Time Model
public class TimePlans
{
/// <summary>
/// Guid
/// </summary>
public Guid Guid { get; set; }
/// <summary>
/// 闹钟时间
/// </summary>
public DateTime SettingTime { get; set; }
/// <summary>
/// 提醒次数
/// </summary>
public int RemindNumber { get; set; }
/// <summary>
/// 提醒类型
/// </summary>
public string RemindType { get; set; }
/// <summary>
/// 是否提醒
/// </summary>
public bool WhetherRemind { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remarks { get; set; }
/// <summary>
/// 铃声
/// </summary>
public string Ring { get; set; }
/// <summary>
/// 再响间隔
/// </summary>
public int IntervalTime { get; set; }
/// <summary>
/// 再响次数
/// </summary>
public int Frequency { get; set; }
}
#endregion
/// <summary>
/// 时钟类
/// </summary>
public class TimeAbout : AuxiliaryExtensionMethod
{
SQLiteFunction sql;
FileStreamReader fsr = new FileStreamReader();
SoundPlayer sp = new System.Media.SoundPlayer();
public TimeAbout()
{
sql = new SQLiteFunction("TimingPlan");
}
/// <summary>
/// 设定时间入库
/// </summary>
/// <param name="Hour">小时</param>
/// <param name="Minute">分钟</param>
/// <param name="RemindType">提醒类型:周一 - 周日,0:工作日</param>
/// <param name="Remarks">备注</param>
/// <param name="Time">上午下午</param>
/// <param name="RemindNumber">提醒次数,-1:循环提醒</param>
/// <returns></returns>
public string AddTimingPlan(string Hour, string Minute, string RemindType = "", string Remarks = "", string Time = "上午", string Ring = "", int RemindNumber = -1, int IntervalTime = 0, int Frequency = 0)
{
if ((IsNotNull(RemindType) || RemindNumber > 0) && !(IsNotNull(RemindType) && RemindNumber > 0))
{
if (Time == "下午")
Hour = (int.Parse(Hour) + 12).ToString();
DateTime dt = DateTime.Parse(Hour + ":" + Minute);
TimePlans Tp = new TimePlans();
Tp.Guid = Guid.NewGuid();
Tp.SettingTime = dt;
Tp.RemindNumber = RemindNumber;
Tp.RemindType = RemindType;
Tp.WhetherRemind = true;
Tp.CreateTime = DateTime.Now;
Tp.Ring = Ring;
Tp.IntervalTime = IntervalTime;
Tp.Frequency = Frequency;
if (Remarks != "")
Tp.Remarks = Remarks;
try
{
if (sql.AddFunction(Tp, "TimingPlan"))
return "闹钟-设置成功!";
else
return "闹钟-设置失败!";
}
catch (Exception ex)
{
return "闹钟-入库失败!";
}
}
else
return "闹钟-设置信息有误!";
}
//这是查询闹钟列表数据的拼接代码
/// <summary>
/// 拼接闹钟列表
/// </summary>
/// <returns></returns>
public DataTable SelectTimingPlaninfo()
{
DataSet ds = sql.SelectDt("select * From TimingPlan");
DataTable TimingPlaninfo = new DataTable();
TimingPlaninfo.Columns.Add("提醒时间");
TimingPlaninfo.Columns.Add("提醒方式");
TimingPlaninfo.Columns.Add("是否提醒");
TimingPlaninfo.Columns.Add("再响间隔");
TimingPlaninfo.Columns.Add("铃声");
foreach (DataRow item in ds.Tables[0].Rows)
{
DataRow dr = TimingPlaninfo.NewRow();
dr["提醒时间"] = DateTime.Parse(item["SettingTime"].ToString()).ToShortTimeString();
if (Convert.ToInt32(item["RemindNumber"].ToString()) > 0)
dr["提醒方式"] = item["RemindNumber"].ToString() + "次";
else if (item["RemindType"].ToString() == "0")
dr["提醒方式"] = "法定节假日";
else if (item["RemindType"].ToString() != "0" && IsNotNull(item["RemindType"].ToString()))
dr["提醒方式"] = item["RemindType"].ToString();
if ((bool)item["WhetherRemind"] == true)
dr["是否提醒"] = "是";
else
dr["是否提醒"] = "否";
if ((int)item["IntervalTime"] > 0 && (int)item["Frequency"] > 0)
dr["再响间隔"] = item["IntervalTime"].ToString() + "分钟," + item["Frequency"].ToString() + "次";
if (IsNotNull(item["Ring"].ToString()))
dr["铃声"] = item["Ring"].ToString();
TimingPlaninfo.Rows.Add(dr);
}
return TimingPlaninfo;
}
#endregion
}
SQL 相关的代码
#region 数据查询
public DataSet SelectDt(string sql)
{
DataSet ds = SQLiteHelper.ExecuteDataSet(sql);
return ds;
}
#endregion
#region Model 入库
/// <summary>
/// Model 数据入库
/// </summary>
/// <param name="data"> Model </param>
/// <param name="Table">数据表名</param>
/// <param name="type">0:最后拼创建时间,1:什么都不拼</param>
/// <returns></returns>
public bool AddFunction(object data, string Table, int type = 1)
{
List<object[]> parameters = new List<object[]>();
List<object[]> strparameter = ReflectionFunction.ForeachClassProperties<object>(data);
List<object> val = new List<object>();
string sqlparameter = "";
foreach (object[] itemval in strparameter)
{
sqlparameter += itemval[0] + ",";
val.Add(itemval[1]);
}
parameters.Add(val.ToArray());
if (type == 0)
sqlparameter += "CreateTime";
if (type == 1)
sqlparameter = sqlparameter.Substring(0, sqlparameter.Length - 1);
int result = SQLiteHelper.ExecuteNonQuery(SQLiteHelper.insert(Table, sqlparameter), parameters);
if (result == 0)
{
return false;
}
else
{
return true;
}
}
#endregion
SQLHelper 相关代码
#region 数据连接地址
private static string connectionstring;
public static string ConnectionString
{
get { return connectionstring; }
set { connectionstring = value; }
}
#endregion
#region 建立连接
private static SQLiteConnection _Conn = null;
/// <summary>
/// 连接对象
/// </summary>
public static SQLiteConnection Conn
{
get
{
if (_Conn == null)
{
_Conn = new SQLiteConnection(ConnectionString);
}
return SQLiteHelper._Conn;
}
set { SQLiteHelper._Conn = value; }
}
#endregion
#region 根据查询语句和参数查询并返回 DataSet
/// <summary>
/// 查询数据集
/// </summary>
/// <param name="cn">连接.</param>
/// <param name="commandText">查询语句.</param>
/// <param name="paramList">object参数列表.</param>
/// <returns></returns>
public static DataSet ExecuteDataSet(string commandText, params object[] paramList)
{
SQLiteCommand cmd = Conn.CreateCommand();
cmd.CommandText = commandText;
if (paramList != null)
{
AttachParameters(cmd, commandText, paramList);
}
DataSet ds = new DataSet();
if (Conn.State == ConnectionState.Closed)
Conn.Open();
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
da.Fill(ds);
da.Dispose();
cmd.Dispose();
Conn.Close();
return ds;
}
#endregion
#region 添加 SQLite 数据
public static string insert(string Table_name, string parame)
{
StringBuilder strSql = new StringBuilder();
strSql.Append("insert into " + Table_name + "(");
strSql.Append(parame + ")");
strSql.Append("values (");
string[] parames = parame.Split(',');
foreach (var item in parames)
{
strSql.Append("@" + item + ",");
}
strSql.Remove(strSql.Length - 1, 1);
strSql.Append(")");
return strSql.ToString();
}
#endregion
#region 添删改-事物执行方法,返回影响的行数(自研)
/// <summary>
/// 执行ExecuteNonQuery方法
/// </summary>
/// <param name="cn">连接</param>
/// <param name="commandText">语句</param>
/// <param name="paramList">参数</param>
/// <returns></returns>
public static int ExecuteNonQuery(string commandText, List<object[]> paramList)
{
int count = 0;
if (Conn.State == ConnectionState.Closed)
Conn.Open();
SQLiteTransaction trans = Conn.BeginTransaction();
try
{
foreach (var item in paramList)
{
int result = ExecuteNonQuery(trans, commandText, item);
count += result;
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
}
finally
{
trans.Dispose();//释放事务对象
Conn.Close();
//Conn.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
}
//trans.Connection.Close();//关闭事务连接
return count;
}
#endregion
#region 添删改-事务执行方法,返回影响的行数
/// <summary>
/// 执行ExecuteNonQuery方法,带事务
/// </summary>
/// <param name="transaction">之前创建好的SQLiteTransaction对象</param>
/// <param name="commandText">语句.</param>
/// <param name="paramList">参数.</param>
/// <returns>返回影响的行数</returns>
/// <remarks>
/// 定义事务 DbTransaction trans = conn.BeginTransaction();
/// 或者:SQLiteTransaction trans = Conn.BeginTransaction();
/// 操作代码示例:
/// try
///{
/// // 连续操作记录
/// for (int i = 0; i < 1000; i++)
/// {
/// ExecuteNonQuery(trans,commandText,[] paramList);
/// }
/// trans.Commit();
///}
///catch
///{
/// trans.Rollback();
/// throw;
///}
///trans.Connection.Close();//关闭事务连接
///transaction.Dispose();//释放事务对象
/// </remarks>
public static int ExecuteNonQuery(SQLiteTransaction transaction, string commandText, params object[] paramList)
{
if (transaction == null) throw new ArgumentNullException("transaction is null");
if (transaction != null && transaction.Connection == null) throw new ArgumentException("The transaction was rolled back or committed,please provide an open transaction.", "transaction");
int result = 0;
using (IDbCommand cmd = transaction.Connection.CreateCommand())
{
cmd.CommandText = commandText;
AttachParameters((SQLiteCommand)cmd, cmd.CommandText, paramList);
if (transaction.Connection.State == ConnectionState.Closed)
transaction.Connection.Open();
result = cmd.ExecuteNonQuery();
}
return result;
}
#endregion
在 SQLHelper 中有一个网上找到的判断类型添加 SQL 参数的方法有点问题,在参数为 object null 的时候没有做判断。我处理了一下添加了相关修复
#region 增加参数到命令(自动判断类型)
/// <summary>
/// 增加参数到命令(自动判断类型)
/// </summary>
/// <param name="commandText">命令语句</param>
/// <param name="paramList">object参数列表</param>
/// <returns>返回SQLiteParameterCollection参数列表</returns>
/// <remarks>Status experimental. Regex appears to be handling most issues. Note that parameter object array must be in same ///order as parameter names appear in SQL statement.</remarks>
private static SQLiteParameterCollection AttachParameters(SQLiteCommand cmd, string commandText, params object[] paramList)
{
if (paramList == null || paramList.Length == 0) return null;
SQLiteParameterCollection coll = cmd.Parameters;
string parmString = commandText.Substring(commandText.IndexOf("@"));
// pre-process the string so always at least 1 space after a comma.
parmString = parmString.Replace(",", " ,");
// get the named parameters into a match collection
string pattern = @"(@)\S*(.*?)\b";
Regex ex = new Regex(pattern, RegexOptions.IgnoreCase);
MatchCollection mc = ex.Matches(parmString);
string[] paramNames = new string[mc.Count];
int i = 0;
foreach (Match m in mc)
{
paramNames[i] = m.Value;
i++;
}
// now let's type the parameters
int j = 0;
Type t = null;
foreach (object o in paramList)
{
if (o != null)
{
t = o.GetType();
SQLiteParameter parm = new SQLiteParameter();
switch (t.ToString())
{
case ("DBNull"):
case ("Char"):
case ("SByte"):
case ("UInt16"):
case ("UInt32"):
case ("UInt64"):
throw new SystemException("Invalid data type");
case ("System.String"):
parm.DbType = DbType.String;
parm.ParameterName = paramNames[j];
parm.Value = (string)paramList[j];
coll.Add(parm);
break;
case ("System.Byte[]"):
parm.DbType = DbType.Binary;
parm.ParameterName = paramNames[j];
parm.Value = (byte[])paramList[j];
coll.Add(parm);
break;
case ("System.Int32"):
parm.DbType = DbType.Int32;
parm.ParameterName = paramNames[j];
parm.Value = (int)paramList[j];
coll.Add(parm);
break;
case ("System.Boolean"):
parm.DbType = DbType.Boolean;
parm.ParameterName = paramNames[j];
parm.Value = (bool)paramList[j];
coll.Add(parm);
break;
case ("System.DateTime"):
parm.DbType = DbType.DateTime;
parm.ParameterName = paramNames[j];
parm.Value = Convert.ToDateTime(paramList[j]);
coll.Add(parm);
break;
case ("System.Double"):
parm.DbType = DbType.Double;
parm.ParameterName = paramNames[j];
parm.Value = Convert.ToDouble(paramList[j]);
coll.Add(parm);
break;
case ("System.Decimal"):
parm.DbType = DbType.Decimal;
parm.ParameterName = paramNames[j];
parm.Value = Convert.ToDecimal(paramList[j]);
break;
case ("System.Guid"):
parm.DbType = DbType.Guid;
parm.ParameterName = paramNames[j];
parm.Value = (System.Guid)(paramList[j]);
coll.Add(parm);
break;
case ("System.Object"):
parm.DbType = DbType.Object;
parm.ParameterName = paramNames[j];
parm.Value = paramList[j];
coll.Add(parm);
break;
default:
throw new SystemException("Value is of unknown data type");
} // end switch
}
else
{
SQLiteParameter parm = new SQLiteParameter();
parm.DbType = DbType.Object;
parm.ParameterName = paramNames[j];
parm.Value = paramList[j];
coll.Add(parm);
}
j++;
}
return coll;
}
#endregion
差不多入库的代码就这些了。中间在添加入库的时候还用到了一个反射的代码。
public class ReflectionFunction
{
/// <summary>
/// C#反射遍历对象属性
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="model">对象</param>
public static List<object[]> ForeachClassProperties<T>(T model)
{
List<object[]> stritems = new List<object[]>();
Type t = model.GetType();
PropertyInfo[] PropertyList = t.GetProperties();
foreach (PropertyInfo item in PropertyList)
{
object[] items = new object[] { item.Name, item.GetValue(model, null) };
stritems.Add(items);
}
return stritems;
}
}
还有一个判断是否为空的,都是常规代码啦。也贴一下
/// <summary>
/// 辅助扩展方法
/// </summary>
public class AuxiliaryExtensionMethod
{
#region 判断对象是否为空
//判断对象是否为空
public static bool IsNotNull(object Obj)
{
return Obj != null && Obj != DBNull.Value && !string.IsNullOrEmpty(Obj.ToString());
}
#endregion
}
以上入库的代码基本就完成了,之后是查询,并添加到提醒列表的代码,也发出来做一下参考。
SQLiteFunction sql;
FileStreamReader fsr = new FileStreamReader();
SoundPlayer sp = new System.Media.SoundPlayer();
public TimeAbout()
{
sql = new SQLiteFunction("TimingPlan");
}
#region 闹钟提醒
#region 读取数据库存储提醒时间信息
private List<object[]> lob = new List<object[]>();
public List<object[]> Lob
{
get { return lob; }
set { lob = value; }
}
#endregion
/// <summary>
/// 加载时间表中需要提醒的数据
/// </summary>
/// <returns></returns>
public bool LoadTimePlan()
{
//查询数据库,加载提醒列表
DataSet ds = sql.SelectDt("select * From TimingPlan where WhetherRemind = True");
if (ds.Tables.Count > 0)
{
List<DateTime> ldt = new List<DateTime>();
Holiday hi = new Holiday();
bool flag = hi.GetIsHolidaybitefu(DateTime.Now.ToString("yyyyMMdd"));
//通过 DateTime.Now.DayOfWeek 判断今天是星期几
string Weeks = WordConversions.ToCharacter(Convert.ToInt32(DateTime.Now.DayOfWeek).ToString());
string Sunday = ConfigurationManager.AppSettings["Sunday"];
//因为星期天 DateTime.Now.DayOfWeek 返回 0 所以要特殊处理一下。这里默认 Sunday 是星期天。
//<!--Sunday-->
//<add key="Sunday" value="星期天" />
string Week = Convert.ToInt32(DateTime.Now.DayOfWeek) < 1 ? Sunday.Substring(Sunday.Length - 1) : Weeks;
//判断当天星期几。筛选按照星期循环的数据当天是否需要提醒。
foreach (DataRow item in ds.Tables[0].Rows)
{
int IntervalTime = Convert.ToInt32(item["IntervalTime"].ToString());
int Frequency = Convert.ToInt32(item["Frequency"].ToString());
bool isflag = false;
if (IsNotNull(item["RemindType"]) && item["RemindType"].ToString() != "0" && item["RemindType"].ToString().IndexOf(Week) >= 0)
{
object[] obj = new object[] { item["Guid"].ToString(), (DateTime)item["SettingTime"], item["Ring"].ToString() };
this.Lob.Add(obj);
isflag = true;
}
if (flag)
{
if (IsNotNull(item["RemindType"]) && item["RemindType"].ToString() == "0")
{
object[] obj = new object[] { item["Guid"].ToString(), (DateTime)item["SettingTime"], item["Ring"].ToString() };
this.Lob.Add(obj);
isflag = true;
}
}
if ((int)item["RemindNumber"] > 0 && ((DateTime)item["SettingTime"]).ToString("yyyyMMdd") == DateTime.Now.ToString("yyyyMMdd"))
{
//如果是按次数提醒则在 Guid 字段处做标记。方便提醒完全部次数修改数据库
object[] obj = new object[] { item["Guid"].ToString() + "_Number", (DateTime)item["SettingTime"], item["Ring"].ToString() };
this.Lob.Add(obj);
isflag = true;
}
if (isflag == true)
{
if (IntervalTime > 0 && Frequency > 0)
{
for (int i = 0; i < Frequency; i++)
{
object[] obj = new object[] { item["Guid"].ToString(), ((DateTime)item["SettingTime"]).AddMinutes(IntervalTime), item["Ring"].ToString() };
this.Lob.Add(obj);
}
}
}
}
}
//生成列表后开启线程,循环执行提醒方法。
Thread thread = new Thread(Remind);
thread.IsBackground = true;
thread.Start();
return true;
}
/// <summary>
/// 提醒方法
/// </summary>
void Remind()
{
List<string> ldt = new List<string>();
foreach (object[] item in this.Lob)
{
ldt.Add(((DateTime)item[1]).ToShortTimeString());
}
//判断数据库中三种循环方式当天有没有闹钟
while (this.Lob.Count > 0)
{
DateTime Current = DateTime.Now;
//如果当前时间的时,分数值与列表值相等则记录,并提醒。
if (ldt.Contains(Current.ToShortTimeString()))
{
List<string> SqlKey = new List<string>();
List<object[]> RemoveKey = new List<object[]>();
string Ring = "";
foreach (object[] items in this.Lob)
{
if (((DateTime)items[1]).ToShortTimeString() == Current.ToShortTimeString())
{
if (Ring == "" && IsNotNull(items[2].ToString()))
Ring = items[2].ToString();
if (items[0].ToString().IndexOf("_Number") >= 0)
{
SqlKey.Add(items[0].ToString());
}
RemoveKey.Add(items);
}
}
//如果数据库中有设定铃声则播放铃声否则播放默认铃声
if (Ring != "")
{
sp.SoundLocation = fsr.SplicePath("voice") + @"\" + Ring;
sp.Play();
}
else
{
sp.SoundLocation = fsr.SplicePath("voice") + @"\" + ConfigurationManager.AppSettings["Ring"];
sp.Play();
}
//提醒过后的从列表中移除,知道列表中没有要提醒的则退出循环。
foreach (var item in RemoveKey)
{
this.Lob.Remove(item);
}
//如果是按次数提醒的在提醒后修改数据库次数
foreach (var item in SqlKey)
{
Guid guid = Guid.Parse(item.Substring(0, item.IndexOf("_")));
int result = SQLiteHelper.GuidUpdate(guid, "TimingPlan", "RemindNumber=RemindNumber-1");
}
//做完处理后停止运行一段时间。不重复判断浪费系统资源
Thread.Sleep(50000);
}
}
}
#endregion
整点提醒则比较简单。基本思路就是判断当前时间的分钟是否是 00 如果是则播放整点音频,也可以做一个弹框,因为我是写在类中,生成 winform 窗体和 Lable 的时候有点问题。如果大佬们知道的话求指导下。在类中生成半透明 winform 是成功的。但是生成居中 Lable 的时候只有灰色的一个 Lable 大小。我也调至居中了。但是不显示文字。背景也没有透明。不知道为什么。直接在 winform 调用是没有问题的。在类中调用就显示不对了。贴一下整点报时的代码
#region 整点报时
/// <summary>
/// 整点报时
/// </summary>
/// <returns></returns>
public bool IntegerTime(bool Switch)
{
Thread thread = new Thread(IntegerRemind);
thread.IsBackground = true;
if (Switch)
{
thread.Start(true);
if (thread.IsAlive)
return true;
else
return false;
}
else
{
thread.Start(false);
Thread.Sleep(500);
if (thread.IsAlive)
return false;
else
return true;
}
}
/// <summary>
/// 整点报时方法
/// </summary>
/// <param name="o"></param>
void IntegerRemind(object o)
{
bool flag = Convert.ToBoolean(o);
while (flag)
{
DateTime Current = DateTime.Now;
if (Current.Minute == 00)
{
int hour = Current.Hour;
sp.SoundLocation = fsr.SplicePath("voice") + @"\" + hour.ToString("000") + ".wav";
sp.Play();
Thread.Sleep(550000);
}
}
}
#endregion
在写这个帖子的时候我又把这个闹钟的模块单独提取出来作为一个项目整理了一下(之前是作为我宠物项目的一个小模块的)最后我也会上传共大家参考。项目中也用了不少东西的。自己整理的涉及到的封装类也有很多,文字转换类。文件操作类。xml读写类。反射相关方法。调用接口获取相关信息的 Web 方法等等,
这就是整个项目了。需要的可以自行下载。
https://download.csdn.net/download/qq_32468717/11615562
有需要的可以留言回复,或者私信我都可以!
完结~