How to solve Unchecked cast in android without suppressing the warning - android

How do I solve this issue without using SuppressWarning("uncheckedcast"), this there any way to check the object before casting it or any other way to solve this issue.
The problem is inside onLoadFinished(). I am using the data for different datatypes as you can see, first as boolean and then List.
Thank you in advance.
package com.howaboutthis.satyaraj.wallpaper;
import android.support.v4.app.Fragment;
import android.support.v4.content.Loader;
import android.content.Context;
import android.content.DialogInterface;
import android.support.v4.app.LoaderManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class FragmentChanging extends Fragment implements LoaderManager.LoaderCallbacks {
private ProgressDialog dialog;
public FragmentChanging(){
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup
container,
Bundle savedInstanceState) {
final View view =
inflater.inflate(R.layout.fragment_changing_wallpaper, container, false);
getLoaderMangaer.init(0,null,FragmentChanging.this);
return view;
}
#Override
public Loader onCreateLoader(int id, Bundle args) {
if (id == 0 || id == 2){
dialog.setMessage("Loading Settings...");
dialog.show();
}
return new TestInternetLoader(getContext());
}
return null;
}
#Override
public void onLoadFinished(Loader loader, Object data) {
int id = loader.getId();
if (id == 0 || id == 2){
boolean check = (Boolean) data;
if (check)
if (dialog.isShowing()) dialog.dismiss();
}
else if(id == 3)
List<Bitmap> bitmaps = (List<Bitmap>) data; //Unchecked cast
}
#Override
public void onLoaderReset(Loader loader) {
}
}

You can get rid of the lint warning by using a LoaderManager.LoaderCallbacks<List<Bitmap>> . If you want to do so, you'll have to change (almost) every occurrence of Loader to Loader<List<Bitmap>>.
(An exception seems to be onLoaderReset(Loader loader))
Moreover, if you use a custom AsyncTaskLoader it would have to extend AsyncTaskLoader<List<Bitmap>>.
Then you can write
#Override
public void onLoadFinished(Loader<List<Bitmap>> loader, List<Bitmap> data) {
List<Bitmap> bitmaps = data;
}
EDIT
If the suggested approach is not possible because the type of data may vary you can check for the types you are going to handle like this:
if (data instanceof List<?>){
List temp = (List)data;
// do what's required for List data
// (if necessary do a type check on list elements)
if (tempList.size() > 0){
Object firstItem = tempList.get(0);
if (firstItem instanceof Bitmap){
// now you know that your Loader gave you a List with at least one Bitmap
List<Bitmap> bitmaps = new ArrayList<>();
for (Object item: tempList){
if (item instanceof Bitmap){
bitmaps.add((Bitmap) item);
}
}
}
}
}
else if (data instanceof Boolean){
boolean check = (Boolean) data;
if (check){
// handle Boolean data
}
}

Related

How to remove or hide the application button

