response.body() result changes during execution. (retrofit2-get method) - android

I'm a beginner learning Android.
I'm trying to make my application receive data from local database.
So I used retroit2 as followed
public class SNSDataServicer {
private String BASE_URL = "http://10.0.2.2:8080/";
Retrofit retrofitClient =
new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
SelectAPI select = retrofitClient.create(SelectAPI.class);
InsertAPI insert = retrofitClient.create(InsertAPI.class);
UpdateAPI update = retrofitClient.create(UpdateAPI.class);
DeleteAPI delete = retrofitClient.create(DeleteAPI.class);
}
interface SelectAPI{
#GET("sns/all/{candidate}")
Call<List<SNSData>> selectAllByCandidate(#Path("candidate") String candidate);
}
and this is the code for MainActivity.java
public class MainActivity extends AppCompatActivity {
SNSDataServicer dataService = new SNSDataServicer();
List<SNSData> snsDataList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView checker = findViewById(R.id.checker);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dataService.select.selectAllByCandidate("3").enqueue(new Callback<List<SNSData>>() {
#Override
public void onResponse(Call<List<SNSData>> call, Response<List<SNSData>> response) {
snsDataList = response.body();
return;
}
#Override
public void onFailure(Call<List<SNSData>> call, Throwable t) {
t.printStackTrace();
Toast.makeText(getApplicationContext(), "Fail", Toast.LENGTH_LONG).show();
Log.d("Failure", "onResponse: Failed");
}
});
if(snsDataList==null) {
checker.setText("null");
} else {
checker.setText(snsDataList.get(0).getMedia());
}
}
});
}
}
When I press button, the textview's text should be set to size of the list.
But snsDataList kept on returning null
eventhough reponse.body() returned list successfully
below is scree capture of my debugging.
1.
enter image description here
by this point it was perfect, but when I hit F8 to debug next step
enter image description here
response body has been changed and when I hit F8 more, it takes me to
ExecutorCallAdapterFactory.java
Handler.class
Looper.class
and no more.
Then suddenly my snsDataList becomes null...
This is ridiculously hard for me and I've tried to solve it by myself for very long but I have failed...
Can someone help me with this problem? It will be really grateful.

Related

Android fetching values from Firebase Database

Hello so I've been strugging for awhile now. I want to consult someone about my code. I want to apply
a coloring function to my app.
When the person presses the button when it's at its:
GREEN state it updates the value on the database to BEING HOUSEKEPT
YELLOW state when pressed sends READY FOR INSPECTION RoomStatus
RED state when pressed sends READY FOR HOUSEKEEPING RoomStatus
It was working earlier but when I tried to restrict the users that users who are Housekeepers can't access the RED STATE which are for House Keepers, I inserted somewhere in my code where I want to implement it.
I'm going over loops here can somebody tell me where I did wrong?
Here's my code:
Button room1;
private DatabaseReference mFirebaseDatabase, mFirebaseDatabase1, mFirebaseDatabase1room;
private FirebaseDatabase mFirebaseInstance;
private DatabaseReference referenceroom1;
private String roomStat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navi_to_scan2);
mFirebaseInstance = FirebaseDatabase.getInstance();
mFirebaseDatabase1 = mFirebaseInstance.getReference("Rooms");
mFirebaseDatabase = mFirebaseInstance.getReference("Users");
mFirebaseDatabase1room = mFirebaseInstance.getReference("Rooms").child("Room1");
referenceroom1 = mFirebaseDatabase1.child("Room1").child("RoomStatus");
room1 = (Button) findViewById(R.id.rm1Btn);
mFirebaseDatabase1.child("Room1").addValueEventListener(new ValueEventListener() { //attach listener
#Override
public void onDataChange(DataSnapshot dataSnapshot) { //something changed!
for (DataSnapshot locationSnapshot : dataSnapshot.getChildren()) {
String location = locationSnapshot.getValue().toString();
if (location.equals("READY FOR HOUSEKEEPING")) {
room1.setBackgroundColor(Color.GREEN);
roomStat = "Green";
} else if (location.equals("BEING HOUSEKEPT")) {
room1.setBackgroundColor(Color.YELLOW);
roomStat = "Yellow";
} else {
room1.setBackgroundColor(Color.RED);
roomStat = "Red";
}
if (roomStat.equals("Green")) {
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = "BEING HOUSEKEPT";
DatabaseReference reference = mFirebaseDatabase1.child("Room1").child("RoomStatus");
reference.setValue(message);
Intent next1 = new Intent(getApplicationContext(), ReaderActivity3.class);
startActivity(next1);
}
});
} else if (roomStat.equals("Yellow")) {
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = "READY FOR INSPECTION";
DatabaseReference reference = mFirebaseDatabase1.child("Room1").child("RoomStatus");
reference.setValue(message);
Intent next1 = new Intent(getApplicationContext(), ReaderActivity2.class);
startActivity(next1);
}
});
} else {
room1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = "READY FOR HOUSEKEEPING";
DatabaseReference reference = mFirebaseDatabase1.child("Room1").child("RoomStatus");
reference.setValue(message);
Intent next1 = new Intent(getApplicationContext(), ReaderActivity.class);
startActivity(next1);
//I ALSO WANT TO PUT A CONDITION HERE FETCHING userType from Structure
// mFirebaseDatabase = mFirebaseInstance.getReference("Users").child("userKey");
//but doing this would mean that I would have to put a listener inside, would that be okay? I tried when this
//was working at first but it didin't and now the whole thing is not working
}
});
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) { //update UI here if error occurred.
}
});
}
Here's my structure:
Can you help me identify what's the problem with how i implemented this?
I see nothing wrong, try debugging. Android is buggy nowadays, especially when you're connecting to a cloud database. In the left side of the run button the bug shaped one. Debug.
Or maybe you could try to show your location which is your string, to check if you pulled the right info from your database. You can use logs. A guide can be found here
https://developer.android.com/studio/debug/am-logcat.html

