1

学校でのプロジェクト用の Android アプリケーションがあります。このアプリの目的は、GPS 位置情報を取得し、利用可能な Wi-Fi ネットワークをスキャンして、その情報を文字列にまとめてツイートすることです (これもアプリによって)。GPS と Wi-Fi の部分はゼロから作成され、Twitter のコードはチームメイトの 1 人が見つけたオープン ソースのものです。私たちは誰も Android プログラミングの経験がないので、飛ぶだけでよいことを学んできました。アプリの種類は現在機能していますが、十分ではありません。通常、いくつかのツイートをオフにすることができますが、最終的には常に ANR を取得します。これはおそらく GPS または WIFI コードから来ていると思います。これは私たちが自分で書いたものだからです。テスト用に Twitter コードだけを使って別のアプリを作成しましたが、問題なく動作しているように見えたので、そうは思いません。

経験豊富な一部の Android プログラマーは、このコードの一部を見て、彼らが見た問題、具体的にはこのアプリが ANR を引き起こしている可能性があるものを指摘できますか? また、私たちが現在持っているものよりも優れたアーキテクチャ/フレームワークを提案してくれる人がいれば、私は興味があります. アプリが動作すると、次のようなツイートが送信されます。

ajd7v - 34 U0b0ed38fc_ _ _ _ _ _ _ _ _ _ _ _ _ 00b0ed39c4 _ _ _ _ _ __ _ _ _ _ _ W0b0edf50c + 44974893-093232387

これは、アクティビティ クラスの関連コードです...

    private Intent in;
public static TextView textView1;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_spectral_tweets);


    mConsumer = new CommonsHttpOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);

    mProvider = new DefaultOAuthProvider(
            "http://api.twitter.com/oauth/request_token",
            "http://api.twitter.com/oauth/access_token",
            "http://api.twitter.com/oauth/authorize");

    prefs = PreferenceManager.getDefaultSharedPreferences(this);
    String token = prefs.getString("token", null);
    String tokenSecret = prefs.getString("tokenSecret", null);

    if (token != null && tokenSecret != null) {
        mConsumer.setTokenWithSecret(token, tokenSecret);
        oauthClient = new OAuthSignpostClient(CONSUMER_KEY,
                CONSUMER_SECRET, token, tokenSecret);
        twitter = new Twitter(TWITTER_USER, oauthClient);
    } else {
        Log.d(TAG, "onCreate. Not Authenticated Yet " );
        new OAuthAuthorizeTask().execute();
    }

    in = new Intent(this, BackgroundService.class);
    textView1 = (TextView) findViewById(R.id.textView1);
    changeText("On Create");
}

public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_spectral_tweets, menu);
    return true;
}

/**
 * Changes textView1 to string msg
 */
public static void changeText(String msg) {
    textView1.setText(msg);
}

/**
 * tell the service to start displaying GPS/WIFI updates
 */
public void startMessages(View view) {
    startService(in);
}

/**
 * tell the service to stop displaying GPS/WIFI updates
 */
public void stopMessages(View view) {
    changeText("stopped");
    stopService(in);
}

/**
 * When the BACK key is pressed ask the user if they want to quit
 * if they do then stop the service and exit the program
 */
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
    if ((keyCode == KeyEvent.KEYCODE_BACK)) {
        @SuppressWarnings("unused")
        AlertDialog alertbox = new AlertDialog.Builder(this)
        .setMessage("Do you want to exit the application?")
        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            // stop the service and end the program
            public void onClick(DialogInterface arg0, int arg1) {
                stopService(in);
                finish();
            }
        })
        .setNegativeButton("No", new DialogInterface.OnClickListener() {
            // return to program
            public void onClick(DialogInterface arg0, int arg1) {}
        })

        .show();
    }
    return super.onKeyDown(keyCode, event);
}

これは、GPS と Wi-Fi を処理するサービスのコードです...

public class BackgroundService extends Service implements LocationListener
{
private static Timer repeater = new Timer();
private static LocationManager lm;
private getInfoAndTweet getAndTweet = this.new getInfoAndTweet();

private static final int MIN_TIME_MILLISECONDS = 0;
private static final int MIN_DIST_METERS = 0;
private static final int frequency = 30 * 1000;
private double temp_long = 0.0;
private double temp_lat = 0.0;
private int temp_count = 0;
private boolean thread_running = false;


@Override
public IBinder onBind(Intent arg0) {
    return null;
}

public void onCreate()
{
    super.onCreate();
    lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
    lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_MILLISECONDS, MIN_DIST_METERS, this);
    Toast.makeText(getApplicationContext(), "Location display is on", Toast.LENGTH_SHORT).show();
    startService();
}

public void onDestroy()
{
    repeater.cancel();
    lm.removeUpdates(this);
    unregisterReceiver(getAndTweet.receiver);
    Toast.makeText(getApplicationContext(), "Location display is off", Toast.LENGTH_SHORT).show();
    temp_lat = 0;
    temp_long = 0;
    temp_count = 0;
}