I'm new to android studio and I'm trying to remove a button from my videos app
I have 4 buttons in my app Android : Recent,Featured,Popular,Random and Live.
I would like to delete the Live button, but I am not able to
If necessary I can take a screenshot of my android studio.
I don't necessarily need to remove the button if I have another way to just hide it, that would be a big help too
I followed my code:
If necessary I can take a screenshot of my android studio.
package com.app.materialvideo.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.duolingo.open.rtlviewpager.RtlViewPager;
import com.app.materialvideo.Config;
import com.app.materialvideo.R;
import com.app.materialvideo.utils.CustomTabLayout;
import com.app.materialvideo.utils.SharedPref;
import static com.app.materialvideo.utils.Constant.FILTER_LIVE;
import static com.app.materialvideo.utils.Constant.FILTER_video;
import static com.app.materialvideo.utils.Constant.ORDER_FEATURED;
import static com.app.materialvideo.utils.Constant.ORDER_LIVE;
import static com.app.materialvideo.utils.Constant.ORDER_POPULAR;
import static com.app.materialvideo.utils.Constant.ORDER_RANDOM;
import static com.app.materialvideo.utils.Constant.ORDER_RECENT;
public class FragmentTabLayout extends Fragment {
public RelativeLayout tab_background;
public CustomTabLayout smartTabLayout;
public ViewPager viewPager;
public RtlViewPager viewPagerRTL;
public int tab_count = 5;
SharedPref sharedPref;
View view;
public FragmentTabLayout() {
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (Config.ENABLE_RTL_MODE) {
view = inflater.inflate(R.layout.fragment_tab_layout_rtl, container, false);
} else {
view = inflater.inflate(R.layout.fragment_tab_layout, container, false);
}
sharedPref = new SharedPref(getActivity());
tab_background = view.findViewById(R.id.tab_background);
smartTabLayout = view.findViewById(R.id.tabs);
if (sharedPref.getIsDarkTheme()) {
tab_background.setBackgroundColor(getResources().getColor(R.color.colorToolbarDark));
smartTabLayout.setSelectedIndicatorColors(getResources().getColor(R.color.colorAccentDark));
} else {
tab_background.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
}
initViewPager();
return view;
}
public void initViewPager() {
if (Config.ENABLE_RTL_MODE) {
viewPagerRTL = view.findViewById(R.id.view_pager_rtl);
viewPagerRTL.setOffscreenPageLimit(tab_count);
viewPagerRTL.setAdapter(new ViewPagerAdapter(getChildFragmentManager(), tab_count));
smartTabLayout.post(() -> smartTabLayout.setViewPager(viewPagerRTL));
} else {
viewPager = view.findViewById(R.id.view_pager);
viewPager.setOffscreenPageLimit(tab_count);
viewPager.setAdapter(new ViewPagerAdapter(getChildFragmentManager(), tab_count));
smartTabLayout.post(() -> smartTabLayout.setViewPager(viewPager));
}
}
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
int noOfItems;
public ViewPagerAdapter(FragmentManager fm, int noOfItems) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
this.noOfItems = noOfItems;
}
#NonNull
#Override
public Fragment getItem(int position) {
if (position == 0) {
return Fragmentvideo.newInstance(ORDER_RECENT, FILTER_video);
} else if (position == 1) {
return Fragmentvideo.newInstance(ORDER_FEATURED, FILTER_video);
} else if (position == 2) {
return Fragmentvideo.newInstance(ORDER_POPULAR, FILTER_video);
} else if (position == 3) {
return Fragmentvideo.newInstance(ORDER_RANDOM, FILTER_video);
} {
return Fragmentvideo.newInstance(ORDER_LIVE, FILTER_LIVE);
}
}
#Override
public int getCount() {
return noOfItems;
}
#Override
public String getPageTitle(int position) {
if (position == 0) {
return getResources().getString(R.string.menu_recent);
} else if (position == 1) {
return getResources().getString(R.string.menu_featured);
} else if (position == 2) {
return getResources().getString(R.string.menu_popular);
} else if (position == 3) {
return getResources().getString(R.string.menu_random);
} {
return getResources().getString(R.string.menu_live);
}
}
}
}
From my understanding, you don't want to remove a classic button, but a Tab button used inside a TabLayout.
If you want to remove it , easiest way would be to remove the last condition in your if else statements that deal with displaying and handling this button.
From the code you posted should be
Here
{
return getResources().getString(R.string.menu_live);
}
and here, as i think these two deal with the "Live" button.
{
return Fragmentvideo.newInstance(ORDER_LIVE, FILTER_LIVE);
}
As well as reduce the value passed to the ViewPager Adapter "noOfItems" variable by 1. In your situation, I think the variable is "tabCount" and that should be set to 4 ( down from 5). I see it's used in many places and changing this should deal with all cases.
If hiding is also good, then this code should also work.
Just use it inside onCreateView(). The code is in Kotlin and works on a default TabLayout, but i am not sure if it will work as i see you use a custom one.
tabLayout?.getTabAt(4)?.view?.visibility = View.GONE
You need to pass the index of the tab you want to hide, so in your case, you have 5 tabs, so the index is 4.
If you know id of the button.
view.findViewById(R.id.btn_firs).setVisibility(View.GONE);

How to get the current item inside FragmentPagerAdapter?

