一、说在前面
1、昨天完成了:
1)脱离对现成的api的依赖,自己独立爬取、处理和存储数据,实现数据初步审核去除“坏数据”。
2)在web端,自己编写自己的“api”接口,灵活的组织和传递自己所需的数据。
3)重构前三天的代码,加强了app的稳定性,(比如说:现成的api接口用个别的图片地址形式和其他大多数不同,按照统一的方法进行渲染时会出现系统崩溃的现象)。
4)新闻类别数据项展示时换用了卡片视图,是界面更加美观。
2、今天完成了:
1)历史记录的增删,展示。
3、明天的计划:
1)用户发布自己的新闻。(6h)
二、冲刺成果
可滑动删除:
三、代码
1、实体
package com.me.domain; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; @Entity public class New_ { @PrimaryKey(autoGenerate = true) private int id; // @ColumnInfo(name = "评论数量") private int commentCount; // @ColumnInfo(name = "阅读量") private int priority; // @ColumnInfo(name = "来源") private String source; // @ColumnInfo(name = "标题") private String title; // @ColumnInfo(name = "摘要") private String digest; // @ColumnInfo(name = "图片地址") private String imgsrc; // @ColumnInfo(name = "时间") private String ptime; // @ColumnInfo(name = "正文") private String zw; // @ColumnInfo(name = "类型") private String type; private Boolean history = false; public Boolean getHistory() { return history; } public void setHistory(Boolean history) { this.history = history; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getCommentCount() { return commentCount; } public void setCommentCount(int commentCount) { this.commentCount = commentCount; } public int getPriority() { return priority; } public void setPriority(int priority) { this.priority = priority; } public String getSource() { return source; } public void setSource(String source) { this.source = source; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDigest() { return digest; } public void setDigest(String digest) { this.digest = digest; } public String getImgsrc() { return imgsrc; } public void setImgsrc(String imgsrc) { this.imgsrc = imgsrc; } public String getPtime() { return ptime; } public void setPtime(String ptime) { this.ptime = ptime; } public String getZw() { return zw; } public void setZw(String zw) { this.zw = zw; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
2、dao层(接口+注解)
package com.me.dao; import androidx.lifecycle.LiveData; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.Query; import com.me.domain.New_; import java.util.List; @Dao public interface NewsDao { @Insert void insertNews(New_... new_s); @Delete void deleteNews(New_... new_); @Query("DELETE FROM New_") void deleteAllNews(); @Query("SELECT * FROM New_ ORDER BY ID DESC") LiveData<List<New_>> getAllNew_sLive(); }
3、database:
package com.me.db; import android.content.Context; import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; import com.me.dao.NewsDao; import com.me.domain.New_; @Database(entities = {New_.class},version = 1,exportSchema = false) public abstract class NewsDatabase extends RoomDatabase { private static NewsDatabase INSTANCE; public static synchronized NewsDatabase getNewsDatabase(Context context){ if( INSTANCE == null){ INSTANCE = Room.databaseBuilder(context.getApplicationContext(), NewsDatabase.class,"news_database") //.addMigrations(MIGRATION_1_2) .build(); } return INSTANCE; } public abstract NewsDao getNewsDao(); }
4、ui界面
1)数据项:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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="wrap_content" android:orientation="vertical"> <androidx.cardview.widget.CardView android:layout_marginTop="3dp" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.me.view.MyImageView android:id="@+id/iv_new" android:layout_width="0dp" android:layout_height="80dp" android:layout_margin="4dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/guideline" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_percent="0.2" /> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" android:padding="4dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="@+id/guideline" app:layout_constraintTop_toTopOf="parent">> <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="1" android:text="title" android:textSize="24dp" /> <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:maxLines="3" android:text="content" android:textSize="13dp" /> <TextView android:id="@+id/tv_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginRight="5dp" android:gravity="right" android:text="content" android:textSize="10dp" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.cardview.widget.CardView> </LinearLayout>
2)历史数据界面:
<FrameLayout 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="com.me.fragment.HistoryFragment"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/history" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
5、逻辑代码(fragment)
package com.me.fragment; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.me.ViewModel.NewsViewModel; import com.me.adapter.NewAdapter; import com.me.domain.New_; import com.me.domain.News; import com.me.news_2.R; import java.util.ArrayList; import java.util.List; /** * A simple {@link Fragment} subclass. */ public class HistoryFragment extends Fragment { private NewAdapter adapter = new NewAdapter(); private RecyclerView recyclerView; private NewsViewModel newsViewModel; private List<News> list = new ArrayList<News>(); private List<New_> list_ = new ArrayList<New_>(); public HistoryFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View inflate = inflater.inflate(R.layout.fragment_history, container, false); recyclerView = inflate.findViewById(R.id.history); return inflate; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); newsViewModel = ViewModelProviders.of(this).get(NewsViewModel.class); final LiveData<List<New_>> allNews = newsViewModel.getAllNews(); allNews.observe(requireActivity(), new Observer<List<New_>>() { @Override public void onChanged(List<New_> new_s) { list_ = new_s; Gson gson = new Gson(); String s = gson.toJson(new_s); list = gson.fromJson(s,new TypeToken<List<News>>(){}.getType()); adapter.setData(list); adapter.notifyDataSetChanged(); } }); // Toast.makeText(getContext(), allNews.isEmpty()+" ", Toast.LENGTH_SHORT).show(); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(adapter); new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.START | ItemTouchHelper.END) { @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { // New_ new_ = list_.get(viewHolder.getLayoutPosition()); // newsViewModel.deleteNews(new_); return false; } @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { New_ new_ = list_.get(viewHolder.getLayoutPosition()); newsViewModel.deleteNews(new_); } }).attachToRecyclerView(recyclerView); } }
6、适配器:
package com.me.fragment; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.lifecycle.LiveData; import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.me.ViewModel.NewsViewModel; import com.me.adapter.NewAdapter; import com.me.domain.New_; import com.me.domain.News; import com.me.news_2.R; import java.util.ArrayList; import java.util.List; /** * A simple {@link Fragment} subclass. */ public class HistoryFragment extends Fragment { private NewAdapter adapter = new NewAdapter(); private RecyclerView recyclerView; private NewsViewModel newsViewModel; private List<News> list = new ArrayList<News>(); private List<New_> list_ = new ArrayList<New_>(); public HistoryFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View inflate = inflater.inflate(R.layout.fragment_history, container, false); recyclerView = inflate.findViewById(R.id.history); return inflate; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); newsViewModel = ViewModelProviders.of(this).get(NewsViewModel.class); final LiveData<List<New_>> allNews = newsViewModel.getAllNews(); allNews.observe(requireActivity(), new Observer<List<New_>>() { @Override public void onChanged(List<New_> new_s) { list_ = new_s; Gson gson = new Gson(); String s = gson.toJson(new_s); list = gson.fromJson(s,new TypeToken<List<News>>(){}.getType()); adapter.setData(list); adapter.notifyDataSetChanged(); } }); // Toast.makeText(getContext(), allNews.isEmpty()+" ", Toast.LENGTH_SHORT).show(); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(adapter); new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.START | ItemTouchHelper.END) { @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { // New_ new_ = list_.get(viewHolder.getLayoutPosition()); // newsViewModel.deleteNews(new_); return false; } @Override public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { New_ new_ = list_.get(viewHolder.getLayoutPosition()); newsViewModel.deleteNews(new_); } }).attachToRecyclerView(recyclerView); } }