动手写一个服务器性能实时监控Android程序

一、效果图

左面是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下。

发布了42 篇原创文章 · 获赞 7 · 访问量 7736

猜你喜欢

转载自blog.csdn.net/HouXinLin_CSDN/article/details/104388728