昨天把花了很多时间把热搜界面设计出来了,今天也终于把热搜界面完成了。思想是用了异步加载数据,和java的ajax类似。获取数据就是通过一个网络请求来获得数据库的内容。具体实现效果看下图
上面三个图是用的异步加载获取的数据(进入首页即可获得数据,不用点击),三个按键是之前的测试数据。参考微博热搜和QQ热搜界面,设计成这样的,不好看。数据是从数据库里读取的4.17日阅读量最多的前50篇文章。具体了解界面看上一篇博客。
因为要通过网络获取数据,所以得需要添加访问网络的依赖
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
在res新建一个xml文件夹,新建一个network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
在AndroidManifest.xml的appliacationn里添加以下语句
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config">
这样网络请求就不会报错了。(我的网络请求出了好多错,把这两个加上就没问题了)
具体思路:通过异步请假,发送网络请求,请求数据库数据,返回json格式。因为查询的是多条,所以最后会返回的是json的数组,需要通过gson.fromJson()方法,转换成我们list数组。
代码在昨天的基础上加了很多东西,当然也有一些测试的(删除全部信息,插入等)。
New_实体类
package com.example.hotsearch;
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 New_(int priority, String title) { this.priority = priority; this.title = title; } 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; }
}
Adapter适配器
package com.example.hotsearch;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import java.util.ArrayList;
import java.util.List;public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
List<New_> allNews = new ArrayList<>();public void setAllNews(List<New_> allNews) { this.allNews = allNews; } @NonNull @Override public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); View itemViem = layoutInflater.inflate(R.layout.cell_normal, parent,false); return new MyViewHolder(itemViem); } @Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { New_ new_ = allNews.get(position); holder.textViewNumber.setText(String.valueOf(position+1)); holder.editTextTitle.setText(new_.getTitle()); holder.editTextTitle.setEnabled(false); holder.editTextTitle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); holder.textViewSearchNum.setText(new_.getPriority()+"人查询"); } @Override public int getItemCount() { return allNews.size(); } //用来管理我们新建的ConstraintLayout static class MyViewHolder extends RecyclerView.ViewHolder { TextView textViewNumber,textViewSearchNum; EditText editTextTitle; public MyViewHolder(@NonNull View itemView) { super(itemView); textViewNumber = itemView.findViewById(R.id.textViewNumber); editTextTitle = itemView.findViewById(R.id.editTextTitle); textViewSearchNum = itemView.findViewById(R.id.textViewSearchNum); } }
}
NewsDao
package com.example.hotsearch;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;import java.util.List;
@Dao
public interface NewsDao {
@Insert
public void insertNews(New_...new_s);
@Query("SElECT * FROM New_")
public LiveData<List<New_>> getAllNewsLive();
@Query("DELETE FROM New_")
public void deleteAllNews();
}
NewsDatabase(数据库)
package com.example.hotsearch;
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
@Database(entities = {New_.class},version = 1,exportSchema = false)
public abstract class NewsDatabase extends RoomDatabase {
private static NewsDatabase INSTANCE;
static synchronized NewsDatabase getDatabase(Context context){
if(INSTANCE == null){
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),NewsDatabase.class,"new_database")
.allowMainThreadQueries()
.build();
}
return INSTANCE;
}
public abstract NewsDao getNewsDao();
工程类添加了网络请假方法和内部类来实现我们的异步请求
NewsRepository
package com.example.hotsearch;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;import androidx.lifecycle.LiveData;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;public class NewsRepository {
private LiveData<List<New_>> allNews;
private NewsDao newsDao;
public NewsRepository(Context context) {
NewsDatabase wordDatabase = NewsDatabase.getDatabase(context.getApplicationContext());
newsDao = wordDatabase.getNewsDao();
allNews = newsDao.getAllNewsLive();
}public LiveData<List<New_>> getAllNews() { return allNews; } // 定义类的接口-- 插入 public void insertNews(New_...news){ new InsertAsyncTask(newsDao).execute(news); } public void deleteNews(){ new DeleteAsyncTask(newsDao).execute(); } // 插入类 static class InsertAsyncTask extends AsyncTask<New_,Void,Void> { private NewsDao newsDao; public InsertAsyncTask(NewsDao newsDao) { this.newsDao = newsDao; } // 将在主线程的工作放到后台来执行 @Override protected Void doInBackground(New_...new_s) { newsDao.insertNews(new_s); return null; } } // 删除类 static class DeleteAsyncTask extends AsyncTask<New_,Void,Void> { private NewsDao newsDao; public DeleteAsyncTask(NewsDao newsDao) { this.newsDao = newsDao; } // 将在主线程的工作放到后台来执行 @Override protected Void doInBackground(New_...new_s) { newsDao.deleteAllNews(); return null; } } // 创建一个内部类来实现 ,在实现下面内部类之前,需要自定义的Bean对象来封装处理Josn格式的数据 class NewsAsyncTask extends AsyncTask<String,Void,List<New_>>{ @Override protected List<New_> doInBackground(String... strings) { getJson(strings[0]); return null; } } public void getJson(final String address) { new Thread(new Runnable(){ @Override public void run() { HttpURLConnection connection = null; try { URL url = new URL(address); Log.d("address",address); connection=(HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setConnectTimeout(10000); connection.setReadTimeout(5000); connection.connect(); int code=connection.getResponseCode(); if(code==200){ InputStream is=connection.getInputStream(); String state = getStringFromInputStream(is); Gson gson = new Gson(); List<New_> list = gson.fromJson(state,new TypeToken<List<New_>>(){}.getType()); for (int i=0;i<50;i++){ New_ new_2 = new New_(list.get(i).getPriority(),list.get(i).getTitle()); newsDao.insertNews(new_2); } } } catch (Exception e) { e.printStackTrace(); }finally{ if(connection!=null){ connection.disconnect(); } } } }).start(); } private static String getStringFromInputStream(InputStream is) throws Exception{ ByteArrayOutputStream baos=new ByteArrayOutputStream(); byte[] buff=new byte[1024]; int len=-1; while((len=is.read(buff))!=-1){ baos.write(buff, 0, len); } is.close(); String html=baos.toString(); baos.close(); return html; }
}
NewsViewModel
package com.example.hotsearch;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;import java.util.List;
public class NewsViewModel extends AndroidViewModel {
private NewsRepository newsRepository;
public NewsViewModel(@NonNull Application application) {
super(application);
newsRepository = new NewsRepository(application);
}public LiveData<List<New_>> getAllNews() { return newsRepository.getAllNews(); } // 定义类的接口-- 插入 public void insertWords(New_...news){ newsRepository.insertNews(news); } public void deleteWords(New_...news){ newsRepository.deleteNews(); } public void getJson(String url){ newsRepository.getJson(url); }
}
MainActivity
package com.example.hotsearch;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;public class MainActivity extends AppCompatActivity {
Button buttonInsert,buttonClear,buttonNews;
NewsViewModel newsViewModel;
RecyclerView recyclerView;
MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);final String[] url = {"你要访问的网络请求地址"}; buttonInsert = findViewById(R.id.buttonInsert); buttonNews = findViewById(R.id.buttonNews); buttonClear = findViewById(R.id.button); recyclerView = findViewById(R.id.RecyclerView); myAdapter = new MyAdapter(); newsViewModel = ViewModelProviders.of(this).get(NewsViewModel.class); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(myAdapter); newsViewModel.getJson(url[0]); newsViewModel.getAllNews().observe(this, new Observer<List<New_>>() { @Override public void onChanged(List<New_> new_s) { myAdapter.setAllNews(new_s); myAdapter.notifyDataSetChanged(); } }); buttonInsert.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { New_ new_2 = new New_(400,"aaa"); newsViewModel.insertWords(new_2); } }); buttonClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { newsViewModel.deleteWords(); } });
// buttonNews.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
//
// }
// });}
}