Android

时间:2016-03-22 02:29:21

标签: java android multithreading optimization

我有一个简单的活动,需要活动10-15分钟。该活动使用TelephonyManager获取三个LTE参数:RSRP,RSRQ,PCI。它每秒收集这三个参数和一个时间戳,因此,UI每秒更新一次。

用于获取LTE参数的方法在后台线程上运行。除了UI每秒更新一次,没有什么是计算密集型的。但是,如果我运行活动超过五分钟,那么我会收到可爱的Android Monitor消息:" I / Choreographer:跳过91帧!应用程序可能在其主线程上做了太多工作。"

所以我必须做错事,因为我相信我在后台线程上做了所有艰苦的工作。如果我运行活动10-15分钟,它将跳过约1,000帧。然后,如果我通过应用程序并按下按钮运行另一个测试,它将开始跳过与前15分钟测试结束时一样多的帧,并且在第二个测试结束时它可以跳过多达2500个帧。然后每次按下按钮开始下一个活动时需要更长更长的时间(即使在没有完成任何操作的活动中)。而且只有五项活动!

以下是我需要在15分钟内有效收集数据的活动的屏幕截图:

screenshot1

和相应的Android Monitor日志: screenshot2

以下是我的名为Third.java的活动代码:

package com.parksjg.its.pscrindoortesttool;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.CellInfo;
import android.telephony.CellInfoLte;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import au.com.bytecode.opencsv.CSVWriter;

/**
 * Created by josephparks on 1/27/16.
 */
public class Third extends Activity implements Runnable {

    SignalStrengthListener signalStrengthListener;
    TextView lteRsrp;
    TextView lteRsrq;
    TextView cellPciTextView, fileName;
    ImageView img;
    Button stopButton;

    TelephonyManager tm;
    List<CellInfo> cellInfoList;
    String lte1, lte2;
    int cellPci = 0;

    ArrayList data;
    CSVWriter writer;
    String mydate;
    String startDate;
    boolean done = false;


    @Override
    public void run() {
        // Moves the current Thread into the background
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

        // This runs the code to grab the LTE parameters
        startTele();

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.third_activity);

        // Sets up the TextViews and UI
        setupUI();
        // Runs telephony method on background thread
        run();
        // takes the collected data and adds it to the CSV format once per second
        setupCSV();
        // Sets up the stop button, writes data to CSV, and starts next activity
        setupButton();

    }

    // This method is called by startTele() and is responsible for grabbing the LTE params 
    private class SignalStrengthListener extends PhoneStateListener {
        @Override
        public void onSignalStrengthsChanged(android.telephony.SignalStrength signalStrength) {

            ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).listen(signalStrengthListener, SignalStrengthListener.LISTEN_SIGNAL_STRENGTHS);

            tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

            String ltestr = signalStrength.toString();
            String[] parts = ltestr.split(" ");
            lte1 = parts[9];
            lte2 = parts[10];

            try {
                cellInfoList = tm.getAllCellInfo();
                for (CellInfo cellInfo : cellInfoList) {
                    if (cellInfo instanceof CellInfoLte) {
                        // cast to CellInfoLte and call all the CellInfoLte methods you need
                        // Gets the LTE PCI: (returns Physical Cell Id 0..503, Integer.MAX_VALUE if unknown)
                        cellPci = ((CellInfoLte) cellInfo).getCellIdentity().getPci();
                    }
                }
            } catch (Exception e) {
//                Log.d("SignalStrength", "+++++++++++++++++++++++++++++++ null array spot 3: " + e);
            }

            // Gets the timestamp of when these LTE params where collected
            mydate = java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());

            // Updates the UI TextViews for RSRP, RSRQ, and PCI
            lteRsrp.setText(String.valueOf(lte1));
            lteRsrq.setText(String.valueOf(lte2));
            cellPciTextView.setText(String.valueOf(cellPci));

            super.onSignalStrengthsChanged(signalStrength);

        }
    }

    // This takes the collected LTE data and timestamps and concatenates them into one object
    // which is then easy to create a CSV file from
    private void setupCSV() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                data.add(new String[]{mydate, lte1, lte2, String.valueOf(cellPci)});
            }
        }, 0, 1000);//put here time 1000 milliseconds=1 second

    }

    private void setupUI () {

        data = new ArrayList();

        // startDate is used to name the CSV file
        startDate = java.text.DateFormat.getDateTimeInstance().format(Calendar.getInstance().getTime());

        lteRsrp = (TextView) findViewById(R.id.lteRsrp);
        lteRsrq = (TextView) findViewById(R.id.lteRsrq);
        cellPciTextView = (TextView) findViewById(R.id.cellPciTextView);
        fileName = (TextView) findViewById(R.id.fileName);
        fileName.setText(startDate);
        stopButton = (Button) findViewById(R.id.stopButton);

        img = (ImageView) findViewById(R.id.imageView);
        img.setImageResource(R.drawable.recording);

//        Log.d("Time and Date", "+++++++++++++ DATE : " + mydate);

    }

    private void startTele() {
        // start the signal strength listener
        signalStrengthListener = new SignalStrengthListener();

        ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).listen(signalStrengthListener, SignalStrengthListener.LISTEN_SIGNAL_STRENGTHS);
        tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

        try {
            cellInfoList = tm.getAllCellInfo();
        } catch (Exception e) {
//            Log.d("SignalStrength", "+++++++++++++++++++++++++++++++++++++++++ null array spot 1: " + e);

        }

    }

    private void setupButton() {
        stopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Toast.makeText(Third.this, "Writing output to CSV!", Toast.LENGTH_LONG).show();

                // Writes the data to a CSV file named by startDate
                writeCSV();

                try{
                    if(signalStrengthListener != null) {
                        tm.listen(signalStrengthListener, SignalStrengthListener.LISTEN_NONE);
//                        Log.d("TAG", "+++++++++++++++++++++++++++++++++++ Stop button Success!!!!!!");
                    }
                }catch(Exception e){
                    e.printStackTrace();
//                    Log.d("TAG", "+++++++++++++++++++++++++++++++++++ Stop button Fail!!!!!! with error = " + e);
                }

                // Intent passes startDate and the boolean done to indicate when the CSV has been written
                Intent intent = new Intent(getBaseContext(), Fourth.class);
                intent.putExtra("START_DATE", startDate);
                intent.putExtra("DONE", done);
                startActivity(intent);
                finish();

            }
        });

    }

    private void writeCSV() {

        try {
            File file = new File(getExternalFilesDir(null), startDate+".csv");
            writer = new CSVWriter(new FileWriter(file, true), ',');
            // Headers
            String[] headers = "Time, RSRP, RSRQ, PCI".split(",");
            writer.writeNext(headers);
            writer.writeAll(data);
            writer.flush();
            writer.close();
            Toast.makeText(Third.this, "CSV Successful!", Toast.LENGTH_SHORT).show();
            done = true;
//                    Log.d("CSV Writer", "CSV Writer Successful!");

        } catch (IOException e) {
//            Log.d("CSV Writer", "Error writing CSV file : " + e);
            Toast.makeText(Third.this, "Error writing CSV file", Toast.LENGTH_SHORT).show();
        }

    }

}