private void startService()
{
    repeater.scheduleAtFixedRate(getAndTweet, 0, frequency);
}

/* this class will contain all of the GPS and WIFI classes so that none of that stuff clogs up the main thread */
private class getInfoAndTweet extends TimerTask
{
    WifiManager wifi;
    BroadcastReceiver receiver;

    DecimalFormat lat = new DecimalFormat("00.000000");
    DecimalFormat lon = new DecimalFormat("000.000000");
    String gps_info;
    String wifi_info;
    String final_string;
    private final String hashtag = "#ajd7v-34 ";
    int count = 0;

    private class WIFIscanner extends BroadcastReceiver
    {

        private final ArrayList<Integer> channel_numbers = new ArrayList<Integer> (Arrays.asList(0, 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462));
        List <ScanResult> results;
        Map<Integer, String> levels = new HashMap<Integer, String>();
        String empty_channel = "__________";        // 10 spaces

        public WIFIscanner()
        {
            init_levels();
        }

            public void onReceive(Context context, Intent intent)
        {
            wifi_info = "";
            results = wifi.getScanResults();
            ScanResult sr;
            Iterator<ScanResult> it = results.iterator();
            ScanResult channel_info[] = new ScanResult[12];

            for (int i = 1; i < 12; i++)
            {
                channel_info[i] = null;
            }

            while (it.hasNext())
            {
                sr = it.next();
                int channel = channel_numbers.indexOf(Integer.valueOf(sr.frequency));

                if (channel_info[channel] == null)
                {
                    channel_info[channel] = sr;
                }
                else
                {
                    if (channel_info[channel].level < sr.level)
                    {
                        channel_info[channel] = sr;
                    }
                }
            }

            for (int i = 1; i < 12; i++)
            {
                if (channel_info[i] != null)
                {
                    wifi_info += (levels.get(channel_info[i].level) == null ? "0" : levels.get(channel_info[i].level))  + channel_info[i].BSSID.replace(":", "").substring(2, 11);
                }
                else
                {
                    wifi_info += empty_channel;
                }
            }

            final_string = hashtag + wifi_info + gps_info;
            if (temp_count != 0)
            {
                if(Twitter_Test_AppActivity.twitter != null) {
                    Twitter_Test_AppActivity.twitter.setStatus(final_string);
                    Twitter_Test_AppActivity.changeText("Auto Tweet Sent: " + count + "\t" + final_string);
                } else {
                    Twitter_Test_AppActivity.changeText("Tweet not sent");
                }
            }
            else
            {
                Twitter_Test_AppActivity.changeText(count + "\tno new GPS info");
            }
            thread_running = false;
        }

    }

    public void run()
    {
        thread_running = true;
        wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        if (receiver == null)
        {
            receiver = new WIFIscanner();
        }
        registerReceiver(receiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

        String latitude = lat.format(temp_lat / temp_count).replace(".",  "");
        String longitude = lon.format(temp_long / temp_count).replace(".",  "");
        gps_info = ((temp_lat / temp_count) > 0 ? "+" : "") + latitude + ((temp_long / temp_count) > 0 ? "+" : "") + longitude;

        wifi.startScan();
        count++;
    }
}

public void onLocationChanged(Location location) {
    if (thread_running)
    {
        temp_lat += location.getLatitude();
        temp_long += location.getLongitude();
        temp_count ++;
    }
}

public void onProviderDisabled(String provider) {
    Toast.makeText(getApplicationContext(), "GPS disabled", Toast.LENGTH_SHORT).show();

}

public void onProviderEnabled(String provider) {
    Toast.makeText(getApplicationContext(), "GPS enabled", Toast.LENGTH_SHORT).show();

}

public void onStatusChanged(String provider, int status, Bundle extras) {}

}

編集 これについてもっと考えていたとき、メインスレッドで実行されているTwitterコードもANRを引き起こしている可能性があることに気づきました. 学校のネットワークは最高とは言えず、私のラップトップは接続に問題が生じることさえあります (私のラップトップのせいではありません。他の場所では問題ありません)。低速または貧弱なネットワーク接続により、ツイートを送信しようとしたときにメインスレッドがハングアップし、電話がアプリの ANR を引き起こす可能性はありますか?

4

1 に答える 1

0

まず第一にTimerTask、データを保存するのに最適な場所ではありません。your TimerTaskonly を使用して、 からいくつかのメソッドを定期的に実行しますService

Context第二に、すべての関連コンポーネントのすべての内部クラスをクラスのようにActivity、またはクラスServiceとして作成することをお勧めしstaticます。これにより、コードがメモリ リークから保護されます。

BroadcastRreceiverまた、タイマータスクの呼び出しごとに登録するのではなく、一度だけ登録することをお勧めします。

Reto Meier の本「Android アプリケーション開発」などを読むことを強くお勧めします。

于 2012-12-01T06:00:56.613 に答える