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就完成了,其中也還存在一些不足的地方 ,如果路過的小夥伴有疑問,或者上面的代碼不夠清晰,歡迎到評論區留言或者私信我,
創作不易,如果對您有幫助,可以點個贊,點個關注哦,感謝感謝!

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