一、效果图
左面是Deepin的系统监视器,右面是Android程序,当打开Eclipse时候,两个程序显示的CPU使用率和内存使用率都有明显的上升,关闭后也都有明显的下降。
二、编写服务端提供性能数据。
首先是Java检测性能,并提供http服务。这里用到个框架:oshi.hardware,可以获取到各种信息,在这里,只获取了CPU、内存使用率和内存大小,CPU核数。
private CpuInfos getCpuInfo() {
try {
SystemInfo systemInfo = new SystemInfo();
CentralProcessor processor = systemInfo.getHardware().getProcessor();
long[] prevTicks = processor.getSystemCpuLoadTicks();
TimeUnit.SECONDS.sleep(1);
long[] ticks = processor.getSystemCpuLoadTicks();
long nice = ticks[CentralProcessor.TickType.NICE.getIndex()] - prevTicks[CentralProcessor.TickType.NICE.getIndex()];
long irq = ticks[CentralProcessor.TickType.IRQ.getIndex()] - prevTicks[CentralProcessor.TickType.IRQ.getIndex()];
long softirq = ticks[CentralProcessor.TickType.SOFTIRQ.getIndex()] - prevTicks[CentralProcessor.TickType.SOFTIRQ.getIndex()];
long steal = ticks[CentralProcessor.TickType.STEAL.getIndex()] - prevTicks[CentralProcessor.TickType.STEAL.getIndex()];
long cSys = ticks[CentralProcessor.TickType.SYSTEM.getIndex()] - prevTicks[CentralProcessor.TickType.SYSTEM.getIndex()];
long user = ticks[CentralProcessor.TickType.USER.getIndex()] - prevTicks[CentralProcessor.TickType.USER.getIndex()];
long iowait = ticks[CentralProcessor.TickType.IOWAIT.getIndex()] - prevTicks[CentralProcessor.TickType.IOWAIT.getIndex()];
long idle = ticks[CentralProcessor.TickType.IDLE.getIndex()] - prevTicks[CentralProcessor.TickType.IDLE.getIndex()];
long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
return new CpuInfos(processor.getLogicalProcessorCount(),(float) (1.0-(idle * 1.0 / totalCpu)));
}catch (InterruptedException e){}
return null;
}
private MemoryInfos getMemInfo(){
SystemInfo systemInfo = new SystemInfo();
GlobalMemory memory = systemInfo.getHardware().getMemory();
//
long totalByte = memory.getTotal();
long acaliableByte = memory.getAvailable();
return new MemoryInfos(totalByte,acaliableByte,(totalByte-acaliableByte)*1.0/totalByte);
}
private SysInfos getSysInfo(){
Properties props = System.getProperties();
String osName = props.getProperty("os.name");
String osArch = props.getProperty("os.arch");
return new SysInfos(osName,osArch);
}
并封装成MemoryInfos和CpuInfos对象。
public class MemoryInfos {
private long total;
private long userTotal;
private double utilization;
public MemoryInfos(long total, long userTotal, double utilization) {
this.total = total;
this.userTotal = userTotal;
this.utilization = utilization;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public long getUserTotal() {
return userTotal;
}
public void setUserTotal(long userTotal) {
this.userTotal = userTotal;
}
public double getUtilization() {
return utilization;
}
public void setUtilization(double utilization) {
this.utilization = utilization;
}
}
public class CpuInfos {
private int logicalProcessorCount;
private float sysUtilization;
public CpuInfos(int logicalProcessorCount, float sysUtilization) {
this.logicalProcessorCount = logicalProcessorCount;
this.sysUtilization = sysUtilization;
}
public int getLogicalProcessorCount() {
return logicalProcessorCount;
}
public void setLogicalProcessorCount(int logicalProcessorCount) {
this.logicalProcessorCount = logicalProcessorCount;
}
public float getSysUtilization() {
return sysUtilization;
}
public void setSysUtilization(float sysUtilization) {
this.sysUtilization = sysUtilization;
}
}
使用com.sun.net.httpserver.HttpServer创建一个http服务,并添加一个获取信息的接口。使用fastjson转换成json数据返回给客户端。这样服务端就算编写完了。
public class MonitorHttpServer {
Logger logger= Logger.getLogger(MonitorHttpServer.class.getName());
private int port;
private HttpServer httpServer;
public MonitorHttpServer(int port) {
this.port = port;
try {
httpServer = HttpServer.create(new InetSocketAddress(port), 0);
initContext();
httpServer.start();
logger.info("服务启动成功----------------->"+port+"端口");
} catch (IOException e) {
e.printStackTrace();
}
}
private void initContext(){
httpServer.createContext("/listInfo",new PerformanceHandler());
}
}
public class PerformanceHandler implements HttpHandler {
private Performance performance =new Performance();
@Override
public void handle(HttpExchange httpExchange) throws IOException {
String result = JSON.toJSONString(performance.getInfos());
httpExchange.sendResponseHeaders(200, result.length());
OutputStream os = httpExchange.getResponseBody();
os.write(result.getBytes());
os.close();
}
}
三、Android
使用Retrofit获取到到数据,并用MPAndroidChart显示出来,其中上下翻页是使用了viewpager2。由于服务端都是提供最新的数据,Android需要一个列队保存最近几条记录,用来绘制折线图,并且这个列队大小到达指定大小时,要移除其中最先被添加进来的数据。
首先在MainActivity中初始化Retrofit,并且每隔一秒请求数据,并添加到ViewPagerAdapter中维护的列队中。
public class MainActivity extends AppCompatActivity {
private static final String TAG="MainActivity";
private ViewPager2 mViewPager;
private Retrofit mRetrofit;
private Apis mApis;
private Handler mHandler =new Handler();
private Runnable mRequestRunnable;
private ViewPagerAdapter mViewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager =findViewById(R.id.viewpager);
initRetrofit();
mRequestRunnable =new RequestRunnable();
mHandler.postDelayed(mRequestRunnable,0);
mViewPagerAdapter =new ViewPagerAdapter(this);
mViewPager.setAdapter(mViewPagerAdapter);
}
private void initRetrofit(){
mRetrofit= new Retrofit.Builder()
.baseUrl(Url.HOST)
.addConverterFactory(GsonConverterFactory.create())
.build();
mApis= mRetrofit.create(Apis.class);
}
private void addData(ComputerInfos computerInfos){
mViewPagerAdapter.put(computerInfos);
}
class RequestRunnable implements Runnable{
@Override
public void run() {
if (mHandler!=null && !isDestroyed()){
Call<ComputerInfos> computerInfosCall = mApis.listInfos();
computerInfosCall.enqueue(new Callback<ComputerInfos>() {
@Override
public void onResponse(Call<ComputerInfos> call, Response<ComputerInfos> response) {
addData(response.body());
mHandler.postDelayed(RequestRunnable.this,1000);
}
@Override
public void onFailure(Call<ComputerInfos> call, Throwable t) {
t.printStackTrace();
mHandler.postDelayed(RequestRunnable.this,1000);
}
});
}
}
}
}
其中BoundedLinkedList是自定义的,用来到达指定大小时,自动移除最先添加的记录。循环遍历列队中的数据,并且生成LineData设置到LineChart中。
public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.MyViewHolder> {
private LinkedList<CpuInfos> mCpuInfos;
private LinkedList<MemoryInfos> mMemoryInfos;
private Context mContext;
public ViewPagerAdapter(Context context) {
mContext = context;
mCpuInfos = new BoundedLinkedList<>(10);
mMemoryInfos = new BoundedLinkedList<>(10);
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Log.i("TAG", "onCreateViewHolder: ");
View view = LayoutInflater.from(mContext).inflate(R.layout.item_line_chart, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
LineChart lineChart = holder.mLineChart;
String label = position == 0 ? "CPU使用率图" : "内存使用率图";
new ChartDecorating(lineChart, label);
new ChartDecorating(holder.mPieChart, label);
if (position == 0 && mCpuInfos.size() > 0) {
List<Float> values = new ArrayList<>();
for (int i = 0; i < mCpuInfos.size(); i++) {
values.add(Float.valueOf(mCpuInfos.get(i).getSysUtilization() * 100));
}
lineChart.setData(DataManager.createLineData(values, "CPU使用率"));
float value = Float.valueOf(mCpuInfos.peekLast().getSysUtilization() * 100);
holder.mPieChart.setData(DataManager.createPieData(value));
holder.mInfos.setText("核数:" + mCpuInfos.peekLast().getLogicalProcessorCount());
} else if (position == 1 && mMemoryInfos.size() > 0) {
List<Float> values = new ArrayList<>();
for (int i = 0; i < mMemoryInfos.size(); i++) {
values.add(Float.valueOf(String.format("%.2f", mMemoryInfos.get(i).getUtilization() * 100)));
}
lineChart.setData(DataManager.createLineData(values, "内存使用率"));
float value = Float.valueOf(String.format("%.2f", mMemoryInfos.peekLast().getUtilization() * 100));
holder.mPieChart.setData(DataManager.createPieData(value));
holder.mInfos.setText("内存大小" + ByteUtils.formatByte(mMemoryInfos.peekLast().getTotal()));
}
}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return 2;
}
public void put(ComputerInfos infos) {
mMemoryInfos.offer(infos.getMemoryInfos());
mCpuInfos.offer(infos.getCpuInfos());
notifyDataSetChanged();
}
class MyViewHolder extends RecyclerView.ViewHolder {
LineChart mLineChart;
PieChart mPieChart;
TextView mInfos;
public MyViewHolder(View itemView) {
super(itemView);
this.mLineChart = (LineChart) itemView.findViewById(R.id.linechart);
this.mPieChart = (PieChart) itemView.findViewById(R.id.piechart);
this.mInfos = (TextView) itemView.findViewById(R.id.info);
}
}
}
以上代码已放入https://gitee.com/hxl495/server-performance下。