Retrofit login button click not working with fragment

I have tried logging in with retrofit wherein the login button from activity login will redirect me to home activity if successful. Then I tried using fragments. I have two fragments on main activity that can replace each other which are login fragment and register fragment. Know, I know that if I want to use any of the fragment's elements, then I must implement an interface that the mainactivity must implement to be able to use let's say edittext, buttons from fragment. I have done this, but when I try to implement retrofit's asynchronous task in the login button method, when I click it, nothing is happening. I tried putting a toast in the same login button method and it works, but not the retrofit call.
Login fragment:
public class LoginLayout extends Fragment {
EditText schoolid;
EditText password;
Login login;
Button loginButton;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.login_layout, container, false);
schoolid = (EditText) view.findViewById(R.id.loginschoolid);
password = (EditText) view.findViewById(R.id.loginpassword);
loginButton = (Button) view.findViewById(R.id.login);
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String schoolidtext = schoolid.getText().toString();
String passwordtext = password.getText().toString();
login.loginButtonClicked(schoolidtext, passwordtext);
}
});
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try{
login = (Login) activity;
}catch(Exception e) {
}
}
public interface Login{
public void loginButtonClicked(String schoolid, String password);
}
}
MainActivity:
public void loginUser(String schoolid, String password) {
//Here we will handle the http request to insert user to mysql db
//Creating a RestAdapter
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ROOT_URL) //Setting the Root URL
.build(); //Finally building the adapter
//Creating object for our interface
LoginAPI api = adapter.create(LoginAPI.class);
api.loginUser(
//Passing the values
schoolid,
password,
//Creating an anonymous callback
new Callback<Response>() {
#Override
public void success(Response result, Response response) {
//On success we will read the server's output using bufferedreader
//Creating a bufferedreader object
BufferedReader reader = null;
//An string to store output from the server
String output = "";
//Initializing buffered reader
try {
reader = new BufferedReader(new InputStreamReader(result.getBody().in()));
//Reading the output in the string
output = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
if (output.equals("Successful")) {
isLoggedIn = true;
if(isLoggedIn == true) {
Intent i = new Intent(MainActivity.this, HomeActivity.class);
startActivity(i);
}
//Displaying the output as a toast
Toast.makeText(MainActivity.this, output, Toast.LENGTH_LONG).show();
}
}
#Override
public void failure(RetrofitError error) {
//If any error occured displaying the error as toast
Toast.makeText(MainActivity.this, error.toString(), Toast.LENGTH_LONG).show();
}
}
);
}
#Override
public void loginButtonClicked(String schoolid, String password) {
//this line doesn't work
loginUser(schoolid, password);
//this line works
Toast.makeText(MainActivity.this, "button clicked", Toast.LENGTH_LONG).show();
}
Fragments get attached to activity, the onFragmentInteraction is a call back method that your activity use to interact with the fragment
LoginFragment
Create a listener
private OnFragmentInteractionListener mListener;
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
void onLoginFragmentInteraction(String schoolidtext, String passwordtext);
}
Initialize the listener
#Override
public void onStart() {
super.onStart();
try {
mListener = (OnFragmentInteractionListener) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString()
+ " must implement OnFragmentInteractionListener");
}
}
Call the listener
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String schoolidtext = schoolid.getText().toString();
String passwordtext = password.getText().toString();
//call the listenner on the main activity
mListener.onLoginFragmentInteraction(schoolidtext, passwordtext);
}
});
MainActivity
Implement the call back :
public class MainActivity extends Activity
implements LoginFragment.OnFragmentInteractionListener{
}
Override it
#Override
public void onLoginFragmentInteraction(String schoolidtext, String passwordtext) {
loginUser(schoolid, password);
Toast.makeText(MainActivity.this, "button clicked", Toast.LENGTH_LONG).show();
}

