been trying to figure out why my code wont run in the new 4.0 emulator for a few days now and cant seem to get to the bottom of it, My code which runs just fine in the 2.2 sdk wont work at all in the 4.0 sdk emulator, as a result of this Ive been trying to track down some tutorials on debugging but cant quite seem to get a clear explanation as to which one is best or quite frankly a clear way as to how to execute the functions, so my question is which is best and what is the best way to do it?
Update:
Exceptions:
11-23 10:16:34.655: E/AndroidRuntime(1358): java.lang.RuntimeException:
Unable to resume activity {com.testapp2.second/com.testapp2.second.activities.AuthorizationActivity}: android.os.NetworkOnMainThreadException
11-23 10:16:34.655: E/AndroidRuntime(1358): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2443)
here is my code:
activity1:
package com.testapp2.second.activities;
import com.testapp2.second.OTweetApplication;
import com.testapp2.second.R;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
public class Testapp2Activity extends ListActivity {
private Twitter twitter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = (OTweetApplication)getApplication();
twitter = app.getTwitter();
setContentView(R.layout.main);
}
@Override
protected void onResume() {
super.onResume();
if (!app.isAuthorized()) {
beginAuthorization();
} else {
loadTimelineIfNotLoaded();
}
}
private void loadTimelineIfNotLoaded() {
loadHomeTimeline();
}
private void beginAuthorization() {
Intent intent = new Intent(this, AuthorizationActivity.class);
startActivity(intent);
}
private void loadHomeTimeline() {
try {
ResponseList<Status> statii = twitter.getHomeTimeline();
StatusListAdapter adapter = new StatusListAdapter(this, statii);
setListAdapter(adapter);
} catch (TwitterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private class StatusListAdapter extends ArrayAdapter<Status> {
public StatusListAdapter(Context context, ResponseList<Status> statii) {
super(context, android.R.layout.simple_list_item_1, statii);
}
}
}
activity 2:
package com.testapp2.second.activities;
import com.testapp2.second.OTweetApplication;
import com.testapp2.second.R;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class AuthorizationActivity extends Activity {
private OTweetApplication app;
private WebView webView;
private WebViewClient webViewClient = new WebViewClient() {
@Override
public void onLoadResource(WebView view, String url) {
// the URL we're looking for looks like this:
// http://otweet.com/authenticated?oauth_token=1234567890qwertyuiop
Uri uri = Uri.parse(url);
if (uri.getHost().equals("otweet.com")) {
String token = uri.getQueryParameter("oauth_token");
if (null != token) {
webView.setVisibility(View.INVISIBLE);
app.authorized();
finish();
} else {
// tell user to try again
}
} else {
super.onLoadResource(view, url);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = (OTweetApplication)getApplication();
setContentView(R.layout.authorization_view);
setUpViews();
}
@Override
protected void onResume() {
super.onResume();
String authURL = app.beginAuthorization();
webView.loadUrl(authURL);
}
private void setUpViews() {
webView = (WebView)findViewById(R.id.web_view);
webView.setWebViewClient(webViewClient);
}
}
extended application:
package com.testapp2.second;
import com.testapp2.second.authorization.OAuthHelper;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import android.app.Application;
public class OTweetApplication extends Application {
private Twitter twitter;
private RequestToken currentRequestToken;
private OAuthHelper oAuthHelper;
@Override
public void onCreate() {
super.onCreate();
oAuthHelper = new OAuthHelper(this);
twitter = new TwitterFactory().getInstance();
oAuthHelper.configureOAuth(twitter);
}
public Twitter getTwitter() {
return twitter;
}
public boolean isAuthorized() {
return oAuthHelper.hasAccessToken();
}
public String beginAuthorization() {
try {
if (null == currentRequestToken) {
currentRequestToken = twitter.getOAuthRequestToken();
}
return currentRequestToken.getAuthorizationURL();
} catch (TwitterException e) {
e.printStackTrace();
}
return null;
}
public boolean authorize(String pin) {
try {
AccessToken accessToken = twitter.getOAuthAccessToken(currentRequestToken, pin);
oAuthHelper.storeAccessToken(accessToken);
return true;
} catch (TwitterException e) {
throw new RuntimeException("Unable to authorize user", e);
}
}
public void authorized() {
try {
AccessToken accessToken = twitter.getOAuthAccessToken();
oAuthHelper.storeAccessToken(accessToken);
} catch (TwitterException e) {
throw new RuntimeException("Unable to authorize user", e);
}
}
}
oauth helper:
package com.testapp2.second.authorization;
import java.io.InputStream;
import java.util.Properties;
import com.testapp2.second.R;
import twitter4j.Twitter;
import twitter4j.auth.AccessToken;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
public class OAuthHelper {
private static final String APPLICATION_PREFERENCES = "app_prefs";
private static final String AUTH_KEY = "auth_key";
private static final String AUTH_SEKRET_KEY = "auth_secret_key";
private SharedPreferences prefs;
private AccessToken accessToken;
private String consumerSecretKey;
private String consumerKey;
private Context context;
public OAuthHelper(Context context) {
this.context = context;
prefs = context.getSharedPreferences(APPLICATION_PREFERENCES, Context.MODE_PRIVATE);
loadConsumerKeys();
accessToken = loadAccessToken();
}
public void configureOAuth(Twitter twitter) {
twitter.setOAuthConsumer(consumerKey, consumerSecretKey);
twitter.setOAuthAccessToken(accessToken);
}
public boolean hasAccessToken() {
return null != accessToken;
}
public void storeAccessToken(AccessToken accessToken) {
Editor editor = prefs.edit();
editor.putString(AUTH_KEY, accessToken.getToken());
editor.putString(AUTH_SEKRET_KEY, accessToken.getTokenSecret());
editor.commit();
this.accessToken = accessToken;
}
private AccessToken loadAccessToken() {
String token = prefs.getString(AUTH_KEY, null);
String tokenSecret = prefs.getString(AUTH_SEKRET_KEY, null);
if (null != token && null != tokenSecret) {
return new AccessToken(token, tokenSecret);
} else {
return null;
}
}
private void loadConsumerKeys() {
try {
Properties props = new Properties();
InputStream stream = context.getResources().openRawResource(R.raw.oauth);
props.load(stream);
consumerKey = (String)props.get("consumer_key");
consumerSecretKey = (String)props.get("consumer_secret_key");
} catch (Exception e) {
throw new RuntimeException("Unable to load consumer keys from oauth.properties", e);
}
}
}
manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testapp2.second"
android:versionCode="1"
android:versionName="1.0" >
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Light"
android:name=".OTweetApplication" >
<activity
android:label="@string/app_name"
android:name=".activities.Testapp2Activity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".activities.AuthorizationActivity" android:label="@string/authorization" />
</application>
<uses-sdk android:minSdkVersion="14" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
The first exception says everything:
NetworkOnMainThreadExceptionYou should never ever do network stuff on the UI thread. You should do it in a Thread/AsyncTask.
If you provide us some code of your activity, we can say you what you should change.
Update:
In your
onResume()ofAuthorizationActivityyou callapp.beginAuthorization();which can calltwitter.getOAuthRequestToken()which, as far as I saw in the twitter4j api, makes network connections. So this shouldn’t be done inonResume()which runs in the UI Thread/Main Thread.My advice: Make the twitter communication/authentication in an
AsyncTaskas you never know how fast/slow a connection might be. You should test your current application while having a slow connection. I guess you might get slow response of your application and/or anapplication not respondingmessage.Read this for further information: Designing for Responsiveness
The reason it worked below 4.0 was: it was introduced in API 11: NetworkOnMainThreadException