# Android服务器性能监控 **Repository Path**: hxl495/server-performance ## Basic Information - **Project Name**: Android服务器性能监控 - **Description**: Android监控Linux服务器CPU、内存状态 - **Primary Language**: Android - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2020-02-19 - **Last Updated**: 2022-09-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 一、效果图 左面是Deepin的系统监视器,右面是Android程序,当打开Eclipse时候,两个程序显示的CPU使用率和内存使用率都有明显的上升,关闭后也都有明显的下降。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200219103554135.gif) ### 二、编写服务端提供性能数据。 首先是Java检测性能,并提供http服务。这里用到个框架:oshi.hardware,可以获取到各种信息,在这里,只获取了CPU、内存使用率和内存大小,CPU核数。 ```java 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对象。 ```java 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数据返回给客户端。这样服务端就算编写完了。 ```java 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中维护的列队中。 ```java 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 computerInfosCall = mApis.listInfos(); computerInfosCall.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { addData(response.body()); mHandler.postDelayed(RequestRunnable.this,1000); } @Override public void onFailure(Call call, Throwable t) { t.printStackTrace(); mHandler.postDelayed(RequestRunnable.this,1000); } }); } } } } ``` 其中BoundedLinkedList是自定义的,用来到达指定大小时,自动移除最先添加的记录。循环遍历列队中的数据,并且生成LineData设置到LineChart中。 ```java public class ViewPagerAdapter extends RecyclerView.Adapter { private LinkedList mCpuInfos; private LinkedList 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 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 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下。