一、前言:
本项目主要是通过 SQLite 数据库和 ListView 组件实现的一个关于查看新闻信息的 app,关于相关的知识,如果有不了解的小伙伴可以先学习一下。
二、项目流程图:
三、项目效果图:
1、首页:
2、新闻信息页:
3、信息详情页:
四、代码展示:
SQLiteDBHelper.java – 加载数据库信息
package com.example.newsqlite;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import androidx.annotation.Nullable;
/**
* A helper class to manage database creation and version management.
*
* 既然父类是一个帮助类,子类至少也是一个帮助类,而且更加强大
*
* */
public class SQLiteDBHelper extends SQLiteOpenHelper {
// 创建数据库
static final String CREATE_SQL[] = {
"CREATE TABLE news (" +
"_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"title varchar," +
"content varchar," +
"keyword varchar," +
"category varchar," +
"author INTEGER," +
"publish_time varchar" +
")",
"CREATE TABLE user (" +
"_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"name varchar," +
"password varchar," +
"email varchar," +
"phone varchar," +
"address varcher" +
")",
"INSERT INTO user VALUES (1,'admin',123,'admin@163.com',123,'洛阳')",
"INSERT INTO user VALUES (2,'zhangsan',123,'zhangsan@163.com',123,'北京')",
"INSERT INTO user VALUES (3,'lisi',123,'lisi@163.com',123,'上海')",
"INSERT INTO user VALUES (4,'wangwu',123,'wangwu@163.com',123,'深圳')"
};
// 调用父类的构造方法(便于之后进行初始化赋值)
public SQLiteDBHelper(@Nullable Context context, @Nullable String name, int version) {
super(context, name, null, version);
}
/**
* Called when the database is created for the first time. This is where the
* creation of tables and the initial population of the tables should happen.
*
* @param db The database.
*/
@Override
public void onCreate(SQLiteDatabase db) {
// 创建数据库
Log.i("sqlite_____", "create Database");
// 执行 SQL 语句
for (int i = 0; i < CREATE_SQL.length; i++) {
db.execSQL(CREATE_SQL[i]);
}
// 完成数据库的创建
Log.i("sqlite_____", "Finished Database");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
SQLiteLoginActivity.java – 登录
package com.example.newsqlite;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.example.newsqlite.R;
import com.example.newsqlite.SQLiteDBHelper;
import com.example.newsqlite.SQLiteListActivity;
/**
* 用户登录校验:
* 1、登录成功则跳转到 SQLiteListActivity。
* 2、登录失败则重新登录。
*
* */
public class SQLiteLoginActivity extends AppCompatActivity {
SQLiteDBHelper dbHelper;
EditText etUsername;
EditText etPassword;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sqlite_login);
// 创建 SQLiteDBHelper 对象,利用构造方法进行初始化赋值
dbHelper = new SQLiteDBHelper(this,"sqlite.db",1);
// 通过 id 找到 布局管理器中的 相关属性
etUsername = findViewById(R.id.etUsername);
etPassword = findViewById(R.id.etPassword);
}
// 当用户点击提交按钮时,就会到这里(单击事件)
public void onClick(View view) {
// 获取用户的用户名和密码进行验证
String username = etUsername.getText().toString();
String password = etPassword.getText().toString();
/**
* Create and/or open a database.
* */
SQLiteDatabase db = dbHelper.getReadableDatabase();
/**
*
* 查询用户信息,放回值是一个游标(结果集,遍历结果集)
*
* */
Cursor cursor = db.query("user",new String[]{"name","password"}, "name=?",new String[]{username},null,null,null,"0,1");
// 游标移动进行校验
if(cursor.moveToNext()) {
// 从数据库获取密码进行校验
String dbPassword = cursor.getString(cursor.getColumnIndex("password"));
// 关闭游标
cursor.close();
if(password.equals(dbPassword)) {
// 校验成功则跳转到 ListViewSampleAdapterActivity
Intent intent = new Intent(this, ListViewSampleAdapterActivity.class);
// 启动
startActivity(intent);
return;
}
}
// 跳转失败也要进行关闭
cursor.close();
// 跳转失败就提示用户相关的错误信息
Toast.makeText(this,"奥利给不足,输入信息有误!",Toast.LENGTH_LONG).show();
}
@Override
public void onDestroy() {
super.onDestroy();
dbHelper.close();
}
}
activity_sqlite_login.xml – 登录布局管理器
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SQLiteLoginActivity">
<LinearLayout
android:background="@drawable/button_background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="欢迎登录"
android:textSize="32sp"
android:padding="10dp"
android:textColor="#fff"
/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="150dp">
<EditText
android:id="@+id/etUsername"
android:hint="用户名/邮箱/手机号"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_background"
android:padding="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"/>
<EditText
android:id="@+id/etPassword"
android:hint="密码"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:background="@drawable/edit_background"
android:padding="20dp"
android:layout_margin="20dp"/>
<Button
android:textSize="18sp"
android:text="登录"
android:textColor="#fff"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:background="@drawable/button_background"
android:padding="20dp"
android:layout_margin="20dp"/>
<RelativeLayout
android:paddingTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="手机快速注册"
android:textSize="20sp"
android:layout_marginLeft="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:text="忘记密码"
android:textSize="20sp"
android:layout_marginRight="10dp"/>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
ListViewSampleAdapterActivity.java – 新闻首页
package com.example.newsqlite;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ListViewSampleAdapterActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.listview);
// 准备适配器中的数据
final List<Map<String,Object>> data = new ArrayList<>();
Map<String,Object> line1 = new HashMap<>();
line1.put("time","10月20日");
line1.put("description","我的项目用例图");
line1.put("langIcon",R.mipmap.u33);
data.add(line1);
Map<String,Object> line2 = new HashMap<>();
line2.put("time","10月15日");
line2.put("description","难忘清秋,心灵的旅行");
line2.put("langIcon",R.mipmap.u39);
data.add(line2);
Map<String,Object> line3 = new HashMap<>();
line3.put("time","10月2日");
line3.put("description","好吃的水煮肉,美好的记忆");
line3.put("langIcon",R.mipmap.u45);
data.add(line3);
ListView listView01 = findViewById(R.id.listView01);
// 适配器,将信息放到自定义布局管理器上上
SimpleAdapter adapter = new SimpleAdapter(
this, // 上下文
data, // 数据
R.layout.list_item_layout, // 适配器
new String[]{"time","description","langIcon"}, // 相应的属性
new int[]{R.id.time,R.id.description,R.id.langIcon} // 布局管理器对应的位置
);
// 放置适配器中的内容到 ListView 中
listView01.setAdapter(adapter);
// 根据点击的信息跳转到相应的详情页
final HashMap<String,Integer> map = new HashMap<>();
map.put("10月20日",0);
map.put("10月15日",1);
map.put("10月2日",2);
// 时间监听器,当用户点击某条新闻时就进行相应的跳转
listView01.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Map<String, Object> line = data.get(position);
find(map.get(line.get("time").toString())); //页面跳转函数参数为模拟
}
});
}
// key 作为每条信息的标识进行跳转到指定的页面
public void find(int key) {
Intent intent = new Intent(this,ContentDetailActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("key",key);
intent.putExtras(bundle);
startActivity(intent);
}
}
list_item_layout.xml --适配器中的布局管理器
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="20dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="20dp">
<ImageView
android:id="@+id/langIcon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:adjustViewBounds="true"
android:src="@mipmap/ocs" />
<RelativeLayout
android:paddingTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="语言名字"
android:textSize="24sp" />
<ImageView
android:id="@+id/langIco"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_marginTop="0dp"
android:layout_marginRight="10dp"
android:adjustViewBounds="true"
android:src="@mipmap/u35" />
</RelativeLayout>
<TextView
android:id="@+id/description"
android:textSize="24sp"
android:text="语言介绍"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
/>
</LinearLayout>
listview.xml – 放置适配器中列表项的布局管理器
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ListViewSampleAdapterActivity"
android:background="#fff">
<TextView
android:paddingTop="20dp"
android:text="小潘同学的独家新闻"
android:gravity="center"
android:background="#F0B2AF"
android:textSize="30dp"
android:textColor="#000000"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ListView
android:id="@+id/listView01"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
ContentDetailActivity.java – 内容详情页
package com.example.newsqlite;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;
import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// 内容详情
public class ContentDetailActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_content_detail);
// 获取上一个页面的信息
Bundle bundle = this.getIntent().getExtras();
Integer key = bundle.getInt("key");
// 根据 key 来加载新闻的详情信息
Map<String,Object> map = load(key);
// 获取各个组件在布局管理器中位置,然后进行填充
ImageView langIcon = findViewById(R.id.langIcon);
TextView type = findViewById(R.id.type);
TextView mood = findViewById(R.id.mood);
TextView caption = findViewById(R.id.caption);
TextView viewById = findViewById(R.id.content);
// 将对应的组件放到特定的位置
langIcon.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), (Integer) map.get("langIcons")));
type.setText((String) map.get("types"));
mood.setText((String) map.get("moods"));
caption.setText((String) map.get("captions"));
viewById.setText((String) map.get("viewByIds"));
}
public Map<String,Object> load(int key) {
List<Map<String,Object>> data = new ArrayList<>();
Map<String,Object> line1 = new HashMap<>();
line1.put("langIcons",R.mipmap.u33);
line1.put("types","项目");
line1.put("moods","By 小潘同学");
line1.put("captions","项目用例图");
line1.put("viewByIds"," 又过深秋,枯瘦的空气里总是流淌着稍许萧瑟的味道。在这个静谧且肆意的季节里,我的思绪仿若这秋季光华里被吵醒的落叶,揉着惺忪的睡眼在风的纹络里茫然地漂浮着。\n" +
" 一首落叶的礼赞,一座城市的沦落。\n" +
" 在北方这座城市里,如果仔细观察,是可以看得见季节的转换的。匆忙的路人、街角的乞讨者、穿梭不停的车流、灯火辉煌的繁华夜景,它们即使占据了城市独有的风貌,我们也可以在抬头的瞬间,寻找到秋天的身影:一片秋高气爽的天空、一缕藏在城市温暖气流里的清冷空气、一街泛着枯容却又繁花似锦的落叶,这些都像是秋天带给我们的特色菜肴,被时光煮进了城市这口精美的大锅里。");
data.add(line1);
Map<String,Object> line2 = new HashMap<>();
line2.put("langIcons",R.mipmap.u39);
line2.put("types","风景");
line2.put("moods","By 小潘");
line2.put("captions","难忘清秋,心灵的旅行");
line2.put("viewByIds"," 又过深秋,枯瘦的空气里总是流淌着稍许萧瑟的味道。在这个静谧且肆意的季节里,我的思绪仿若这秋季光华里被吵醒的落叶,揉着惺忪的睡眼在风的纹络里茫然地漂浮着。\n" +
" 一首落叶的礼赞,一座城市的沦落。\n" +
" 在北方这座城市里,如果仔细观察,是可以看得见季节的转换的。匆忙的路人、街角的乞讨者、穿梭不停的车流、灯火辉煌的繁华夜景,它们即使占据了城市独有的风貌,我们也可以在抬头的瞬间,寻找到秋天的身影:一片秋高气爽的天空、一缕藏在城市温暖气流里的清冷空气、一街泛着枯容却又繁花似锦的落叶,这些都像是秋天带给我们的特色菜肴,被时光煮进了城市这口精美的大锅里。");
data.add(line2);
Map<String,Object> line3 = new HashMap<>();
line3.put("langIcons",R.mipmap.u45);
line3.put("types","美食");
line3.put("moods","By 小潘同学");
line3.put("captions","好吃的水煮肉,美好的记忆");
line3.put("viewByIds"," 又过深秋,枯瘦的空气里总是流淌着稍许萧瑟的味道。在这个静谧且肆意的季节里,我的思绪仿若这秋季光华里被吵醒的落叶,揉着惺忪的睡眼在风的纹络里茫然地漂浮着。\n" +
" 一首落叶的礼赞,一座城市的沦落。\n" +
" 在北方这座城市里,如果仔细观察,是可以看得见季节的转换的。匆忙的路人、街角的乞讨者、穿梭不停的车流、灯火辉煌的繁华夜景,它们即使占据了城市独有的风貌,我们也可以在抬头的瞬间,寻找到秋天的身影:一片秋高气爽的天空、一缕藏在城市温暖气流里的清冷空气、一街泛着枯容却又繁花似锦的落叶,这些都像是秋天带给我们的特色菜肴,被时光煮进了城市这口精美的大锅里。");
data.add(line3);
// 将相应的信息进行传递
Map<String,Object> map = data.get(key);
return map;
}
}
activity_content_detail.xml – 内容详情页对应的布局管理器
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".ContentDetailActivity"
android:scrollbars="none"
android:background="#fff"
>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/langIcon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@mipmap/ocs" />
<RelativeLayout
android:paddingTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp">
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="风景"
android:textSize="24sp" />
<TextView
android:id="@+id/mood"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:textColor="#000000"
android:text="By 小潘同学"
android:textSize="24sp" />
</RelativeLayout>
<TextView
android:id="@+id/caption"
android:paddingTop="20dp"
android:text="难忘今秋"
android:gravity="center"
android:textSize="25dp"
android:textStyle="bold"
android:textColor="#000000"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/content"
android:padding="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#504B50"
android:singleLine = "false"
android:textScaleX="1.2"
android:lineSpacingExtra="5dp"
android:text="又过深秋,枯瘦的空气里总是流淌着稍许萧瑟的味道。在这个静谧且肆意的季节里,我的思绪仿若这秋季光华里被吵醒的落叶,揉着惺忪的睡眼在风的纹络里茫然地漂浮着。
一首落叶的礼赞,一座城市的沦落。
在北方这座城市里,如果仔细观察,是可以看得见季节的转换的。匆忙的路人、街角的乞讨者、穿梭不停的车流、灯火辉煌的繁华夜景,它们即使占据了城市独有的风貌,我们也可以在抬头的瞬间,寻找到秋天的身影:一片秋高气爽的天空、一缕藏在城市温暖气流里的清冷空气、一街泛着枯容却又繁花似锦的落叶,这些都像是秋天带给我们的特色菜肴,被时光煮进了城市这口精美的大锅里。"
android:textSize="18sp" />
</LinearLayout>
</ScrollView>
五、后记:
到此,一个简单的新闻APP就完成了,其中也还存在一些不足的地方 ,如果路过的小伙伴有疑问,或者上面的代码不够清晰,欢迎到评论区留言或者私信我,
创作不易,如果对您有帮助,可以点个赞,点个关注哦,感谢感谢!