I have the following code -
#Override
public void sendDeviceIdResult(String deviceId, boolean isAlreadyExist) {
int currentItem = viewPager.getCurrentItem();
Fragment item = adapter.getItem(currentItem);
if (item instanceof PhoneStateAndAgeVerificationFragment) {
Dialog dialog = ((PhoneStateAndAgeVerificationFragment) item).getProgressDialog();
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
Intent intent = new Intent();
intent.putExtra(KEY_DEVICE_ID, deviceId);
intent.putExtra(KEY_IS_SUCCESS, !isAlreadyExist);
setResult(RESULT_OK, intent);
finish();
}
The issue is that one the line of getItem(position) it does not get the actual reference of the current fragment, but creates a brand new one.
I want to get the reference to the current one and dismiss it's AlertDialog on it.
I know this has been asked many times but I got completely lost while reading all the solutions, so if someone could please show me something that is relevant to my case?
here is my PhoneStateAndAgeVerificationFragment -
package com.onemdtalent.app.ui.verification;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.core.content.ContextCompat;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import com.onemdtalent.app.App;
import com.onemdtalent.app.R;
import com.onemdtalent.app.core.base.AbstractFragment;
import butterknife.BindView;
import butterknife.OnCheckedChanged;
import butterknife.OnClick;
public class PhoneStateAndAgeVerificationFragment extends AbstractFragment{
#BindView(R.id.frag_verification_phone_checkbox_age)
CheckBox checkBoxAge;
private AlertDialog.Builder mBuilder;
private Dialog mDialog;
public static Fragment newInstance() {
return new PhoneStateAndAgeVerificationFragment();
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mBuilder = new AlertDialog.Builder(getActivity(), R.style.DialogTheme);
}
#OnCheckedChanged(R.id.frag_verification_phone_checkbox_age)
void OnAgeCheckedChanged(CompoundButton button, boolean checked) {
if (checked) {
button.setTextColor(ContextCompat.getColor(button.getContext(), R.color.black));
}
}
#OnClick(R.id.verification_button_got_it)
void onBtnGotItClicked(View view) {
if (!checkBoxAge.isChecked()) {
checkBoxAge.setTextColor(ContextCompat.getColor(checkBoxAge.getContext(), R.color.accent_red));
return;
}
showProgressDialog();
if (getContext() instanceof VerificationPageListener) {
((VerificationPageListener) getContext()).onPageAgreed();
}
}
#Override
protected int getLayoutResourceId() {
return R.layout.layout_verification_phone_age;
}
private void showProgressDialog(){
if (mBuilder == null) {
mBuilder = new AlertDialog.Builder(App.getAppContext());
}
mBuilder.setCancelable(false);
mBuilder.setView(R.layout.custom_proggress_dialog);
mDialog = mBuilder.create();
mDialog.show();
}
public Dialog getProgressDialog() {
return mDialog;
}
}
Try adding the following code in your FragmentPagerAdapter, this has worked for me.
public class MyPagerAdapter extends FragmentPagerAdapter {
private Fragment mCurrentFragment;
public Fragment getCurrentFragment() {
return mCurrentFragment;
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
}
Call the getCurrentFragment() method from your sendDeviceIdResult() method
I hope this helps.

setAdapter is not calling getView.

I know this question has been asked several times, but the solutions have been specific to the askers' problems. Consequently, none of those solutions helped me, even though I tried following all of their suggestions.
So here goes.
I have a movies Activity like this. Notice that I have a MoviesAdapter inner class, that's supposed to populate the moviesDisplay ListView.
package com.example.midtermexam;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.database.DataSetObserver;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class MoviesActivity extends Activity {
public String url;
public ListView moviesDisplay;
public static ArrayList<Movie> thisMovies;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movies);
url=getIntent().getExtras().getString("url");
moviesDisplay = (ListView)findViewById(R.id.listView1);
new AsyncMoviesGet(this).execute(url);
}
public void populateListView()
{
Log.d("listview","adapter created");
Log.d("listview","Listview declared");
Log.d("listview","adapter populated");
moviesDisplay.setAdapter(new MoviesListAdapter());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.movies, menu);
return true;
}
private class MoviesListAdapter extends ArrayAdapter<Movie> {
public MoviesListAdapter() {
super(MoviesActivity.this, R.layout.movies_activity_listview, thisMovies);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Make sure we have a view to work with (may have been given null)
View movieView = convertView;
if (movieView == null) {
movieView = getLayoutInflater().inflate(R.layout.movies_activity_listview, parent, false);
}
// Find the car to work with.
return movieView;
}
}
}
The populateListView() method is called from an AsyncTask called AsyncMoviesGet, whose postExecute() looks like this.
#Override
protected void onPostExecute(ArrayList<Movie> result) {
if(result != null){
m.thisMovies = result;
m.populateListView();
Log.d("demo", result.toString());
} else{
Log.d("demo", "null result");
}
}
You can see the Log messages inside the populateListView() method. These 3 statements get executed. However, the setAdapter() function doesn't seem to call the "GetView" function.
Add stuff to ArrayAdapter at least, use mAdapter.addAll():
private MoviesListAdapter mAdapter;
. . . . . .
#Override
protected void onCreate(Bundle savedInstanceState) {
. . . . .
mAdapter = new MoviesListAdapter();
moviesDisplay.setAdapter(mAdapter);
}
. . . . .
protected void onPostExecute(ArrayList<Movie> result) {
if(result != null){
m.thisMovies = result;
mAdapter.clear();
mAdapter.addAll(result);
mAdapter.notifyDatasetInvalidated();
Log.d("demo", result.toString());
} else{
Log.d("demo", "null result");
}
}
You have to add a constructor to your Custom Adapter class, one that takes a context, resource id & a data structure containing the items you'd like to display, in this case your thisMovies.
public MoviesListAdapter(Context context, int resourceId,
ArrayList<String> viewItems)
{
super(context, resourceId, viewItems);
}
Then you have to construct your adapter based on the results you've received in your onPostExecute(). Before this is done, create an instance variable in the activity which will be used to store the adapter.
MoviesListAdapter mMovieAdapter = null;
Afterwards, construct it by changing this
moviesDisplay.setAdapter(new MoviesListAdapter());
to something like below
if(thisMovies != null && thisMovies.size() > 0) {
mMovieAdapter = new MoviesListAdapter(getApplicationContext(), R.layout.movies_activity_listview, thisMovies);
moviesDisplay.setAdapter(mMovieAdapter);
} else {
Log.w("MyApplication","onPostExecute() did not return any items!");
}
You should initialise and call adapter by this way..........this is just an e.g. you need to modify it according to your controls:
ListView lv = (ListView) v.findViewById(R.id.listview1);
ListViewAdapter adapter = new ListViewAdapter(container.getContext(),
android.R.layout.simple_list_item_1, R.id.textview1);
adapter.notifyDataSetChanged();
lv.setAdapter(adapter);
And inside the custom adapter class, its constructor should also have these kind of parameters:
public ListViewAdapter(Context context,int resource, int textViewResourceId, List<YourObjectType> items) {
super(context,resource,textViewResourceId, items);
this.context1 = context;
// TODO Auto-generated constructor stub
}

