Android线程与Sqlite
前言
👨💻👨🌾📝记录学习成果,以便温故而知新
项目目录
一、线程
(1)Handler
安卓的线程中有耗时长的操作,在操作完成后需要操作界面,就用到Handler来操作界面,代码如下
new Thread(() -> {
Log.i(getClass().getName(), "Thread start");
postMsg("Thread start");
try {
Thread.sleep(30*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(getClass().getName(), "Thread end");
postMsg("Thread end");
}).start();
private void postMsg(String content) {
Bundle bundle = new Bundle();
bundle.putString("msg", content);
Message msg = new Message();
msg.setData(bundle);
msgHandler.sendMessage(msg);
}
Handler msgHandler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String content = bundle.getString("msg");
Toast.makeText(ThreadActivity.this, content, Toast.LENGTH_SHORT).show();
}
};
(2)代码ThreadActivity、activity_thread
package cn.fy.sqlite.activity;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import cn.fy.sqlite.databinding.ActivityMainBinding;
import cn.fy.sqlite.databinding.ActivityThreadBinding;
public class ThreadActivity extends AppCompatActivity {
private ActivityThreadBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_thread);
binding = ActivityThreadBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("线程");
/**
* 线程操作界面需要用Handler
*/
binding.btnStartThread.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(() -> {
Log.i(getClass().getName(), "Thread start");
postMsg("Thread start");
try {
Thread.sleep(30*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(getClass().getName(), "Thread end");
postMsg("Thread end");
}).start();
}
});
/**
* 线程操作界面不用Handler出错
*/
binding.btnStartThreadError.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread(() -> {
Log.i(getClass().getName(), "Thread start");
Toast.makeText(ThreadActivity.this, "Thread start", Toast.LENGTH_SHORT).show();
try {
Thread.sleep(30*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(getClass().getName(), "Thread end");
Toast.makeText(ThreadActivity.this, "Thread end", Toast.LENGTH_SHORT).show();
}).start();
}
});
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
private void postMsg(String content) {
Bundle bundle = new Bundle();
bundle.putString("msg", content);
Message msg = new Message();
msg.setData(bundle);
msgHandler.sendMessage(msg);
}
Handler msgHandler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String content = bundle.getString("msg");
Toast.makeText(ThreadActivity.this, content, Toast.LENGTH_SHORT).show();
}
};
}
<?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"
tools:context=".activity.ThreadActivity">
<Button
android:id="@+id/btn_start_thread"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="60dp"
android:text="开始线程"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_start_thread_error"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="60dp"
android:text="线程出错示例"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_start_thread" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.Sqlite
实现Sqlite的增删改查
由于Sqlite是本机数据库,延时很小,为了演示效果,就没有对数据库操作后刷新界面做Handler封装
(1)SQLite
工具类
package cn.fy.sqlite.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class SQLite extends SQLiteOpenHelper {
public SQLite(Context context) {
super(context, "SQL.db", null, 1);
//第一个参数对应的是一个上下文,第二个参数对应的是数据库的名称,第三个参数一般为空就好了,第四个参数对应的是数据库的版本号默认为一就好了
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
Log.i(getClass().getName(), "onCreate");
//删除表
String sql = "drop table if exists user;";
sqLiteDatabase.execSQL(sql);
//创建表
sql = "create table user(ID INTEGER PRIMARY KEY AUTOINCREMENT, name varchar(30), age Integer )";
//创建一个表,表的名称叫user这里面会有四个字段,Integer是整形,varchar数据量的大小是根据后面括号进行变化
sqLiteDatabase.execSQL(sql);
Log.i(getClass().getName(), sql);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
(2)User
模型
package cn.fy.sqlite.model;
public class User {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
(3)DAO
package cn.fy.sqlite.dao;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.widget.Toast;
import java.util.ArrayList;
import cn.fy.sqlite.db.SQLite;
import cn.fy.sqlite.model.User;
public class UserDao {
private SQLiteDatabase database;
public UserDao(Context context) {
SQLite sqLite = new SQLite(context);//实例化对象,对象为初始创建的名称
database = sqLite.getWritableDatabase();//读写操作
}
public void addUser(User user) {
String sql = "insert into user(name, age) values(?, ?)";
database.execSQL(sql, new Object[]{ user.getName(), user.getAge() });
}
public void updateUser(User user) {
String sql = "update user set name=?, age=? where ID=?";//通过查询编号进行修改
database.execSQL(sql, new Object[]{ user.getName(), user.getAge(), user.getId() });
}
public void delUser(User user) {
String sql="delete from user where ID=?";
database.execSQL(sql, new Object[]{ user.getId() });
}
public ArrayList<User> queryUser(User user) {
ArrayList<User> userList = new ArrayList<>();
String sql = "select * from user";//查询字段名称number
Cursor cursor = database.rawQuery(sql, null);//获取一个游标
while(cursor.moveToNext()) {//判断是否可以移动到下一行
//获取这一行名称的数据,对应的是添加时的字段(列名称)
int id = cursor.getInt(cursor.getColumnIndexOrThrow("ID"));
String name = cursor.getString(cursor.getColumnIndexOrThrow("name"));
int age = cursor.getInt(cursor.getColumnIndexOrThrow("age"));
User u = new User();
u.setId(id);
u.setName(name);
u.setAge(age);
userList.add(u);
}
return userList;
}
}
(4)Adapter
在UserAdapter实现修改与删除
package cn.fy.sqlite.adapter;
import android.content.Context;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import java.util.ArrayList;
import cn.fy.sqlite.R;
import cn.fy.sqlite.activity.SqliteActivity;
import cn.fy.sqlite.dao.UserDao;
import cn.fy.sqlite.model.User;
public class UserAdapter extends BaseAdapter {
private Context context;
private LayoutInflater layoutInflater;
private UserDao userDao;
ArrayList<User> userList;
public UserAdapter(Context context, ArrayList<User> userList) {
this.context = context;
layoutInflater = LayoutInflater.from(context);
this.userList = userList;
userDao = new UserDao(context);
}
@Override
public int getCount() {
return userList!=null ? userList.size() : 0;
}
@Override
public Object getItem(int i) {
return userList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = layoutInflater.inflate(R.layout.layout_user_list_item, null);
TextView id = view.findViewById(R.id.txt_id);
TextView name = view.findViewById(R.id.txt_name);
TextView age = view.findViewById(R.id.txt_age);
User user = (User)getItem(i);
id.setText(user.getId() + "");
name.setText(user.getName());
age.setText(user.getAge() + "");
Button b1 = view.findViewById(R.id.btn_update_user);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AlertDialog.Builder customizeDialog = new AlertDialog.Builder(context);
final View dialogView = LayoutInflater.from(context).inflate(R.layout.layout_user_dialog, null);
EditText name1 = (EditText) dialogView.findViewById(R.id.txt_dialog_name);
name1.setText(user.getName());
EditText age1 = (EditText) dialogView.findViewById(R.id.txt_dialog_age);
age1.setText(user.getAge() + "");
customizeDialog.setTitle("修改用户");
customizeDialog.setView(dialogView);
customizeDialog.setNegativeButton("取消", null);
customizeDialog.setPositiveButton("确定",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 获取EditView中的输入内容
EditText name = (EditText) dialogView.findViewById(R.id.txt_dialog_name);
EditText age = (EditText) dialogView.findViewById(R.id.txt_dialog_age);
User u = new User();
u.setId(user.getId());
u.setName(name.getText().toString());
u.setAge(Integer.parseInt(age.getText().toString()));
userDao.updateUser(u);
((SqliteActivity)context).refreshListView();
Toast.makeText(context, "修改用户成功", Toast.LENGTH_SHORT).show();
}
});
customizeDialog.show();
}
});
Button b2 = view.findViewById(R.id.btn_del_user);
b2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final AlertDialog.Builder normalDialog = new AlertDialog.Builder(context);
normalDialog.setTitle("删除用户");
normalDialog.setMessage("请确认" );
normalDialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
userDao.delUser(user);
((SqliteActivity)context).refreshListView();
Toast.makeText(context, "删除用户成功", Toast.LENGTH_SHORT).show();
}
});
normalDialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
// 显示
normalDialog.show();
}
});
return view;
}
}
(5)Activity
新增在Activity中实现
package cn.fy.sqlite.activity;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.util.ArrayList;
import cn.fy.sqlite.R;
import cn.fy.sqlite.adapter.UserAdapter;
import cn.fy.sqlite.dao.UserDao;
import cn.fy.sqlite.databinding.ActivitySqliteBinding;
import cn.fy.sqlite.databinding.ActivityThreadBinding;
import cn.fy.sqlite.model.User;
public class SqliteActivity extends AppCompatActivity {
private ActivitySqliteBinding binding;
private UserDao userDao;
ArrayList<User> userList;
UserAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_sqlite);
binding = ActivitySqliteBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("Sqlite");
userDao = new UserDao(SqliteActivity.this);
userList = userDao.queryUser(new User());
adapter = new UserAdapter(SqliteActivity.this, userList);
binding.listView.setAdapter(adapter);
binding.btnAddUser.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showAddUserDialog();
}
});
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
private void showAddUserDialog() {
AlertDialog.Builder customizeDialog = new AlertDialog.Builder(SqliteActivity.this);
final View dialogView = LayoutInflater.from(SqliteActivity.this).inflate(R.layout.layout_user_dialog, null);
customizeDialog.setTitle("新增用户");
customizeDialog.setView(dialogView);
customizeDialog.setNegativeButton("取消", null);
customizeDialog.setPositiveButton("确定",new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 获取EditView中的输入内容
EditText name = (EditText) dialogView.findViewById(R.id.txt_dialog_name);
EditText age = (EditText) dialogView.findViewById(R.id.txt_dialog_age);
User user = new User();
user.setName(name.getText().toString());
user.setAge(Integer.parseInt(age.getText().toString()));
userDao.addUser(user);
refreshListView();
Toast.makeText(SqliteActivity.this, "新增用户成功", Toast.LENGTH_SHORT).show();
}
});
customizeDialog.show();
}
public void refreshListView() {
userList = userDao.queryUser(new User());
adapter = new UserAdapter(SqliteActivity.this, userList);
binding.listView.setAdapter(adapter);
}
}
(6)activity_sqlite
<?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"
tools:context=".activity.SqliteActivity">
<Button
android:id="@+id/btn_add_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="新增"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/divider"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="1dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="1dp"
android:background="?android:attr/listDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_add_user" />
<ListView
android:id="@+id/list_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="2dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="2dp"
android:layout_marginBottom="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider" />
</androidx.constraintlayout.widget.ConstraintLayout>
(7)layout_user_list_item
ListView布局文件
<?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">
<TextView
android:id="@+id/txt_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:id="@+id/txt_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:id="@+id/txt_age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btn_update_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_weight="1"
android:text="修改" />
<Button
android:id="@+id/btn_del_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_weight="1"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:text="删除" />
</LinearLayout>
</LinearLayout>
(8)layout_user_dialog
新增修改对话框布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/txt_dialog_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="姓名"
android:text="" />
<EditText
android:id="@+id/txt_dialog_age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="年龄"
android:minHeight="48dp" />
</LinearLayout>
4.MainActivity
package cn.fy.sqlite;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import cn.fy.sqlite.activity.SqliteActivity;
import cn.fy.sqlite.activity.ThreadActivity;
import cn.fy.sqlite.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.btnThread.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, ThreadActivity.class);
startActivity(intent);
}
});
binding.btnSqlite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, SqliteActivity.class);
startActivity(intent);
}
});
}
}
<?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"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_thread"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="60dp"
android:text="线程"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn_sqlite"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="60dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="60dp"
android:text="Sqlite"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_thread" />
</androidx.constraintlayout.widget.ConstraintLayout>
5.AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCode">
<activity
android:name=".activity.SqliteActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".activity.ThreadActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest>