I have a status in my json object that was set to boolean. My main problem is that in every handled time let's say 5 secs it will add another set of status which is the previous status displayed and it has no end. I'm not sure what triggered this can anyone help me with this I'm just starting to learn android.
Update 2
You need to clear the old content of the TextView before appending any new content
//hardware
hardwareStatus.setText("") // Clear old response data from TextView
for (int i = 0; i < response.body().getHardware().length; i++){
// Your logic
}
//software
softwareStatus.setText("") // Clear old response data from TextView
for (int i = 0; i < response.body().getSoftware().length; i++){
// Your logic
}
Update 1
You're seeing the old results because your appending to the results TextView
hardwareStatus.append(spannable);
hardwareStatus.append("\n\n");
Just use
hardwareStatus.setText(spannable);
Old
From my understanding you are running into an infinite loop of api calls that is triggered every 5 seconds, if that is the case It's because you are calling the postDelayed function again inside the runnable, if you're looking to call the endpoint just one time then remove this line
handler.postDelayed(runnable = new Runnable() {
public void run() {
//do your function;
getSystemObject();
handler.postDelayed(runnable, apiDelayed); // Remove this
}
}, apiDelayed);
Another thing to note here is that you should be initializing the views in the
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
hardwareName = view.findViewById(R.id.hardware_name);
hardwareStatus = view.findViewById(R.id.hardware_status);
softwareName = view.findViewById(R.id.software_name);
softwareStatus = view.findViewById(R.id.software_status);
flagName = view.findViewById(R.id.flagreport_name);
}
Also you're building the retrofit instance every time you call the api, it's better to create a singleton for retrofit and call the create method to initialize a global variable in your fragment or activity, then use this variable in your function like this
// Global variable
private WebApi api = Retrofit.getInstance().create(WebApi.class);
then in any function call
api.getNameStatus();
Call getSystemObject from onViewCreated instead of from onResume.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
handler.postDelayed(runnable = new Runnable() {
public void run() {
//do your function;
getSystemObject();
handler.postDelayed(runnable, apiDelayed);
}
}, apiDelayed);
}
Related
I want to make a text view that will update the text after 12 seconds randomly from an array list, automatically.
My code is not working well, it just changes the text one time but I want it to change it every 12 sec.
Here is is the onCreate method of my fragment:
#SuppressLint("SetTextI18n")
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
TextView topStatus_tv = root.findViewById(R.id.TopStatus);
String[] topStatus = {
"Hello ", //0
"Welcome to your PERSONAL DICTIONARY",//1
"Hi Whats up beauty?",//2
"Good Evening, sir",//3
"how is the Weather",//4
"Get Motivated, go on",//5
"By upgrading your second language, open your mind and be more clever",//6
"Practice everyday!",//7
"Make good habits",//8
"Your HABITS will make a good person from you,\nnot just your Believes",//9
"Knock knock! who is it?\nits the programmer needs your donation",//10
"First make a good Believe, then make good habits\n(Good does not mean perfect)",//11
"Decrease blaming, increase accepting",//12
"You know? sometimes im tired from everything. ",//13
"Music is strange, isn't it?",//14
"you wanna see someone weird? goto setting, press donate button and choose 1000$.\nthen go look at the mirror",//15
"Spotify, IM COMING FOR YOU!!!",//16
"Don't work too much.\ngo hangout with your friends, their idiots",//17
"you know? In parallel worlds you are coding and I am using your app",//18
"When you are in a good mood, the world has to give you what you want",//19
"make a wall from others goodness.\nwhen they make a mistake, take one brick from wall, don't break it."//20
};
Handler handler = new Handler();
for (int i = 0; i < 100; i++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
int random = new Random().nextInt(20);
topStatus_tv.setText(topStatus[random]);
}
}, 12000);
}
return root;
}
Assign your Runnable to a variable. Then use the variable in postDelayed. At the end of your run() function call postDelayed with the Runnable-variable again with 12 seconds.
Remove your for loop and use a counter variable to limit the number of repetitions.
Something like this (without the counter):
class YourActivity {
// ...
private Handler handler = new Handler();
private Runnable runnable;
public View onCreateView() {
// ...
runnable = new Runnable() {
#Override
public void run() {
int random = new Random().nextInt(20);
topStatus_tv.setText(topStatus[random]);
handler.postDelayed(runnable, 12000);
}
};
handler.postDelayed(runnable, 12000);
// ...
}
}
You can give id to the textView and use onClickListener in your java code and setTime
I am using a fragment which shows differnet informations about an object. Inside onCreate of the fragment I retrieve some values from the object and store them in global variables:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
String serializedShow = getArguments().getString(SHOW_TO_LOAD);
mShow = (new Gson()).fromJson(serializedShow, Show.class);
mScope = mShow.getScope();
mLanguage = MainActivity.getSystemLanguage();
mLanguage = mLanguage.replace("_", "-");
mId = Integer.valueOf(mShow.getShowId()).toString(); //this line is important
Log.v(LOG_TAG, "DetailFragment onStart, Id is " + mId);
}
As you can see I assign to this variable a specific ID. I use the log to check if the value of mId is the correct one and it is. Everything works well so far.
Next int he code the user can click a button to upen up am url in the browser. The URls are different with each time this fragment is created (every time this fragment shows different stuff)
private void fetchIMDBId(){
Log.v(LOG_TAG, "starting IMDBAsyncTask with id " + mId);
new Async4().execute(mId);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_launch:
fetchIMDBId();
return true;
default:
break;
}
return false;
}
As you can see the method fetchIMDBId() gets called. I have a log line to check if the value of mId which was set before in onCreate is the same.
It is not the same, its a totally different value.
Specifically is the id of the object that was being displayed in a previous instance if this fragment.
Please tell me what I'm doing wrong. Thanks.
E: variable declaration
public class DetailFragment extends Fragment {
private static final String LOG_TAG = DetailFragment.class.getSimpleName();
...
private String mScope, mLanguage, mId;
...
#Override
public void onCreate(Bundle savedInstanceState) {
...
}
E: full source here
I believe you are not assigning your mId correctly to the Async task. You should apply the mid to the async task method so that the corresponding mId from each fragment is called
private void fetchIMDBId(String mId){
Log.v(LOG_TAG, "starting IMDBAsyncTask with id " + mId);
new Async4().execute(mId);
}
and then call the method within the fragment
fetchIMDBId(this.mId);
Try using this.mId and also check if your fragment object is same as previous one.
Call this.fetchIMDBId() instead.
Im trying to create a list here, but the issue is that after i fill the array daysList with information, everything is lost after i exit onResponse.
If i set the textview inside the onResponse method it works, but it does not if i do it outside (like in this case), i get null pointer exception.
I understand that i have to define the array as static to keep the data, but it's not working either! How do i fix this?
public class MainFragment extends Fragment {
private View view;
private RequestQueue requestQueue;
private WeatherAdapter weatherAdapter;
public static WeatherForecast weatherForecast;
public static WeatherForecast.List[] daysList;
private ListView listView;
private TextView textView;
String URL = "requestURL";
public void onCreate (Bundle savedInstanceState) { super.onCreate(savedInstanceState); }
public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
view = inflater.inflate(R.layout.main_fragment,null);
textView = (TextView) view.findViewById(R.id.textview);
requestQueue = Volley.newRequestQueue(getActivity());
JsonObjectRequest jsonWeatherRequest = new JsonObjectRequest(
URL,
null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
weatherForecast = parseWeatherToJson(response.toString());
daysList = weatherForecast.getList();
//textView.setText("Humidity is: " + daysList[0].getHumidity()); <--- If i set it here it works!
weatherAdapter.notifyDataSetChanged();
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.v(TAG, "On Error!");
}
}
);
requestQueue.add(jsonWeatherRequest);
textView.setText("Humidity is: " + daysList[0].getHumidity()); // <---- This throws nullpointer.
}
jsonWeatherRequest is a async request which hits the server and gets the response in onResponse() callback. When you are setting the TextView with the list value outside onResponse(), at that moment your request is not completed and thus your list is null.
So if you want to access the list, then you have to do that in onResponse() callback.
If i set the textview inside the onResponse method it works, but it does not if i do it outside
Net request is an asynchronous operation, so you have to write all the logic in the methods of callback object. That's why you have data inside the callback object, but you haven't them ouside.
Is there a way to use the array information outside the onResponse method?
Yea. Sure there is.
But you need to wait for the response to complete first!!
That is what is missing from your code.
This Q&A explains how to wait for a Volley request to complete:
Wait for result of Async Volley request and return it
But BEWARE that if you wait in the wrong place you are liable to lock up your app's user interface.
I'm still new to android development. I've been at this problem for some time but am still unable to figure out what to do on my own. In an Activity I set up a series of Runnables containing CountDownTimers. One executes after the next, but depending on which CountDownTimer is active, I need to pass a different Intent.extra to a fragment. I've tried setting my extra from inside Runnable, inside Run, and inside of the CountDownTimer onTick, and onFinish.
I fear I have way too much going on in my original Activity to post it, but here is the problem in essence.
public class MatchUpActivity extends Activity implements OpponentFragment.OnFragmentInteractionListener{
List mTotalDrafts;
Bundle mBundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_match_up);
mBundle = new Bundle();
mDraftUsernames = extras.getStringArrayList("DRAFT_LIST");
for (int i = 0; i < totalDrafts; i++) {
Handler delayhandler = new Handler();
delayhandler.postDelayed(new Runnable() {
//bundle.put("extra", totalDrafts.get(0))
public void run() {
//bundle.put("extra", totalDrafts.get(0))
getTimer();
}
}, mTodaysDraftTime + (i * singleDraftDuration) - Calendar.getInstance().getTimeInMillis());
}
}
CountDownTimer
private void getTimer() {
new CountDownTimer(singleDraftDuration, 1000) {
public void onTick(long millisUntilFinished) {
//bundle.put("extra", totalDrafts.get(0))
}
public void onFinish() {
//bundle.put("extra", totalDrafts.get(0))
list.remove(0)
}
}.start();
}
}
I am able to remove items from my list in onFinish, but after I do so I need to send the next element in the list as an extra.
I hope this is enough code to get my question across. I tried to change some things from my original code for simplicity. If there is something I am missing or a better way to do this, please, anybody let me know.
Define the Bundle as global variable in your Activity and not in a Method implementation.
I have been searching for an answer to my problem, but I seem to get none, despite of how many tutorials I followed, how many questions I've gone through and how many things I've tried to do what I want. Basically, I stumbled upon some good tips, and still couldn't manage to do what wanted.
THE PROBLEM
I am creating an Android Application that will use Fragments (alongside with tabs). In these fragments, I have crucial information relating the application, such as text boxes, and buttons. However, I want to do something really simple, which is updating one of my fragments as I come back to it (imagine I swipe back to a fragment, and I update it with the relevant information). Where is the information stored? On a node.js server, to which I call every time I want information. So for that, I created the following structure.
THE STRUCTURE
First of all, I started off creating my Activity.
public class CentralActivity extends FragmentActivity {
CentralPagerAdapter mCentralActivity;
ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_central);
tabHandler();
}
public void tabHandler() {
mCentralActivity = new CentralPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.CentralPager);
mViewPager.setAdapter(mCentralActivity);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position);
}
});
//Action Bar Stuff
}
}
With this said, I need my CentralPagerAdapter, which I created as follows.
public class CentralPagerAdapter extends FragmentStatePagerAdapter {
private int nSwipes = 3;
public CentralPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new CentralFragment();
Bundle args = new Bundle();
args.putInt(CentralFragment.ARG_OBJECT, i + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
return nSwipes;
}
}
And now, my fragment, which is only a class that contains all of my views, and options and so on.
public class CentralFragment extends Fragment {
public static final String ARG_OBJECT = "object";
private View rootView;
private RESTFunction currentFunction;
//Has the info I want
private ArrayList<Integer> tickets = new ArrayList<Integer>();
#SuppressLint("HandlerLeak")
private Handler threadConnectionHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (currentFunction) {
case GET_CLIENT_TICKETS:
handleGetTickets(msg);
break;
case BUY_CLIENT_TICKETS:
break;
default:
break;
}
}
};
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
final Bundle args = getArguments();
handleFragments(inflater, container);
getTicketInfo(null);
return rootView;
}
private void handleFragments(LayoutInflater inflater, ViewGroup container) {
Bundle args = getArguments();
if (args.getInt(ARG_OBJECT) == 1) {
rootView = inflater.inflate(R.layout.fragment_show_tickets,
container, false);
showTicketsHandler();
} else if (args.getInt(ARG_OBJECT) == 2) {
rootView = inflater.inflate(R.layout.fragment_buy_tickets,
container, false);
buyTicketsHandler();
} else {
rootView = inflater.inflate(R.layout.fragment_history_tickets,
container, false);
}
}
public void showTicketsHandler() {
//Get stuff from the tickets array that the REST call will handle
//And set them to boxes or radio buttons
}
public void buyTicketsHandler() {
//Get stuff from the tickets array that the REST call will handle
//And set them to boxes or radio buttons
//As well as button click listeners
}
public void getTicketInfo(ProgressDialog progDialog) {
//Connect to the thread to get the information
//In this case, I have no parameters
ConnectionThread dataThread = new ConnectionThread("myLink", Method.GET, null, threadConnectionHandler, progDialog);
dataThread.start();
}
//Get stuff from the resulting JSON and store it in the tickets ArrayList
private void handleGetTickets(Message msg) {
JSONObject ticketListing = (JSONObject) msg.obj;
try {
tickets.add(ticketListing.getInt("t1"));
tickets.add(ticketListing.getInt("t2"));
tickets.add(ticketListing.getInt("t3"));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
And then, I have my thread..
public class ConnectionThread extends Thread {
private ConnectionRunnable runConnection;
private Handler mHandler;
private ProgressDialog progDialog;
public ConnectionThread(String link, Method method, ArrayList<NameValuePair> payload, Handler handler, ProgressDialog progDialog) {
runConnection = new ConnectionRunnable(link, method.toString(), payload);
mHandler = handler;
this.progDialog = progDialog;
}
#Override
public void run() {
runConnection.run();
threadMsg();
if(progDialog != null)
progDialog.dismiss();
}
public JSONObject getJSON() {
return runConnection.getResultObject();
}
private void threadMsg() {
Message msgObj = mHandler.obtainMessage();
msgObj.obj = getJSON();
mHandler.sendMessage(msgObj);
}
}
And ConnectionRunnable is where I run my HttpURLConnection.
SO WHAT DO I NEED?
Basically, what I'm trying to do, is to get the ticket information from the ConnectionThread BEFORE I load all my view and update them. Plus, I want to be able to swipe back and forth, and update my information on the array as I swipe through the screens (if I go to the second screen, the tickets will update, and if I come back to the first, they will re-update). So basically, call the ConnectionThread everytime I swipe around. If that is possible that, is.
WHAT HAVE I TRIED?
I've tried several things already, and all of them didn't actually help..
The usage of ProgressDialogs to stop the UI Thread on the onCreateView method of the fragment (no use, because it returns the rootView before it handles everything);
Making the UI Thread sleep for 1 second (I don't know why, it blocks all of them);
Overriding the instantiateMethod() of the Adapter, although I think I didn't do it correctly;
Overriding the saveState() of the Adapter, in order to prevent its saved states, and to then get new ticket information;
Giving the fragments tags to update their rootViews on the Adapter, but to no avail;
Getting the information in the activity, and everytime I make a purchase (second fragment), restart the whole activity to get the tickets, which I believe is a really, really bad solution.
I've read several articles, and I still couldn't find my answers.. It's really frustrating. Because it's something so simple, however, the fact that I have to run the HTTP calls on a different thread delays the whole UI updating process.
I've also read the AsyncTask's method. However, I feel like both Threads and AsyncTasks end up in the same.
WHAT TO DO NOW?
Well, that's what I was hoping to find. Because it ends up being annoying as it is.
POSSIBLE REASONS
Is it because I'm separating all classes into spread files, therefore making my work difficult?
Thank you for your time, guys, hope we can find a solution or something.
THE EDIT
So basically, after 4 hours of reading documents and tutorials, I figured that what I needed was setOffscreenPageLimit(int). However, it can't be set to 0, so I will have to do with a setOnPageChangeListener. Now, to figure how to refresh the fragment, and I'll be as good as new.
Alright, it works perfectly! Basically, I did this:
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
((CentralFragment)((CentralPagerAdapter) mViewPager.getAdapter()).instantiateItem(mViewPager, position)).refresh();
getActionBar().setSelectedNavigationItem(position);
}
});
Where my .refresh is:
public void refresh() {
Bundle args = getArguments();
if (args.getInt(ARG_OBJECT) == 0) {
getTicketInfo(0);
} else if (args.getInt(ARG_OBJECT) == 1) {
getTicketInfo(1);
buyTicketsHandler();
} else {
//To Handle Later
}
}
It's as simple as refreshing the page before you go to it. Why didn't I remember this before..? So, here's the reference for those who ever need this!