java - Android 中的 Activity 缓慢且无响应

标签 java android multithreading optimization

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

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

所以我一定做错了什么,因为我相信我正在后台线程上完成所有艰苦的工作。如果我运行该 Activity 10-15 分钟,它将跳过约 1,000 帧。然后,如果我浏览该应用程序并按下按钮运行另一个测试,它将开始跳过与前一个 15 分钟测试结束时一样多的帧,到第二个测试结束时,它可以跳过多达 2500 帧帧。然后,每次按下按钮开始下一个 Activity 所需的时间就会越来越长(即使是在实际上什么也没做的 Activity 中)。而且只有五项 Activity !

这是我需要主动收集数据 15 分钟的 Activity 的屏幕截图:

screenshot1

以及对应的Android Monitor日志: screenshot2

这是我名为 Third.java 的 Activity 的代码:

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>

我是否在后台线程中执行了错误的代码?我怎样才能让这个运行更流畅、 react 更灵敏?同样,运行时间在 5 分钟以内时速度很快,但我们用它来测试研究室内 LTE 网络,我们的步行测试/驾驶测试需要 10-15 分钟,但当我按下停止按钮或新的测试按钮时,我需要它在一两秒内做出响应。有时,按下按钮后,操作需要 20-30 秒才能生效,特别是在连续测试后。

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

Flow1

Flow2

Flow3

Flow4

Flow5

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

谢谢!

最佳答案

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

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

关于java - Android 中的 Activity 缓慢且无响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36145181/

相关文章:

java - Jackson @JsonView 注释会干扰可见性

安卓运行时布局

android - OnAnimationEnd 不起作用,是的,我研究过

c++ - 从 boost::threads 到 boost::asio 计时器

c# - .NET ConcurrentDictionary.ToArray() 参数异常

ruby-on-rails - ruby 2.1.2 超时仍然不是线程安全的吗?

java - 如何使用 apache poi 读取 xlsx 类型的 Excel 文件的单元格内容?

java - 将 Json 字符串转换为字符串

java - 无法使用Windows Server静态IP访问Java Web应用程序

java.lang.NoClassDefFoundError : Failed resolution of: Landroid/support/v7/appcompat/R$drawable; 错误