Android: SQLite + ListView 实现 新闻 App

一、前言:

本项目主要是通过 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,'[email protected]',123,'洛阳')",
            "INSERT INTO user VALUES (2,'zhangsan',123,'[email protected]',123,'北京')",
            "INSERT INTO user VALUES (3,'lisi',123,'[email protected]',123,'上海')",
            "INSERT INTO user VALUES (4,'wangwu',123,'[email protected]',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就完成了,其中也还存在一些不足的地方 ,如果路过的小伙伴有疑问,或者上面的代码不够清晰,欢迎到评论区留言或者私信我,
创作不易,如果对您有帮助,可以点个赞,点个关注哦,感谢感谢!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章