Out-of-sync ArrayAdapter with Autocomplete

I have 3 classes, I wish to use the autocomplete text box to show user certain data (aka cities) from a web service (rest api). I've used this implementation on various features of my own application, but for some reason, there's a synchronization problem within the textchangedlistener...
CitiesArrayAdapter.java (to show a different view, in my case the "city, state"):
package com.android.lzgo.adapters;
import java.util.ArrayList;
import java.util.List;
import com.android.lzgo.activities.LiftSearchActivity;
import com.android.lzgo.activities.R;
import com.android.lzgo.models.City;
import com.android.lzgo.models.Lift;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class CitiesArrayAdapter extends ArrayAdapter<City> {
private static final String TAG = CitiesArrayAdapter.class.getName();
private final ArrayList<City> cities;
private int viewResourceId;
public CitiesArrayAdapter(Context context, int textViewResourceId, ArrayList<City> results) {
super(context, textViewResourceId, results);
this.cities = results;
this.viewResourceId = textViewResourceId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// assign the view we are converting to a local variable
View v = convertView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(viewResourceId, null);
}
City i = cities.get(position);
Log.d(TAG, "Here is my value: " + i);
if (i != null) {
TextView tt = (TextView) v.findViewById(android.R.id.text1);
Log.d(TAG, "Name: " + i.getName() + ", " + i.getProvince_name());
if (tt != null){
tt.setText("Name: " + i.getName() + ", " + i.getProvince_name());
}
}
// the view must be returned to our activity
return v;
}
}
CitiesResponderFragment.java (this is how I get my values from my rest api):
package com.android.lzgo.fragment;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import com.android.lzgo.activities.LiftSearchActivity;
import com.android.lzgo.definitions.Constants;
import com.android.lzgo.models.City;
import com.android.lzgo.service.LzgoService;
import com.google.gson.Gson;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Toast;
public class CitiesResponderFragment extends LzgoResponderFragment {
private static String TAG = CitiesResponderFragment.class.getName();
private List<City> mCities;
ArrayAdapter<City> adapter;
private String enteredCharacters;
LiftSearchActivity activity;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
activity = (LiftSearchActivity) getActivity();
// This gets called each time our Activity has finished creating itself.
getCities();
}
private void getCities() {
if (mCities == null && activity != null) {
Intent intent = new Intent(activity, LzgoService.class);
intent.setData(Uri.parse(Constants.REST_CITIES_AUTOCOMPLETE));
Bundle params = new Bundle();
params.putString("search", getenteredCharacters());
intent.putExtra(LzgoService.EXTRA_HTTP_VERB, LzgoService.GET);
intent.putExtra(LzgoService.EXTRA_PARAMS, params);
intent.putExtra(LzgoService.EXTRA_RESULT_RECEIVER, getResultReceiver());
// Here we send our Intent to our RESTService.
activity.startService(intent);
}
}
#Override
public void onRESTResult(int code, String result) {
Log.e(TAG, Integer.toString(code));
Log.e(TAG, result);
// Check to see if we got an HTTP 200 code and have some data.
if (code == 200 && result != null) {
mCities = getCitiessFromJson(result);
adapter = activity.getArrayAdapter();
adapter.clear();
for( City city : mCities){
//debugging
Log.d(TAG, "City : " + city.getName());
adapter.add(city);
adapter.notifyDataSetChanged();
}
getCities();
}
else {
Activity activity = getActivity();
if (activity != null && code == 400) {
Toast.makeText(activity, result, Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(activity, "Failed to load lzgo data. Check your internet settings.", Toast.LENGTH_SHORT).show();
}
}
private List<City> getCitiessFromJson(String json) {
ArrayList<City> cityList = new ArrayList<City>();
Gson gson = new Gson();
try {
JSONObject citiesWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray cities = citiesWrapper.getJSONArray("cities");
for (int i = 0; i < cities.length(); i++) {
//JSONObject city = cities.getJSONObject(i);
String jsonCity = cities.getString(i);
City city = gson.fromJson( jsonCity, City.class );
//Log.e(TAG, "Hurray! Parsed json:" + city.getString("name"));
//cityList.add(city.getString("name"));
cityList.add(city);
}
}
catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return cityList;
}
public String getenteredCharacters() {
return enteredCharacters;
}
public void setenteredCharacters(String characters) {
this.enteredCharacters = characters;
}
}
LiftSearchActivity.java (My FragmentActivity):
package com.android.lzgo.activities;
import java.util.ArrayList;
import com.android.lzgo.adapters.CitiesArrayAdapter;
import com.android.lzgo.fragment.CitiesResponderFragment;
import com.android.lzgo.models.City;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AutoCompleteTextView;
import android.widget.DatePicker;
public class LiftSearchActivity extends FragmentActivity{
private static final String TAG = LiftSearchActivity.class.getName();
// User lift input
private AutoCompleteTextView autoCityFrom;
private AutoCompleteTextView autoCityTo;
private DatePicker date;
private CitiesArrayAdapter adapter;
private ArrayList<City> mCities ;
int year , month , day;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lift_search);
mCities = new ArrayList<City>();
adapter = new CitiesArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line, mCities);
autoCityFrom = (AutoCompleteTextView) findViewById(R.id.cityFrom);
autoCityTo = (AutoCompleteTextView) findViewById(R.id.cityTo);
adapter.setNotifyOnChange(true);
autoCityFrom.setAdapter(adapter);
autoCityTo.setAdapter(adapter);
autoCityFrom.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// no need to do anything
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (((AutoCompleteTextView) autoCityFrom).isPerformingCompletion()) {
return;
}
if (charSequence.length() < 2) {
return;
}
String query = charSequence.toString();
getCities(query);
}
public void afterTextChanged(Editable editable) {
}
});
autoCityTo.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
// no need to do anything
}
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if (((AutoCompleteTextView) autoCityTo).isPerformingCompletion()) {
return;
}
if (charSequence.length() < 2) {
return;
}
String query = charSequence.toString();
getCities(query);
}
public void afterTextChanged(Editable editable) {
}
});
date = (DatePicker) findViewById(R.id.dpResult);
}
public void searchLifts(View view) {
Intent intent = new Intent(this, LiftsResultActivity.class);
//While autocomplete doesn't work hardcore value...
intent.putExtra("from", Integer.toString(9357)); // Sherbrooke
intent.putExtra("to", Integer.toString(6193)); // Montreal
intent.putExtra("date", Integer.toString(date.getMonth()+1) + "-" + Integer.toString(date.getDayOfMonth()) + "-" + Integer.toString(date.getYear()));
startActivity(intent);
}
public void getCities(String query) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
CitiesResponderFragment responder = (CitiesResponderFragment) fm.findFragmentByTag("RESTResponder");
responder = new CitiesResponderFragment();
responder.setenteredCharacters(query);
ft.add(responder, "RESTResponder");
ft.commit();
}
public CitiesArrayAdapter getArrayAdapter() {
// TODO Auto-generated method stub
return adapter;
}
}
I get the correct result and all. But my service doesn't seem to populate my array adapter in my activity, when I try to show my first "city", my adapter contains nothing. I wonder if I have to put a notifydatasetchanged (I tried, but doesn't work). I'm kind of confuse... any pointers?
While debugging the application I noticed that the properties mObjects of
the ArrayAdapter is cleared even if the associated ArrayList has
elements, and then properties mOriginalValues is filled with the
Strings loaded the first time.
Without seeing the full code base(+ data), I don't know if someone can pin point the reason for your code's failure. But I think the problem comes more from the way you setup the whole auto complete related code than some obvious line error. Below I'll try to address some of this issues(from my point of view) :
First of all, in the TextWatcher from LiftSearchActivity you call the getCities() method which adds, each time the user modifies the auto complete text, a Fragment to the Activity. I really doubt you want this, you should probably look at having only one Fragment in the Activity on which to call a refresh(or update) method, passing it the new filter text. If the user rotates the phone those fragments will also be recreated because of the configuration change.
Second, in the CitiesResponderFragment class you call the fragment's getCities() method(if you don't have any data) in onActivityCreated which start an update service(?!). Now related to the first point, you could end up doing a lot of unnecessary queries, for example if the user enter 4 characters and then decides to delete one of the characters as it was incorrect you'll end up with 5 added fragments, from which 3 will make the service start/query for data.
And last, I'm not sure if you understand how the AutoCompleteTextView works under the hood. In order to provide the drop down with the suggestions the AutoCompleteTextView widget will filter its adapter(adapter.getFilter()) and show as suggestions the items that match the filter. I don't know if you set some threshold on the AutoCompleteTextView but initially the auto complete will be empty for the first 3 characters entered as you start with an empty list of items when you first setup the Activity. The first two characters will not show anything because you start with an empty list and you don't add any new fragments(charSequence.length() < 2). The third character will most likely also not show anything, because the overhead of creating the fragment, starting the service and fetching the data will almost for sure be greater then doing the work of the adapter filtering(which will still see the initially empty list). I don't know if you tested, but from this fourth character the adapter should have some elements in it and the filtering should show something. Clearing the adapter and adding new data in it willl only make that data available to the next character entered in the AutoCompleteTextView.
The proper way of doing the filtering would be to further extend your adapter and implement the getFilter() method to return your own Filter implementation which would query the data store for new filtered items. The filtering method runs on a background thread, with a little work I think you could implement your current logic with the Service and the REST callback.
See example of the REST API Autocomplete : https://subversion.assembla.com/svn/rockitsearch-android/
Although it is part of my service, it can also serve as an example of how you can integrate your own REST API in AutoCompleteTextView control. If you are interested in autocomplete 3rd party service, here you go : www.rockitsearch.com

