android应用程序-gps、wifi和twitter



我在学校有一个项目的android应用程序。该应用程序的目标是获取GPS位置,扫描可用的wifi网络,并将这些信息捆绑到一个字符串中,以便(也由该应用程序)在推特上发布。gps和wifi部分是从头开始写的,twitter代码是我的一个队友发现的一些开源的东西。我们都没有任何安卓编程的经验,所以我们一直在学习我们只需要飞的东西。该应用程序目前运行良好,但还不够好。它通常可以删除一些推文,但最终总是获得ANR。我认为这可能来自GPS或WIFI代码,因为这是我们自己写的东西。我们用twitter代码编写了一个单独的应用程序来测试它,它似乎运行良好,所以我不认为这是问题的原因。

一些有更多经验的安卓程序员能看看这些代码并指出他们看到的任何问题吗,特别是什么可能导致这个应用程序出现ANR?此外,如果有人愿意提出一个比我们目前拥有的更好的架构/框架,我会很感兴趣。当应用程序工作时,我们最终会发送一条推特,看起来像这样:

ajd7v-34 U0b0ed38fc>_____W0b0edf50c+444974893-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和wifi的代码。。。

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吗?

首先,TimerTask不是存储数据的最佳位置。仅使用TimerTask定期执行Service中的某些方法。

其次,最好将所有与Context相关的组件(如ActivityService)的所有内部类都设为static类。这将保护您的代码不受内存泄漏的影响。

此外,最好只注册一次BroadcastRreceiver,不要在每次调用定时器任务时都这样做。

我真的建议你们读一些东西,例如雷托梅尔的书"Android应用程序开发"。