I have an Activity class with quite a lot web services running and want to make my program more "object oriented",so it can be maintainable and easy to read . For example look at the following example.
public class Welcome extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_sample);
buildFitnessClient();
showUser(username,password);
}
private void buildFitnessClient() {
// Create the Google API Client
mClient = new GoogleApiClient.Builder(this)
.addApi(Fitness.SENSORS_API)
.addApi(Fitness.HISTORY_API)
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
.addConnectionCallbacks(
new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "Connected!!!");
// Now you can make calls to the Fitness APIs. What to do?
// Look at some data!!
//showUser(username,password);
new InsertAndVerifyDataTask().execute();
}
#Override
public void onConnectionSuspended(int i) {
// If your connection to the sensor gets lost at some point,
// you'll be able to determine the reason and react to it here.
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
Log.i(TAG, "Connection lost. Cause: Network Lost.");
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
Log.i(TAG, "Connection lost. Reason: Service Disconnected");
}
}
}
)
.addOnConnectionFailedListener(
new GoogleApiClient.OnConnectionFailedListener() {
// Called whenever the API client fails to connect.
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed. Cause: " + result.toString());
if (!result.hasResolution()) {
// Show the localized error dialog
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(),
Welcome.this, 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization dialog is displayed to the user.
if (!authInProgress) {
try {
Log.i(TAG, "Attempting to resolve failed connection");
authInProgress = true;
result.startResolutionForResult(Welcome.this,
REQUEST_OAUTH);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG,
"Exception while starting resolution activity", e);
}
}
}
}
)
.build();
}
#Override
protected void onStart() {
super.onStart();
// Connect to the Fitness API
Log.i(TAG, "Connecting...");
mClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mClient.isConnected()) {
mClient.disconnect();
//showUser(username,password);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
//showUser(username,password);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mClient.isConnecting() && !mClient.isConnected()) {
mClient.connect();
}
}
}
}
private void showUser(final String username, final String password) {
HttpsTrustManager.allowAllSSL();
String tag_json_obj = "json_obj_req";
location = getResources().getConfiguration().locale.getCountry();
final HashMap<String, String> postParams = new HashMap<String, String>();
postParams.put("username", username);
postParams.put("password", password);
Response.Listener<JSONObject> listener;
Response.ErrorListener errorListener;
final JSONObject jsonObject = new JSONObject(postParams);
//{"password":"larissa","username":"samsungtest"}
//{"password":"larissa","username":"theo81developer#gmail.com"}
JsonObjectRequest jsonObjReq = new JsonObjectRequest(AppConfig.URL_USER_CHECK, jsonObject,
new com.android.volley.Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// {"message":"User Information found.","user":{"username":"samsungtest","league_points":null,"team_id":"189","location":"GB","latest_steps":"0","user_type":"LEADER","nickname":"samsungtest"},"status":"success"}
//{"message":"User Information found.","user":{"username":"theo81developer#gmail.com","league_points":null,"team_id":"228","location":"GB","latest_steps":"5033","user_type":"LEADER","nickname":"Samsung User"},"status":"success"}
Log.d("TAG", response.toString());
try {
if (response.getString("status").equals("success")){
userTable(response);
localRanking(username,password,location);
globalRanking(username,password);
}
} catch (JSONException e) {
Log.e("TAG", e.toString());
}
}
}, new com.android.volley.Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//VolleyLog.d("TAG", "Error: " + error.getMessage());
}
}) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
};
// Adding request to request queue
AppController.getInstance().addToRequestQueue(jsonObjReq, tag_json_obj);
}
How can I make it work if I was calling buildFitnessClient() and showUser(...) from another class? I tried some different ways like instastiating a Class called Fitness with buildFitnessClient() method inside,but I am getting null pointer exception on View objects.
You can implement your methods as static so that you can call them from another class or activity and simply pass the required parameters that it may need (such as context, views, etc). And simply use them as something like Fitness.buildFitnessClient( < variables > )
OR
Implement a singleton where you can set variables to be used by your methods and do what you want to do. This, however, is much more complex (at least for me)
** Just be careful with memory leaks **
Related
I am currently working on an Android Application, and i have a problem to handle a request and execute a function just after.
The fact is my Retrofit request is in a Controller, used by a Service, and i am calling the service function inside my Activity (am i clear?).
Clearly, i have to manage one user (get and refresh access token from a webservice) and i need to be able to call my refreshToken() function and execute some code after getting and parsing the response.
This is my code :
UserActivity
public class UserActivity extends AppCompatActivity {
private final static String TAG = "UserActivity";
private User user;
private TextView textViewAccessTokenShow, textViewExpiresInShow, textViewIGPShow, textViewRefreshTokenShow;
private LoginController loginController;
private Wso2Service wso2Service, wso2ServiceIS;
boolean mBounded;
private LoginService loginService;
private Intent mIntent;
//Connection to LoginService
ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(UserActivity.this, "Service is disconnected", Toast.LENGTH_LONG).show();
mBounded = false;
loginService = null;
Log.e(TAG, "onServiceDisconnected: " );
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(UserActivity.this, "Service is connected", Toast.LENGTH_LONG).show();
mBounded = true;
LoginService.LocalBinder mLocalBinder = (LoginService.LocalBinder) service;
loginService = mLocalBinder.getServerInstance();
user = loginService.getUser();
refreshIHM();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);
mIntent = new Intent(this, LoginService.class);
textViewAccessTokenShow = findViewById(R.id.textViewAccessTokenShow);
textViewRefreshTokenShow = findViewById(R.id.textViewRefreshTokenShow);
textViewExpiresInShow = findViewById(R.id.textViewExpiresInShow);
textViewIGPShow = findViewById(R.id.textViewIGPShow);
}
#Override
protected void onResume() { //Getting my user updated outside this activity and printing his informations
super.onResume();
Log.i(TAG, "onResume: ");
if(mBounded == false){
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
} else {
user = loginService.getUser();
refreshIHM();
}
}
public void onClickRefreshToken(View view){
//Where i have to refresh my token, and after that executing refreshIHM()
refreshIHM();
}
public void refreshIHM(){
Log.d(TAG, "refreshIHM() called");
Log.i(TAG, "refreshIHM: "+user.toString());
textViewExpiresInShow.setVisibility(View.VISIBLE);
textViewAccessTokenShow.setVisibility(View.VISIBLE);
textViewRefreshTokenShow.setVisibility(View.VISIBLE);
textViewIGPShow.setVisibility(View.VISIBLE);
textViewAccessTokenShow.setText(user.getAccess_token());
textViewAccessTokenShow.invalidate();
textViewAccessTokenShow.requestLayout();
textViewRefreshTokenShow.setText(user.getRefresh_token());
textViewRefreshTokenShow.invalidate();
textViewRefreshTokenShow.requestLayout();
textViewExpiresInShow.setText(String.valueOf(user.getExpire_in()));
textViewExpiresInShow.invalidate();
textViewExpiresInShow.requestLayout();
textViewIGPShow.setText(user.getId_group_parent());
textViewIGPShow.invalidate();
textViewIGPShow.requestLayout();
}
}
LoginController, where i execute every functions about User data
public class LoginController {
public static final String TAG = "LOGINSERVICE";
private User usertemp;
private Wso2Service wso2Service, wso2ServiceIS;
public LoginController(){
this.wso2Service = new Retrofit.Builder()
.baseUrl(Wso2Service.APIMENDPOINT)
.addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(Wso2Service.class);
this.wso2ServiceIS = new Retrofit.Builder()
.baseUrl(Wso2Service.ISENDPOINT)
.addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(Wso2Service.class);
}
public User parseUserInfo(String request, User user) {
try {
JSONObject jo = new JSONObject(request);
user.setAccess_token(jo.getString("access_token"));
user.setRefresh_token(jo.getString("refresh_token"));
user.setScope(jo.getString("scope"));
user.setId_token(jo.getString("id_token"));
user.setToken_type(jo.getString("token_type"));
user.setExpire_in(jo.getInt("expires_in"));
return user;
} catch (Exception e){
Log.e(TAG, "getUserInfo: "+e.toString());
}
return null;
}
public User parseIdGroupParentInfo(String request, User user){
try {
Log.i(TAG, "parseIdGroupParentInfo: "+request);
JSONObject jo = new JSONObject(request);
user.setId_group_parent(jo.getString("id_group_parent"));
return user;
} catch (Exception e){
Log.e(TAG, "parseIdGroupParentInfo: "+e.toString());
}
return null;
}
public void refreshToken(User user){
this.usertemp = user;
Log.i(TAG, "refreshToken: ");
this.wso2Service.getTokensByRefresh("refresh_token",user.getRefresh_token(),"openid", ApiConstants.token).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
//On parse la réponse
usertemp.setLogin_request_responseJSON(response.body());
parseUserInfo(response.body(), usertemp);
Log.i(TAG, "onLoginReady: " + usertemp.toString());
wso2ServiceIS.getUserInfo("Bearer "+usertemp.getAccess_token()).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.i(TAG, "onResponse: "+response.code()+response.body());
usertemp = parseIdGroupParentInfo(response.body(),usertemp);
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
}
});
} else {
Log.e(TAG, "onResponse: " );
Log.e(TAG, "onResponse: Code "+response.code()+" Body : "+response.body() );
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
}
});
}
}
LoginService, what i call in every activities to use the same User everytime
public class LoginService extends Service {
public final String TAG = "LoginService";
private User user;
private LoginController loginController;
IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
public LoginService getServerInstance() {
return LoginService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
this.user = (User)intent.getSerializableExtra("user");
Log.i(TAG, "onStartCommand: "+user.toString());
loginController = new LoginController();
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
}
#Override
public void onDestroy() {
Log.i(TAG, "onDestroy: ");
super.onDestroy();
}
public User getUser(){
Log.i(TAG, "getUser: ");
return this.user;
}
public void regenerateByRefreshToken(){
Log.d(TAG, "regenerateByRefreshToken: ");
loginController.refreshToken(user);
Log.d(TAG, "regenerateByRefreshToken: end");
}
}
Do you have any idea about how to make my RefroFit function handle its response and only after executing another function inside my UI ? Or inside my regenerateByRefreshToken() function ?
Thank you !
Do you have any idea about how to make my RefroFit function handle its
response and only after executing another function inside my UI ? Or
inside my regenerateByRefreshToken() function ?
As per the current implementation, You can achieve this using Callbacks. Create two callbacks to
Get the usertemp inside service from the controller after successful execution.
Second callback to send the user object back to activity from service
So follow below steps:
a) Create callback interface
// create new OnUserRefresh.java
public interface OnUserRefresh{
void onRefresh(User user);
void onError(Throwable t);
}
b) Modify the controller to receive the callback reference
public class LoginController {
// code...
public void refreshToken(User user, OnUserRefresh onUserRefresh){
this.usertemp = user;
Log.i(TAG, "refreshToken: ");
this.wso2Service.getTokensByRefresh("refresh_token",user.getRefresh_token(),"openid", ApiConstants.token).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
//On parse la réponse
usertemp.setLogin_request_responseJSON(response.body());
parseUserInfo(response.body(), usertemp);
Log.i(TAG, "onLoginReady: " + usertemp.toString());
wso2ServiceIS.getUserInfo("Bearer "+usertemp.getAccess_token()).enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.i(TAG, "onResponse: "+response.code()+response.body());
usertemp = parseIdGroupParentInfo(response.body(),usertemp);
onUserRefresh.onRefresh(usertemp);
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
onUserRefresh.onError(t);
}
});
} else {
Log.e(TAG, "onResponse: " );
Log.e(TAG, "onResponse: Code "+response.code()+" Body : "+response.body() );
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG, "onFailure: ",t );
}
});
}
}
c) Pass callback object from service to controller
public class LoginService extends Service {
/*Add interface, to be used for data passing*/
public void regenerateByRefreshToken(OnUserRefresh onUserRefresh){
Log.d(TAG, "regenerateByRefreshToken: ");
loginController.refreshToken(user, new OnUserRefresh(){
#Override
void onRefresh(User user){
this.user = user;
onUserRefresh.onRefresh(user); // trigger onRefresh in client i.e. activity
}
#Override
void onError(Throwable t){
onUserRefresh.onError(t);
// log error etc
}
});
Log.d(TAG, "regenerateByRefreshToken: end");
}
}
d) Pass callback object from activity to service and implement UI updates method call
public class UserActivity extends AppCompatActivity {
public void onClickRefreshToken(View view){
//Where i have to refresh my token, and after that executing refreshIHM()
loginService.regenerateByRefreshToken(new OnUserRefresh(){
#Override
void onRefresh(User user){
this.user = user;
refreshIHM();
}
#Override
void onError(Throwable t){
// log error etc
}
});
}
}
Note: The initial user reference is always null as you are receiving it from intent in your service
this.user = (User)intent.getSerializableExtra("user");
but you are neither initialising any user object in UserActivity nor adding it in the mIntent object so you need to a user object with token and other required properties in activity for network calls.
You can optimize the flow with lambdas, Rxjava etc as well.
Well, I get Validation:com.android.volley.ParseError: org.json.JSONException:value false of type java.jang.Boolean cannot be converted to JSONObject error whenever I try to receive a boolean value, that is sent by a REST web service, in my android app using volley's JSONObjectRequest format.
I know that using StringRequest will be the easy way to solve this but I really wonder if there's another way to solve this.
My guess is that the primitive boolean value is the problem because it is not equevalent to a json object. so the exeption is thrown in the onResponse(JSONObject response) volley method.
here's the java REST web service:
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Boolean validate(CreditCard card) {
//instructions
if(/* some conditions */) {
cardList.put(card.getId(), card);
return true;
}
return false;
}
and the android app code:
public class MainActivity extends Activity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_id = findViewById(R.id.id);
et_num = findViewById(R.id.number);
et_type = findViewById(R.id.type);
et_ctrlnb = findViewById(R.id.ctrlnum);
et_expd = findViewById(R.id.expdate);
b_validate = findViewById(R.id.validate);
b_validate.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v == b_validate) {
String request_url = "http://192.168.191.1:8080/RESTCardValidator/rest/cardvalidator";
JSONObject cardDetails = new JSONObject();
try {
cardDetails.put("controlNumber", Integer.parseInt(et_ctrlnb.getText().toString()));
cardDetails.put("expiryDate", et_expd.getText().toString());
cardDetails.put("id", Long.parseLong(et_id.getText().toString()));
cardDetails.put("number", et_num.getText().toString());
cardDetails.put("type", et_type.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, request_url, cardDetails,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Toast.makeText(MainActivity.this, "Validation:" + response.toString(), Toast.LENGTH_LONG).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "Validation:" + error.toString(), Toast.LENGTH_LONG).show();
}
});
Volley.newRequestQueue(this).add(request);
}
}
as you see in the image the value true/false is received
First Screenshot-
Second Screenshot -
I'm working on an app that retrieves data from network, stores them to the device and then reads them.
Problem is, I get my data in a Async Task.. And my app doesn't let the task finish before trying to show the data to the user..
I've tried task.get() but without result (it just stops there).
Here is my task:
public GetOptionsTask(XMLPortalGetOptions request) {
super(request);
}
protected void onCancelled(){
// TODO afficher message pas d'options sur le disque
}
#Override
public void handleError(Transaction transaction) {
// TODO afficher message pas d'options sur le disque
}
#Override
public void handleSuccess(Transaction transaction) {
saveOptions(transaction.getResponse());
request = null;
Log.d(OptionsManager.class.getName(), this.getStatus().toString());
}
This task is an instance of my custom Async Task:
protected BaseXMLTransaction request;
public abstract void handleError(Transaction transaction);
public abstract void handleSuccess(Transaction transaction);
public TransactionTask(BaseXMLTransaction request){
this.request = request;
}
#Override
protected Void doInBackground(Void... params) {
try {
Log.i(TransactionTask.class.getName(), "Doing in background");
SocketHandler.sendTransaction(this, request.getRequest());
} catch (SocketHandlerNotConfiguredException e) {
Log.e(TransactionTask.class.getName(), "SocketHandler's parameters were not set.");
}
return null;
}
#Override
public void transactionResult(Transaction transaction) {
switch (transaction.getCode()) {
case ERROR:
Log.e(TransactionTask.class.getName(), "ERROR !!!");
handleError(transaction);
break;
case NO_CLIENT:
Log.e(TransactionTask.class.getName(), "No Client Error");
handleError(transaction);
break;
case NO_SERVER:
Log.e(TransactionTask.class.getName(), "No Server Error");
handleError(transaction);
break;
case OLD_VERSION:
Log.e(TransactionTask.class.getName(), "Old Version");
handleError(transaction);
break;
case TIMEOUT:
Log.e(TransactionTask.class.getName(), "Transaction Timeout");
handleError(transaction);
break;
case SUCCESS:
Log.i(TransactionTask.class.getName(), "Transaction Success");
handleSuccess(transaction);
}
}
I seriously don't know what to do... Execute goes to fast and get doesn't do anything since I'm not returning anything I guess.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
#Override
protected void onPostExecute(String result) {
}
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
and call it like this:
new DownloadFilesTask().execute(url1, url2, url3);
I use an interface as a delegate to do this. Here is an example:
In my main activity I have a onClick listener to trigger my async call and a listener to process once the call is complete.
private void enableLocationButton(){
locationButton = (Button) findViewById(R.id.locationButton);
locationButton.setEnabled(true);
locationButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, selectLocationActivity.class);
intent.putExtra("serverURL",server.getWebServerAddressField());
startActivityForResult(intent, 200);
}
});
}
#Override
protected void onActivityResult(int requestCode,int resultCode, Intent data){
if(resultCode == RESULT_OK) {
switch (requestCode){
case 100:
processServerResponse((PmsWebServer) data.getBundleExtra("server").get("server"));
break;
case 200:
processLocationResponse((PmsDataSource)data.getBundleExtra("location").get("location"));
default:processError();
}
}else{
processError();
}
}
Somewhere in the selectLocationActivity I have a call to the Async call and something to process the response, please note that this class implements an interface that is used in the Async call.
public class selectLocationActivity extends ListActivity implements SoapServiceInterface{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_select);
chosenServer = this.removeURLHeader(getIntent().getStringExtra("serverURL"));
this.retrieveLocationOptionsByServer(chosenServer);
}
private void retrieveLocationOptionsByServer(String server) {
Map<String,Object> parms = new HashMap<String,Object>();
parms.put(WEB_SERVER_NAME,server);
SoapServiceObject service = new SoapServiceObject(Services.SERVICE_DETAILS,parms);
callTheService(service);
}
private void callTheService(SoapServiceObject service){
SoapServiceHelper helper = new SoapServiceHelper();
helper.delegate = thisActivity;
helper.execute(service);
}
#Override
public void serviceCallComplete(SoapObject response){
this.createClickableListOnScreen(response);
}
//...more code...//
}
serviceCallComplete is kicked off by the asyncTask. Below is the code for that task
public class SoapServiceHelper extends AsyncTask<SoapServiceObject, Void, SoapObject>{
public SoapServiceInterface delegate = null;
private Integer RETRY_COUNT = 0;
private final Integer MAX_RETRY_COUNT = 2;
protected SoapObject doInBackground(SoapServiceObject... args){
SoapServiceObject service = args[0];
try{
service.callTheService();
}catch(Exception e){
System.out.println("An error occurred calling the service\n" + e.getMessage());
}
return service.getResponse();
//return callDateTimeService();
}
protected void onPostExecute(SoapObject result){
delegate.serviceCallComplete((SoapObject)(result.getProperty(0)));
}
}
And finally here is the interface
public interface SoapServiceInterface {
public void serviceCallComplete(SoapObject response);
}
I know I'm displaying something to the screen directly from my result, just sub that part with a save and read ;)
One thing with that task was that it was saving stuff into a singleton. I managed to call the methods using the information from the network saved in the singleton at the onResume(). When the threads end, it goes to the onResume and everything works fine!
I am new to android programing and I have two, one problem in the AsyncTask class named RetrieveTokenTask(), in this class I get a token for access email account on gmail, when I call the AsyncTask class create a infinite loop and the message for approbation is open and closed for the app.
The other problem is when I press the button revoke access for data, when try again login in the app not show the Layout with contains data.
I've done this following some tutorials.
Any help would helpful.
Thanks and sorry for any error in my writing but my english is not good.
This code for mi app is the next:
`protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
`
...
//Initializing google plus api client
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN).build();
}
protected void onStart(){
super.onStart();
mGoogleApiClient.connect();
}
protected void onStop(){
super.onStop();
if(mGoogleApiClient.isConnected()){
mGoogleApiClient.disconnect();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btn_sign_in:
signInWithGplus();
break;
case R.id.btn_sign_out:
signOutFromGplus();
break;
case R.id.btn_revoke_access:
revokeGplusAccess();
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
if(!result.hasResolution()){
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this,
0).show();
return;
}
if(!mIntentInProgress){
//Store the connection for later usage
mConnectionResult = result;
if(mSignInClicked){
// The user has already clicked 'sign-in' so we attempt to
// resolve all
// errors until the user is signed in, or they cancel.
resolveSignInError();
}
}
}
#Override
public void onConnected(Bundle arg0) {
mSignInClicked = false;
Toast.makeText(this, "User is connected", Toast.LENGTH_LONG).show();
// Get User's information
getProfileInformation();
// Update the UI after sign-in
updateUI(true);
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
updateUI(false);
}
private void updateUI(boolean isSignedIn){
if(isSignedIn){
btnSignIn.setVisibility(View.GONE);
btnSignOut.setVisibility(View.VISIBLE);
btnRevokeAccess.setVisibility(View.VISIBLE);
llProfileLayout.setVisibility(View.VISIBLE);
}
else {
btnSignIn.setVisibility(View.VISIBLE);
btnSignOut.setVisibility(View.GONE);
btnRevokeAccess.setVisibility(View.GONE);
llProfileLayout.setVisibility(View.GONE);
}
}
/*
* Sign-in into google
*/
private void signInWithGplus(){
if(!mGoogleApiClient.isConnecting()){
mSignInClicked = true;
resolveSignInError();
}
}
/*
* Method to resolve any sign-in errors
*/
private void resolveSignInError(){
if(mConnectionResult.hasResolution()){
try{
mIntentInProgress = true;
mConnectionResult.startResolutionForResult(this, RC_SIGN_IN);
}
catch(SendIntentException e){
mIntentInProgress = false;
mGoogleApiClient.connect();
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RC_SIGN_IN) {
mIntentInProgress = false;
if (resultCode == RESULT_OK) {
// Make sure the app is not already connected or attempting to connect
if (!mGoogleApiClient.isConnecting() &&
!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
}
}
/*
* User's information name, email, profile pic
*/
private void getProfileInformation(){
try{
if(Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null){
Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);
String personName = currentPerson.getDisplayName();
String perosnPhotoUrl = currentPerson.getImage().getUrl();
String personGooglePlusProfile = currentPerson.getUrl();
String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
Log.e(TAG, "Name: " + personName + ", plusProfile: "
+ personGooglePlusProfile + ", email: " + email
+ ", Image: " + perosnPhotoUrl);
txtName.setText(personName);
txtEmail.setText(email);
perosnPhotoUrl = perosnPhotoUrl.substring(0,
perosnPhotoUrl.length() - 2)
+ PROFILE_PIC_SIZE;
new LoadProfileImage(imgProfilePic).execute(perosnPhotoUrl);
new RetrieveTokenTask(txtToken).execute(email);
}
else{
Toast.makeText(getApplicationContext(),
"Person informations is null", Toast.LENGTH_LONG).show();
}
}
catch(Exception e){
e.printStackTrace();
}
}
/*
* Background Async task to load user profile picture from url
*/
private class LoadProfileImage extends AsyncTask<String, Void, Bitmap>{
ImageView bmImage;
public LoadProfileImage(ImageView bmImage){
this.bmImage = bmImage;
}
#Override
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try{
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
}
catch(Exception e){
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result){
bmImage.setImageBitmap(result);
}
}
/*
* Sign-out from google
*/
private void signOutFromGplus(){
if(mGoogleApiClient.isConnected()){
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
mGoogleApiClient.disconnect();
mGoogleApiClient.connect();
updateUI(false);
}
}
/*
* Revoking access from google
*/
private void revokeGplusAccess(){
if(mGoogleApiClient.isConnected()){
Plus.AccountApi.clearDefaultAccount(mGoogleApiClient);
Plus.AccountApi.revokeAccessAndDisconnect(mGoogleApiClient)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status arg0) {
Log.e(TAG, "User acces revoked!");
mGoogleApiClient.connect();
updateUI(false);
}
});
}
}
private class RetrieveTokenTask extends AsyncTask<String, Void, String> {
TextViewTkn Tkn;
private RetrieveTokenTask(TextView tkn){
this.Tkn = tkn;
}
#Override
protected String doInBackground(String... params) {
String accountName = params[0];
String scopes = "oauth2:https://www.googleapis.com/auth/gmail.compose";
String token = null;
try {
token = GoogleAuthUtil.getToken(getApplicationContext(), accountName, scopes);
} catch (IOException e) {
Log.e(TAGTKN, e.getMessage());
} catch (UserRecoverableAuthException e) {
startActivityForResult(e.getIntent(), REQ_SIGN_IN_REQUIRED);
} catch (GoogleAuthException e) {
Log.e(TAGTKN, e.getMessage());
}
return token;
}
#Override
protected void onPostExecute(String result) {
txtToken.setText(result);
}
}
To your second question, an asynctask does not run more than once. If you are trying to reexecute an instance it will not run. You must create new AsyncTask instance every time you want to execute.
You better set a break point in doBackground method and check it.
I am just trying to make a game where I need to post game score on facebook wall. And I am following libGDX framework. Below is my test activity that just post my custom message on facebook wall.
public class MainActivity extends Activity {
private static final String FB_APP_ID = "1452723631660564";
private static final String FACEBOOK_PERMISSION = "publish_stream";
private static final int FB_AUTH = 2; // ANY INTEGER VALUE
Facebook facebook = new Facebook(FB_APP_ID); //
static String FACEBOOK_UPDATE_MSG;
static String FACEBOOK_UPDATE_FAILURE;
static String FACEBOOK_UPDATE_SUCCESS;
static String FACEBOOK_SIGNIN_FAILED;
Handler fHandler = new Handler();
Map<Object, Object> preferences = new HashMap<Object, Object>();
#SuppressLint("NewApi")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
login("Hello facebook test app");
}
#SuppressWarnings("deprecation")
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case FB_AUTH:
facebook.authorizeCallback(requestCode, resultCode, data);
break;
default:
finish();
break;
}
}
public void postMessageOnWall(final String msg) {
try {
if (facebook.isSessionValid()) {
new Thread(new Runnable() {
#Override
public void run() {
Bundle parameters = new Bundle();
parameters.putString("message", msg);
parameters.putString("link", "ANDROID_MARKET_LINK"); // or any other
// link
parameters.putString("name", "APP/GAME NAME");
try {
#SuppressWarnings("deprecation")
String response = facebook.request("me/feed", parameters,
"POST");
FACEBOOK_UPDATE_MSG = FACEBOOK_UPDATE_SUCCESS;
fHandler.post(mUpdateFacebookNotification);
} catch (IOException e) {
FACEBOOK_UPDATE_MSG = FACEBOOK_UPDATE_FAILURE;
fHandler.post(mUpdateFacebookNotification);
}
}
});
}
} catch (Exception e) {
Log.e("error-----------", e.getLocalizedMessage());
}
}
final Runnable mUpdateFacebookNotification = new Runnable() {
public void run() {
Toast.makeText(getBaseContext(), FACEBOOK_UPDATE_MSG,
Toast.LENGTH_LONG).show();
}
};
#SuppressWarnings("deprecation")
public void login(final String msg) {
/*String access_token = preferences.getString("facebook_access_token",
null);*/
String access_token = (String) preferences.get("facebook_access_token");
long expires = 0;
if (access_token != null) {
facebook.setAccessToken(access_token);
}
if (expires != 0) {
facebook.setAccessExpires(10000000l);
}
/*
* Only call authorize if the access_token has expired.
*/
if (!facebook.isSessionValid()) {
facebook.authorize(this, new String[] { "publish_stream","read_stream", "offline_access" },
FB_AUTH, new DialogListener() {
#Override
public void onComplete(Bundle values) {
/*preferences.putString("access_token",
facebook.getAccessToken());
preferences.putLong("access_expires",
facebook.getAccessExpires());
preferences.flush();*/
preferences.put("access_token", facebook.getAccessToken());
preferences.put("access_expires", facebook.getAccessExpires());
if (msg != "")
postMessageOnWall(msg);
else
OpenFbPage();
}
private void OpenFbPage() {
}
#Override
public void onFacebookError(FacebookError error) {
FACEBOOK_UPDATE_MSG = FACEBOOK_SIGNIN_FAILED;
fHandler.post(mUpdateFacebookNotification);
}
#Override
public void onError(DialogError e) {
FACEBOOK_UPDATE_MSG = FACEBOOK_SIGNIN_FAILED;
fHandler.post(mUpdateFacebookNotification);
}
#Override
public void onCancel() {
}
});
}
}
}
I am not getting any exception/error in above code, but it also doesn't post my custom message on my facebook wall. It just opens an fb application and loading alert over that, nothing else. When I debug that, it neither reach on thread's run() method of postMessageOnWall() , nor I get any response defined in same method.
Please guide me where I am wrong. I know I write my whole code related to facebook post in single activity, but it just an test application. Once it is successful, I will segregate the logic.
among hundreds of things badly wrong with this example, you are not starting the thread (by calling start). If you had actually tried to make a small, self-contained example, as you should have, you would have found out on your own.