Having trouble with Custom Support Loader

I am setting up to use the Loader pattern and had issues using the cursor approach, so I have refactored my code because my tables do not use _id as the primary key because of the use of association tables and I setup my code to use the same basic structure as the LoaderCustomSupport.java example from the android developer site. All of the code works without errors and I can see that I have the proper data back and ready for the ListFragment to display but after the onLoadFinished call back completes the setData on the adapter the getView is never called. My getView looks like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PhoneNumberListHolder holder;
if (row == null) {
row = mInflater.inflate(R.layout.phonenumber_row, parent, false);
holder=new PhoneNumberListHolder(row);
row.setTag(holder);
} else {
holder = (PhoneNumberListHolder)row.getTag();
}
holder.populateForm(this.phoneNumbers.get(position));
return row;
}
I am trying to use the holder pattern, but I am thinking that maybe it is part of my issue. Any ideas where I might be going wrong?
Here is the loader code (Like I said I followed the Google example for my first run changing what I thought I would need)
The Abstract Loader for my Class
/*
* Custom version of CommonsWare, LLC, AbstractCursorLoader
*
*/
package myApp.service.data;
import java.util.List;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
abstract public class AbstractPhoneNumberLoader extends AsyncTaskLoader<List<PhoneNumber>> {
abstract protected List<PhoneNumber> buildPhoneNumber();
List<PhoneNumber> lastPhoneNumber=null;
public AbstractPhoneNumberLoader(Context context) {
super(context);
}
#Override
public List<PhoneNumber> loadInBackground() {
List<PhoneNumber> data=buildPhoneNumber();
if (data!=null) {
// Make sure we fill the person
data.size();
}
return (data);
}
/**
* This will run on the UI thread, routing the results from the
* background to the consumer of the Person object
* (e.g., a PhoneNumberListAdapter).
*/
#Override
public void deliverResult(List<PhoneNumber> data) {
if (isReset()) {
// An async query attempted a call while the loader is stopped
if (data!=null) {
data.clear();
data=null;
//not sure the best option here since we cannot close the List object
}
return;
}
List<PhoneNumber> oldPhoneNumber=lastPhoneNumber;
lastPhoneNumber=data;
if (isStarted()) {
super.deliverResult(data);
}
if (oldPhoneNumber!=null && oldPhoneNumber!=data && oldPhoneNumber.isEmpty()) {
oldPhoneNumber.clear();
oldPhoneNumber=null;
}
}
/**
* Start an asynchronous load of the requested data.
* When the result is ready the callbacks will be called
* on the UI thread. If a previous load has completed
* and is still valid the result may be passed back to the
* caller immediately.
*
* Note: Must be called from the UI thread
*/
#Override
protected void onStartLoading() {
if (lastPhoneNumber!=null) {
deliverResult(lastPhoneNumber);
}
if (takeContentChanged() || lastPhoneNumber==null) {
forceLoad();
}
}
/**
* Must be called from the UI thread, triggered by
* a call to stopLoading().
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task
cancelLoad();
}
/**
* Must be called from the UI thread, triggered by a
* call to cancel(). Here, we make sure our Person
* is null, if it still exists and is not already empty.
*/
#Override
public void onCanceled(List<PhoneNumber> data) {
if (data!=null && !data.isEmpty()) {
data.clear();
}
}
/**
* Must be called from the UI thread, triggered by a
* call to reset(). Here, we make sure our Person
* is empty, if it still exists and is not already empty.
*/
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (lastPhoneNumber!=null && !lastPhoneNumber.isEmpty()) {
lastPhoneNumber.clear();
}
lastPhoneNumber=null;
}
}
The Data Loader
/*
* Custom version of CommonsWare, LLC, SQLiteCursorLoader
*
*/
package myApp.service.data;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.List;
import myApp.service.data.ActorDbAdapter;
import android.content.Context;
public class PhoneNumberDataLoader extends AbstractPhoneNumberLoader {
ActorDbAdapter db=null;
protected final String actorId;
protected final String _PHONENUMBERID = "PhoneNumberId";
protected SimpleDateFormat dateFormat = new SimpleDateFormat("dd/mm/yyyy");
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* #param ctx the Context within which to work
*/
public PhoneNumberDataLoader(Context ctx, String actorId) {
super(ctx);
this.actorId = actorId;
getHelper(ctx);
}
// Get a database connection
private void getHelper(Context ctx) {
if (db==null) {
db=new ActorDbAdapter(ctx);
}
db.open();
}
// Loader Methods
/**
* Runs on a worker thread and performs the actual
* database query to retrieve the PhoneNumber List.
*/
#Override
protected List<PhoneNumber> buildPhoneNumber() {
return(db.readPhoneById(actorId));
}
/**
* Writes a semi-user-readable roster of contents to
* supplied output.
*/
#Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.print(prefix);
writer.print("actorId=");
writer.println(actorId);
}
public void insert(PhoneNumber data, String actorId) {
new InsertTask(this).execute(db, data, actorId);
}
// Saved for Later, get Reads and Writes working first
// public void update(PhoneNumber data, String actorId, String whereClause, String[] whereArgs) {
// new UpdateTask(this).execute(db, data, actorId, whereClause, whereArgs);
// }
//
// public void delete(String actorId, String phoneNumberId, String whereClause, String[] whereArgs) {
// new DeleteTask(this).execute(db, actorId, phoneNumberId, whereClause, whereArgs);
// }
public void execSQL(String actorId) {
new ExecSQLTask(this).execute(db, actorId);
}
private class InsertTask extends ContentChangingTask<Object, Void, Void> {
InsertTask(PhoneNumberDataLoader loader) {
super(loader);
}
#Override
protected Void doInBackground(Object... params) {
ActorDbAdapter db=(ActorDbAdapter)params[0];
PhoneNumber data=(PhoneNumber)params[1];
int actorId=Integer.parseInt((String)params[2]);
db.createPhoneNumber(data, actorId);
return(null);
}
}
// Saved for Later, get Reads and Writes working first
// private class UpdateTask extends
// ContentChangingTask<Object, Void, Void> {
// UpdateTask(PhoneNumberDataLoader loader) {
// super(loader);
// }
//
// #Override
// protected Void doInBackground(Object... params) {
// ActorDbAdapter db=(ActorDbAdapter)params[0];
// String table=(String)params[1];
// int actorId=Integer.parseInt((String)params[2]);
// String where=(String)params[3];
// String[] whereParams=(String[])params[4];
//
// db.updatePhoneNumber(table, values, where, whereParams);
//
// return(null);
// }
// }
//
// private class DeleteTask extends
// ContentChangingTask<Object, Void, Void> {
// DeleteTask(PhoneNumberDataLoader loader) {
// super(loader);
// }
//
// #Override
// protected Void doInBackground(Object... params) {
// ActorDbAdapter db=(ActorDbAdapter)params[0];
// int actorId=Integer.parseInt((String)params[1]);
// int phoneNumberId=Integer.parseInt((String)params[2]);
// String where=(String)params[3];
// String[] whereParams=(String[])params[3];
//
// db.deletePhoneNumber(table, where, whereParams);
//
// return(null);
// }
// }
private class ExecSQLTask extends
ContentChangingTask<Object, Void, Void> {
ExecSQLTask(PhoneNumberDataLoader loader) {
super(loader);
}
#Override
protected Void doInBackground(Object... params) {
ActorDbAdapter db=(ActorDbAdapter)params[0];
String actorId=(String)params[1];
db.readPhoneById(actorId);
return(null);
}
}
}
Here is my full ListAdapter
package myApp.planner.utilities;
import java.util.ArrayList;
import java.util.List;
import myApp.planner.R;
import myApp.planner.codes.PhoneOrAddressTypeCode;
import myApp.service.data.PhoneNumber;
import myApp.service.data.PhoneNumberListData;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
public class PhoneNumberListAdapter extends ArrayAdapter<PhoneNumber> {
private List<PhoneNumber> phoneNumbers;
private final LayoutInflater mInflater;
private Activity activity;
public PhoneNumberListAdapter(Activity a, int textViewResourceId) {
super(a, textViewResourceId);
activity = a;
mInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setData(List<PhoneNumber> data) {
if (this.phoneNumbers==null) {
this.phoneNumbers = new ArrayList<PhoneNumber>();
}
this.phoneNumbers.clear();
if (data != null) {
for (PhoneNumber phoneNumber : data) {
this.phoneNumbers.add(phoneNumber);
}
}
}
public static class PhoneNumberListHolder {
private TextView actorid=null;
private TextView phonenumberid=null;
private TextView phonetype=null;
private TextView phonenumber=null;
private CheckBox isprimary=null;
PhoneNumberListHolder(View row) {
actorid=(TextView)row.findViewById(R.id.actorid);
phonenumberid=(TextView)row.findViewById(R.id.phonenumberid);
phonetype=(TextView)row.findViewById(R.id.txtphonetype);
phonenumber=(TextView)row.findViewById(R.id.txtphonenumber);
isprimary=(CheckBox)row.findViewById(R.id.isprimary);
}
//void populateForm(ArrayList<PhoneNumberListData> c, int position) {
void populateForm(PhoneNumber data) {
//PhoneNumberListData data = c.get(position);
// Attempt to add the Actor ID
if (actorid != null){
actorid.setText(data.getActor().get(0).getActorId()==0 ? "0": Integer.toString(data.getActor().get(0).getActorId()));
}
// Attempt to add the Phone Number Item ID
if (phonenumberid != null){
phonenumberid.setText(data.getPhoneNumberId()==0 ? "0": Integer.toString(data.getPhoneNumberId()));
}
// Attempt to add the Phone Number Type
if (phonetype != null){
phonetype.setText(data.getPhoneType()==null ? "": PhoneOrAddressTypeCode.valueOf(data.getPhoneType()).toString());
}
// Attempt to add the Phone Number
if (phonenumber != null){
phonenumber.setText(data.getPhoneNumber1()==null ? "": data.getPhoneNumber1());
}
// Attempt to add the is Primary Flag
if (isprimary != null){
isprimary.setChecked(data.getIsPrimary()==0 ? Boolean.FALSE: Boolean.TRUE);
}
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PhoneNumberListHolder holder;
if (row == null) {
row = mInflater.inflate(R.layout.phonenumber_row, parent, false);
holder=new PhoneNumberListHolder(row);
row.setTag(holder);
} else {
holder = (PhoneNumberListHolder)row.getTag();
}
holder.populateForm(this.phoneNumbers.get(position));
return row;
}
}
The ListFragment:
package myApp.planner;
import java.util.ArrayList;
import java.util.List;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SearchViewCompat;
import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
import android.text.TextUtils;
import android.content.Intent;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.view.ContextMenu;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import myApp.planner.R;
import myApp.planner.utilities.PhoneNumberListAdapter;
import myApp.service.data.PhoneNumber;
import myApp.service.data.PhoneNumberDataLoader;
public class ActorPhoneNumberListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<PhoneNumber>> {
public final static String ID_EXTRA="myapp.planner.actorid";
protected final static String TAG = "ActorPhoneNumberListFragment";
private static final int ADD_ID=Menu.FIRST + 1;
private static final int DELETE_ID=Menu.FIRST + 3;
private PhoneNumberListAdapter mAdapter=null;
private PhoneNumberDataLoader loader=null;
private String mCurFilter;
private String actorId = "0";
//private SharedPreferences prefs=null;
OnActorPhoneNumberListListener listener=null;
OnQueryTextListenerCompat mOnQueryTextListenerCompat;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.actorId = getActivity().getIntent().getExtras().getString(ID_EXTRA).toString();
}
#Override
public void onResume() {
super.onResume();
Bundle args=getArguments();
if (args!=null) {
loadPhoneNumbers(args.getString(ID_EXTRA));
}
// init Empty Test for no Phone numbers Found
// Add the menu options that we need to manage the list
setHasOptionsMenu(true);
// Hookup the dbAdapter and create a blank adapter
initList();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onListItemClick(ListView list, View view, int position, long id) {
if (listener!=null) {
//We will actually want the PhoneNumber Id here for the popup edit screen
String mId = actorId;
listener.onActorPhoneNumberListSelected(mId);
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.phonenumber_opton, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==R.id.addNewPhone) {
//add();
return(true);
} else if (item.getItemId()==R.id.help) {
startActivity(new Intent(getActivity(), HelpPage.class));
return(true);
} else if (item.getItemId()==R.id.phoneRefresh) {
//startActivity(new Intent(getActivity(), ActorPhoneNumberListFragment.class));
//We may just need to refresh the loader
return(true);
} else
return(super.onOptionsItemSelected(item));
}
public void setOnActorPhoneNumberListListener(OnActorPhoneNumberListListener listener) {
this.listener=listener;
}
public void loadPhoneNumbers(String actorId) {
this.actorId=actorId;
}
private void initList() {
mAdapter=new PhoneNumberListAdapter(getActivity(), R.layout.phonenumber_row);
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
getActivity().getSupportLoaderManager().initLoader(0, null, this);
}
public interface OnActorPhoneNumberListListener {
void onActorPhoneNumberListSelected(String actorId);
}
#Override
public Loader<List<PhoneNumber>> onCreateLoader(int loaderId, Bundle args) {
loader= new PhoneNumberDataLoader(getActivity(), actorId);
return(loader);
}
#Override
public void onLoadFinished(Loader<List<PhoneNumber>> loader, List<PhoneNumber> data) {
// Now give the data to the adapter
mAdapter.setData(data);
mAdapter.notifyDataSetChanged();
//setListAdapter(mAdapter);
// Show the list
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
#Override
public void onLoaderReset(Loader<List<PhoneNumber>> arg0) {
// TODO Auto-generated method stub
mAdapter.setData(null);
}
}

Categories

Resources