以下是名为third_activity.xml的相应XML:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffdc1d">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Recording"
        android:textSize="26sp"
        android:textColor="#000000"
        android:id="@+id/lteRecording"
        android:layout_alignParentTop="true"
        android:textAlignment="center"
        android:background="#f91616"
        android:textStyle="bold"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp" />

    <TextView
        android:layout_width="210dp"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="22sp"
        android:textColor="#000000"
        android:id="@+id/lteRsrp"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true"
        android:layout_marginStart="29dp"
        android:layout_marginTop="120dp"
        android:textAlignment="textEnd"
        android:background="#ffdc1d"
        android:textStyle="bold" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="= LTE RSRP"
        android:textSize="22sp"
        android:textColor="#000000"
        android:id="@+id/textView2"
        android:background="#ffdc1d"
        android:textStyle="bold"
        android:layout_alignTop="@+id/lteRsrp"
        android:layout_toEndOf="@+id/stopButton" />

    <TextView
        android:layout_width="210dp"
        android:layout_height="wrap_content"
        android:text="0"
        android:textColor="#a71b1b"
        android:textSize="22sp"
        android:id="@+id/lteRsrq"
        android:layout_below="@+id/lteRsrp"
        android:layout_alignStart="@+id/lteRsrp"
        android:textAlignment="textEnd"
        android:textStyle="bold"
        android:background="#ffdc1d"
        android:layout_marginTop="20dp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="= LTE RSRQ"
        android:textSize="22sp"
        android:textColor="#a71b1b"
        android:id="@+id/textView3"
        android:layout_below="@+id/textView2"
        android:layout_alignStart="@+id/textView2"
        android:textStyle="bold"
        android:background="#ffdc1d"
        android:layout_marginTop="20dp" />

    <TextView
        android:layout_width="210dp"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="22sp"
        android:textColor="#075f09"
        android:id="@+id/cellPciTextView"
        android:layout_below="@+id/lteRsrq"
        android:layout_alignStart="@+id/lteRsrq"
        android:textAlignment="textEnd"
        android:background="#ffdc1d"
        android:textStyle="bold"
        android:layout_marginTop="20dp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="= LTE PCI"
        android:textSize="22sp"
        android:textColor="#075f09"
        android:id="@+id/textView4"
        android:layout_below="@+id/textView3"
        android:layout_alignStart="@+id/textView3"
        android:background="#ffdc1d"
        android:textStyle="bold"
        android:layout_marginTop="20dp" />

    <Button
        android:layout_width="120dp"
        android:layout_height="wrap_content"
        android:text="Stop"
        android:textSize="22sp"
        android:textColor="#ffdc1d"
        android:id="@+id/stopButton"
        android:background="#f91616"
        android:textStyle="bold"
        android:padding="4dp"
        android:textAlignment="center"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="41dp" />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageView"
        android:src="@drawable/recording"
        android:layout_above="@+id/textView2"
        android:layout_alignStart="@+id/lteRsrp"
        android:layout_marginBottom="10dp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Filename:"
        android:textColor="#000000"
        android:textSize="26sp"
        android:id="@+id/textView6"
        android:layout_marginTop="50dp"
        android:layout_below="@+id/cellPciTextView"
        android:layout_alignStart="@+id/cellPciTextView"
        android:textStyle="bold|italic" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        android:textColor="#000000"
        android:textSize="26sp"
        android:id="@+id/fileName"
        android:layout_below="@+id/textView6"
        android:layout_centerHorizontal="true"
        android:textStyle="bold" />


</RelativeLayout>

这是AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.parksjg.its.pscrindoortesttool" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".First"
            android:screenOrientation="portrait"
            android:noHistory="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Second"
            android:screenOrientation="portrait"
            android:noHistory="true">
        </activity>
        <activity android:name=".Third"
            android:screenOrientation="portrait"
            android:noHistory="true">
        </activity>
        <activity android:name=".Fourth"
            android:screenOrientation="portrait"
            android:noHistory="true">
        </activity>
        <activity android:name=".Final"
            android:screenOrientation="portrait"
            android:noHistory="true">
        </activity>
    </application>

</manifest>

我是否在后台线程中执行了错误的代码?如何让这个运行更顺畅,更敏感?再次,它在5分钟内运行时速度很快,但是我们用它来测试研究室内LTE网络,我们的步测/驱动测试需要10-15分钟,但是当我按下停止按钮或新测试按钮时需要它在一两秒内作出回应。有时按下按钮后动作生效需要20-30秒,特别是在连续测试后。

以下是该应用的完整流程:

Flow1

Flow2

Flow3

Flow4

Flow5

上一个活动的按钮重新启动第二个活动。如果您需要任何其他代码,请告诉我,如果有人对自己运行代码感兴趣,我也可以在GitHub上发布整个AndroidStudio项目。

谢谢!

1 个答案:

答案 0 :(得分:1)

由于它是随着时间的推移构建的,它可能意味着操作系统没有正确地对视图或对象进行垃圾收集,因为它们的引用没有被释放......这会导致内存问题。我建议第一步使用内存分析器并检查在测试期间使用了多少内存。除此之外,你可以通过做这样的事情来检查你的方法需要执行的时间

void methodName(){
    long startTime = System.currentTimeMillis();
    .
    .
    .
    .
    Log.w("time needed for this method",Long.toString(System.currentTimeMillis()-startTime);
}