I'm struggling to find the best way to implement my update to the database
The code below is in the adapter for a list view, so each list item has its own seekbar.
The list is of homework assignments so each item has its own degree of completion which I need to persist to a database.
I have a business method which can do the database write, it just needs the id of the assignment and the new progress value.
private void attachProgressUpdatedListener(SeekBar seekBar) {
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) {
// need to update database with new progress here!
}
public void onStartTrackingTouch(SeekBar seekBar) {
// empty as onStartTrackingTouch listener not being used in
// current implementation
}
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// empty as onProgressChanged listener not being used in current
// implementation
}
});
}
the problem I'm having is getting a handle to my AssignmentHandler which deals with the database reads / writes. I can pass the assignment_id to my attachProgressUpdatedListener without any issues but I'm not sure this is the best way to go about it as I haven't got / not sure I want an instance of AssignmentHandler instantiated inside the ArrayAdapter.
You can store the element's database ID in each SeekBar's "tag" (setTag() and getTag() methods), and use that to update the database from the onStopTracking method.
Related
I came across a piece of code,now I am stuck with it.
SeekBar volumeControl=(SeekBar)findViewById(R.id.volumeSeekBar);
volumeControl.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,progress,0 );
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
Here I know that volumeControl is a variable of type SeekBar. In the second line of code volume control is set with a function setOnSeekBarChangeListener. I am unable to understand what's written inside the brackets of setOnSeekBarChangeListener. Can anyone please explain it in detail. I am just introduced to java and don't have much knowledge
This is a small piece of code to control volume using a seek bar.
Inside the brackets of onSeekBarChangeListener, we declare a new SeekBar.onSeekBarChangeListener which implements three methods :
onProgressChanged : This basically tracks the change in the seek bar and then sets the volume according to the amount of change.
onStartTrackingTouch : This methods contains the code which should be executed when the touch gesture starts.
onStopTrackingTouch:
This method contains the code which should be executed which the touch gesture stops.
I am trying to disable button after click in RecyclerView from Retrofit response.
Application is using RecyclerView to populate list and I am using Retrofit to communicate to back-end REST API. There are two buttons inside one item and Retrofit client is activated on click. And if response from API is successful button should be disabled. I came across on two problems:
first few items works just fine, but after few scrolls buttons I have never clicked on are disabled also;
second was that little few random buttons further on in list are still clickable.
public void onBindViewHolder(final NewsViewHolder holder, int position) {
holder.btnPositive.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// init Retrofit Client
JSONPlaceHolderAPI mAPIService;
mAPIService = ApiUtils.getAPIServiceFetch();
mAPIService.getNews(url).enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result>
response) {
holder.btnPositive.setVisibility(View.GONE);
}
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
// do code
}
});
}
});
holder.btnNegative.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
JSONPlaceHolderAPI mAPIService;
mAPIService = ApiUtils.getAPIServiceFetch();
mAPIService.getNews(url).enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result>
response) {
holder.btnNegative.setEnabled(false);
}
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
// do code
}
});
}
});
}
I suppose problem is somewhere in Retrofit where it uses background threads or AsyncTask.
This happens as the recycler view recycles(as the name suggests) the view that is visible to you and gives the same set of ids to every set of items which causes this problem .
This problem has 2 solution :
1) Stop the recycle behaviour of recyclerview as follows:-
#Override
public void onBindViewHolder(#NonNull MyViewHolder myViewHolder, int i) {
myViewHolder.setIsRecyclable(false);
}
But i strongly deny to use this cause recycling is reason why we use recyclerview.
2) Using a POJO Class:-
The best solution for it is to use a POJO class which will have two variables the first one is value and the second one is a boolean variable which show is the item disabled or not . Set the value of POJO boolean variable to true for the items u want to disable and in onBindViewHolder method only disable the buttons for the items which has false set in boolean variable .
If you still are confused contact me i will send you an example of it .
You need to hold states of those buttons. You can hold states in items(such as isNegativeEnabled, willPositiveDisplay etc.) of the list that populates recyclerview. When you click positive button, change willPositiveDisplay to false.
list[position].willPositiveDisplay = false;
And check list[position].willPositiveDisplay is true set visibility as visible, if not set as gone. And do this for negative button.
I'm trying out making an app using Android Studio and I want to constantly update a text view.
I at first thought I should use a loop but that ended up not even running for some reason.
TextView amount = findViewById(R.id.amountTextView);
final SeekBar seekBar = findViewById(R.id.seekBar);
int p = seekBar.getProgress() + 1;
amount.setText(String.valueOf(p));
});
}
}
With this method it doesn't update the results text view. I would like it to constantly update the text view so it shows what number the seek bar is on.
You will need an event for update the state of SeekBar and TextView, in this case I user a Handler(android.os) for update the views each 100 milliseconds of time, but you can use another event like the load of a web service or another.
In your case, it doesn't update because you just update the state of variable, but never update the state of seekbar, that is the reason it will never increment the current state.
private void startLoopUntilEnd() {
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
#Override
public void run() {
int progress = seekBar.getProgress();
textView.setText(String.valueOf(progress));
progress++;
seekBar.setProgress(progress);
startLoopUntilEnd();
}
};
if (currentState <seekBar.getMax()){
handler.postDelayed(runnable,100);
}
}
You can call this method from onCreate in case of Activity or onResume in case of Fragment and after it will go until the SeekBar is complete recursively.
If you want to change the max of seekBar, you can set it in xml or in code.
Use onSeekBarChangeListener:
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
amount.setTextprogress);
}
});
I am using RecyclerView to populate my CardView. Inside CardView, upon clicking on each card, I want to show a custom AlertDialog box with 4 fields. Once user fill those up and submit, I update my database.
Everything is working properly now. Only thing is, all these methods (AlerDialog, query database etc.) I used are inside my RecyclerView Adapter.
Upon reading some posts here in SO, i saw several people suggested against it, e.g. not to right down these kind of methods (specially Dialog) inside Adapter. So, my question is, whether i should rewrite my code or it is all the same performance-wise?
Below is part of my adapter:
public class CardHolderAdapter extends RecyclerView.Adapter<CardHolderAdapter.CardViewHolder>{
====== CONSTRUCTOR ========
====== VIEW HOLDER ========
====== onCreateViewHolder METHOD ========
#Override
public void onBindViewHolder(CardHolderAdapter.CardViewHolder holder, final int position) {
holder.textViewBookname.setText(cardHolderList.get(position).getTitle());
...............
...............
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
alertDialogWishlist(String ... args).show();
}
});
}
#Override
public int getItemCount() {
return cardHolderList.size();
}
public Dialog alertDialogWishlist(String ... args){
AlertDialog.Builder myDialog = new AlertDialog.Builder(context);
View layout = LayoutInflater.from((ActivityMyList) context).inflate(R.layout.alert_dialog_mylist_wishlist, null);
// DATABASE QUERY TO FETCH CUSTOM FIELDS VALUES (4 FILEDS IN TOTAL)
layout.findViewById(R.id.field1).setText(val1)
.....................
.....................
myDialog.setView(layout)
.setTitle(title)
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setPositiveButton(title, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// DATABASE CONNECTION TO UPDATE NEW VALUES
}
});
return myDialog.create();
}
}
There's no performance hit.
There's no direct performance hit to putting methods in your adapter class. This is a java class, like any other, that just implements the necessary classes for it to function as an adapter. Whether you put your dialog creator / database lookups, in their own class, in the activity, or leave them in the adapter....doesn't matter performance wise.
Cache database results.
That said, adapter methods get called frequently. Scrolling a listView adapter for instance would create dozens of calls to create the child views, and if you wrap database calls in one of these heavily called methods it could very well hang. There are things you can do to solve this problem like caching database values, using a single lookup, etc...
Moving methods out of the class is about access and modular design.
If other things are going to be calling the database, and the logic is not unique to the adapter, it should be placed in an area where other class methods can access it without needing to have an instance of adapter or even having the adapter class as part of the project.
I need to stored my listview that i create dynamically by a "add" button. Of course right now if i go out of application the items disappears. I tryied in this way but something's wrong
public class MainActivity extends Activity{
private EditText etInput;
private Button btnAdd;
private ListView lvItem;
private ArrayList<String> itemArrey;
private ArrayAdapter<String> itemAdapter;
/* Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setUpView();
// Eliminare un elemento al longClick con dialog di conferma
lvItem.setOnItemLongClickListener(new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View v,
final int position, long id) {
// TODO Auto-generated method stub
AlertDialog.Builder adb = new AlertDialog.Builder(
MainActivity.this);
adb.setTitle("Are you sure");
adb.setPositiveButton("Yes",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
itemArrey.remove(position);
itemAdapter.notifyDataSetChanged();
}
});
adb.setNegativeButton("No",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
adb.show();
return false;
}
});
lvItem.setClickable(true);
lvItem.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Object o = lvItem.getItemAtPosition(position);
Intent intent2 = new Intent(getApplicationContext(), MainActivity.class); // Mettere settings.class quando creata
MainActivity.this.startActivity(intent2);
}
});
}
private void setUpView() {
etInput = (EditText)this.findViewById(R.id.editText_input);
btnAdd = (Button)this.findViewById(R.id.button_add);
lvItem = (ListView)this.findViewById(R.id.listView_items);
itemArrey = new ArrayList<String>();
itemArrey.clear();
itemAdapter = new ArrayAdapter<String>(this, R.layout.customlistview,itemArrey);
lvItem.setAdapter(itemAdapter);
btnAdd.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
addItemList();
}
});
}
protected void addItemList() {
if (isInputValid(etInput)) {
itemArrey.add(0,etInput.getText().toString());
etInput.setText("");
itemAdapter.notifyDataSetChanged();
}
}
protected boolean isInputValid(EditText etInput2) {
// TODO Auto-generatd method stub
if (etInput2.getText().toString().trim().length()<1) {
etInput2.setError("Insert value");
return false;
} else {
return true;
}
}
// Shared preferences
protected void SavePreferences(String key, String value) {
// TODO Auto-generated method stub
SharedPreferences data = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = data.edit();
editor.putString(key, value);
editor.commit();
}
protected void LoadPreferences(){
SharedPreferences data = PreferenceManager.getDefaultSharedPreferences(this);
String dataSet = data.getString("LISTS", "None Available");
itemAdapter.add(dataSet);
itemAdapter.notifyDataSetChanged();
}
I don't know how "call" the shared preferences and i don't know if in this way it's correct. Right now nothing happen, nothing is saving. Someone can help me please? Thanks
You should look at this API training about activity life cycle:
http://developer.android.com/training/basics/activity-lifecycle/index.html
and also this:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
As you can see, your activity can be gone because the user actively destroy it (using the back button) or the system can destroy it. If they system destroy it you can use onSaveInstanceState to save the data and onCreate to retrieve it. In that case you do not have to use SharedPreferences - just use Bundle as described in the link.
However, if you want to persist your data when the user close it, you should save your data when the call back onDestroy() is called. And retrieve the data when onCreate() is called. onDestroy() is called before the system thinks that your activity is not needed anymore, like when the user click the "back" button. In that case you do have to use one of the storage method provided by android, including Shared preferences. Like someone else said, it requires a "key, value" mechanism, so it might not match 100% with what you do. Using sqlLite is a bit heavy weight for this task, since your data is not really of a table type either (a single column table, actually, which is still not database worthy IMO). I think the best way to store your list is to use internal file. When onDestroy() is called, grab all your data and save to a file. When onCreate() is called, read the file and repopulate your list. You can read about android file system, including internal files here:
http://developer.android.com/training/basics/data-storage/files.html
As a close note, if the user press the "Home" button, your activity will not be destroyed. If he then "Force close" your app then nothing will be saved. If you still want to save it even in that case, I suggest you to save your data when "onStop()" is called and reset your list when onStart() is called.
Right now nothing happen, nothing is saving.
That's because you never call your SavePreferences() method.
If you want to continue using SharedPreferences to store the data in your list, you will need to call SavePreferences() on every item in the list.
However, SharedPreferences are used for storing data in a key-value format. This means that every item in your list will require a key, and you need to know that key to retrieve the data. If your list can contain a variable number of items, SharedPreferences is likely not what you want.
I recommend reading the Storage Options documentation, which provides a complete example using Shared Preferences correctly, and discusses other options which may better suit your needs.