Endless/Infinite Scrolling not working for gridview?

My app tries to get various information from an api call using Retrofit and Gson. This information needs to be displayed as a gridview and the gridview needs to repopulate on scrolling. As of now, I can get the first 10 items, and thats it. How to add the endless scrolling feature to this.
public class ProductListing extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.product_listing_act);
init();
}
public void productListingApiCall() {
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(base_url).setLogLevel(RestAdapter.LogLevel.FULL).build();
final ProductListingApi productListingApi =
restAdapter.create(ProductListingApi.class);
productListingApi.getFeed(file, operation_condition, search_string_condition, minprice_condition, maxprice_condition, mincusratings_condition,
maxcusratings_condition, discount_condition, catids_condition, brands_condition, affids_condition, start_row_condition, limit_condition,
orderby_condition, sortby_condition, new Callback<ProductListingPojo>() {
#Override
public void success(ProductListingPojo productListingPojo, Response response) {
final ProductListingPojo product = productListingPojo;
new Thread(new Runnable() {
#Override
public void run() {
product_key = Arrays.copyOf(product.getProductkey(),
product.getProductkey().length);
cs_category_id = Arrays.copyOf(product.getCsCategoryid(),
product.getCsCategoryid().length);
title = Arrays.copyOf(product.getTitle(),
product.getTitle().length);
price = Arrays.copyOf(product.getSellingprice(),
product.getSellingprice().length);
mrp = Arrays.copyOf(product.getMrp(),
product.getMrp().length);
discount = Arrays.copyOf(product.getDiscountpercent(),
product.getDiscountpercent().length);
image = Arrays.copyOf(product.getProductimageSmall1(),
product.getProductimageSmall1().length);
cus_agg_num = Arrays.copyOf(product.getCustratingAggNum(),
product.getCustratingAggNum().length);
}
}).run();
setAdapter();
}
#Override
public void failure(RetrofitError error) {
tv_title_header.setText(error.getMessage());
Log.e("error", error.getMessage());
}
});
}
void setAdapter() {
adapter = new ProductListingGridAdapter(this, title, image, price, mrp, discount);
gv_product_listing_act.setAdapter(adapter);
}
}
The init() in OnCreate() will initialise all the view and call the productListingApiCall() for the first time. The way the api works is that, i will request for the first 10 items (start_row_condition: 0 and limit: 10), then on reaching the bottom after scrolling it should add the next 10, hence i need to call the api with (start_row_condition: 10 and limit:10). How can i implement this.

App crash when I submit a new post to Parse

This is the only Place my app crashes and one of the more important features
The LogCat tells me:
java.lang.IllegalArgumentException: You must create this type of ParseObject using ParseObject.create() or the proper subclass.
at line 37.
I tried the ParseObject.create() however that just caused more problems (I may have done it incorrectly). How Should I code this?
Here is my newPost class:
public class newPost extends Activity {
private Button addButton;
private TextView postView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newpost);
postView = ((EditText) findViewById(R.id.postView));
addButton = ((Button) findViewById(R.id.addButton));
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//line 37 Below
ParseObject post = new ParseObject("Posts");
post.put("content", postView);
post.saveInBackground(new SaveCallback () {
#Override
public void done(ParseException e) {
if (e == null) {
setResult(RESULT_OK);
finish();
} else {
Toast.makeText(getApplicationContext(),
"Error saving: " + e.getMessage(),
Toast.LENGTH_SHORT)
.show();
}
}
});
}
});
}
Replace this line
ParseObject post = new ParseObject("Posts");
with this
ParseObject post = ParseObject.create("Posts");
Ensure that you've added the below line in the Application.java class where Parse is initialised
ParseObject.registerSubclass(Message.class);
In my case I had to remove the '#ParseClassName' annotation in my model class. My understanding is that if I have a parse model class 'Posts' and I call 'registerSubclass(yourclassname)' in Application, then all I need is
Post obj = new Post();
You probably made a mistake in initialising Parse in your Application class. Or forgot to put android:name=".YourApplicationClass" in your Manifest file.
I got this error because I forgot to register my parse class as a subclass in my application extension:
public class App extends Application
{
#Override
public void onCreate()
{
super.onCreate();
App application = this;
ParseObject.registerSubclass(Posts.class); // <-- This is what you need
Parse.enableLocalDatastore(this);
Parse.initialize(new Parse.Configuration.Builder(getApplicationContext())
.applicationId(EnvironmentConfig.appID)
.server(EnvironmentConfig.serverName)
.enableLocalDataStore()
.build());
ParseInstallation.getCurrentInstallation().saveInBackground();
}
}

Android: Avoid opening the dialog several times, but allow hide and shows the same dialog

I have an Activity with ViewPager PagerSlidingTabStrip for each page of my ViewPager has a fragment, and in each fragment realize an http request (using Volley) to load the data from the page, but when the request ends in error, type timeout or lost connection, I need to display a dialog with the option to redo the call to the server, the problem to prevent multiple dialogs are open for each error is resolved with the snippet:
See this solution here: http://www.jorgecoca.com/android-quick-tip-avoid-opening-multiple-dialogs-when-tapping-an-element/
#Override
public void show(FragmentManager manager, String tag) {
if (manager.findFragmentByTag(tag) == null) {
super.show(manager, tag);
}
}
When the user clicks the dialog button to try again, and the dialog closed and taken to check if there is internet connection, if I'm not, the dialog should be opened again, but the dialog is not displayed again, I believe that the tag does not was released to FragmentManager.
Code in Activity:
final Button mButton = ( Button ) this.findViewById( R.id.btn_opendialog );
final DialogFragmentHelper mDialog = new DialogFragmentHelper();
mDialog.setCallbackListener( new OnCallback() {
#Override
public void onCancel() {
}
#Override
public void onConfirm() {
// verify if network available
mDialog.show( MainActivity.this.getSupportFragmentManager(), DialogFragmentHelper.DIALOG_TAG );
}
} );
mButton.setOnClickListener( new OnClickListener() {
#Override
public void onClick( final View v ) {
mDialog.show( MainActivity.this.getSupportFragmentManager(), DialogFragmentHelper.DIALOG_TAG );
}
} );
Would someone have a suggestion of a workaround?
In order to maintain the structure that is ready in my project, and also keep something closer to my goal, which is to use no flags, nor pass control of a third dialogfragment to manage, arrived at a solution that'll take an hour as a result.
DialogFragmentHelper mDialog = new DialogFragmentHelper();
mDialog.setCallbackListener( new OnCallback() {
#Override
public void onCancel() {}
#Override
public void onConfirm() {
mDialog.dismissAllowingStateLoss();
if(networkAvailable == false){
new Handler().post( new Runnable() {
#Override
public void run() {
mDialog.show( MainActivity.this.getSupportFragmentManager(), DialogFragmentHelper.DIALOG_TAG );
}
} );
}else {
//do something here
}
}
} );
this way I guarantee that while several requests are sent to open the dialogfragment, only the first is executed, and closing the dialogfragment, I can quickly open it again if needed, as can happen in the scenario I'm working.
You could approach it with a singleton controller. E.g.:
package com.example.stackoverflowsandbox;
public class MyDialogController {
private static MyDialogController instance;
public static MyDialogController getInstance() {
if ( MyDialogController.instance == null ) {
MyDialogController.instance = new MyDialogController();
}
return MyDialogController.instance;
}
private boolean dialogOpenned;
private MyDialogController() {}
public void closeDialog() {
if ( this.dialogOpenned ) {
this.dialogOpenned = false;
// you close code...
}
}
public void openDialog() {
if ( !this.dialogOpenned ) {
this.dialogOpenned = true;
// your open code...
}
}
}

Categories

Resources