BaseAdaptor usage for Dynamic Content - java

Im currently doing some android developer that lists items in a ListView, we have created a WebView that add's a JavaScript interface to our page and our page sends information via the JavaScript interface. this all works as expected, so we set up a class called HangoutManager that extends a BaseAdapter, we have implemented several methods in there such as add/remove and exists.
This all works fine and now were at the point where need to use the BaseAdapter to update the ViewList when there changes to the Array Stack.
We can't seem to get it too work, the getView() function never get's called to generate an item. here is some code.
onCreate
public void onCreate(Bundle savedInstanceState)
{
//Call parent to construct the Activity
super.onCreate(savedInstanceState);
//Create Instance of HangoutManager, must be called here
HangoutManagerList = HangoutManager.Instance(this);
//Set the content view to the main ListView
setContentView(R.layout.main);
//instantiate the WebView
CanopyWebView = new CanopyWebView(this);
setListAdapter(HangoutManagerList);
}
HangoutManager
public class HangoutManager extends BaseAdapter
{
public static HangoutManager _Instance;
private ArrayList<JSONObject> DataSet = new ArrayList<JSONObject>();
protected LayoutInflater Inflater;
public static HangoutManager Instance(Context context)
{
if(_Instance == null)
{
_Instance = new HangoutManager(context);
Log.v("HangoutManager", "Instance Created");
}
return _Instance;
}
public HangoutManager(Context context)
{
this.Inflater = LayoutInflater.from(context);
}
public boolean remove(String id)
{
try
{
for(int i=0 ; i< DataSet.size() ; i++ )
{
if(DataSet.get(i).getString("id").equals(id))
{
DataSet.remove(i);
Log.v("HangoutManager", "hangout Removed");
return true;
}
}
}
catch (JSONException e)
{
Log.e("HangoutManager::exists",e.getMessage());
return false;
}
return false;
}
public boolean add(String hangout)
{
try
{
JSONObject HangoutJson = new JSONObject(hangout);
if(this.exists(HangoutJson.getString("id")))
{
this.remove(HangoutJson.getString("id"));
}
DataSet.add(HangoutJson);
Log.v("HangoutManager", "hangout Added");
notifyDataSetChanged();
}
catch(JSONException e)
{
Log.e("HangoutManager",e.getMessage());
}
return true;
}
public boolean exists(String id)
{
try
{
for(int i=0 ; i< DataSet.size() ; i++ )
{
if(DataSet.get(i).getString("id").equals(id))
{
Log.v("HangoutManager", "hangoutExists: " + id);
return true;
}
}
}
catch (JSONException e)
{
Log.e("HangoutManager::exists",e.getMessage());
return false;
}
return false;
}
#Override
public int getCount()
{
return DataSet.size();
}
#Override
public Object getItem(int position)
{
return DataSet.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(int position, View view, ViewGroup viewGroup)
{
if(view == null)
{
view = Inflater.inflate(R.layout.item1, viewGroup, false);
}
//Get the JSONObject for the Item
JSONObject entity = DataSet.get(position);
//Set the JSONObject as the tag for the row
view.setTag(entity);
//return the view to be drawn
return view;
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"
android:id="#android:id/list">
</ListView>
item1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:background="#FFFFFFFF"
android:gravity="center_vertical"
android:text="#string/app_name"
android:textColor="#FF000000"
android:visibility="visible" />
</LinearLayout>
StackTrace (not error stacktrace)
http://pastebin.com/1ftkiLBF
The section about is where we attempt to break but it never breaks at that point, am we doing something wrong ?
Update
The application seems to crash sometime during the notifyDataSetChanged() calls.

You shouldn't call the inflater like this.
Use the following syntax to get an Inflater to use from your getView()
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Also about the stacktrace, it looks like your JS interface callbacks are executed in background. You cannot modify the data collection binded to the ListView nor call updateNotifyDataset() from a background thread.
But you can ask the UIThread to do it for you by calling your add method like this:
yourActivityInstance.runOnUiThread(new Runnable() {
public void run() {
yourAdapterInstance.add(newHangout);
}});

Related

Can't setup my RecyclerView to display whole data from API callback

For a longer period of time, I was tried to make this app works, but unfortunately, I've stuck for good. I would like to display hourly forecast in the RecyclerView, but actually I can't, because the program will display last value of the JSON response. I've tried to print everything in console - just for testing purposes, and I've find out that if I use the for loop, then everything works just fine (but unfortunately only in the console) but as long as I don't wanted to hard code the value that I want to receive:
for(int i = 0; i<11; i++)
I wanted to do something like this:
for(int i = 0; i<list.size(); i++)
but it'll display again just one value. How I may finally solve that? Can I have any prompts? The response from the API callback is properly for sure. Here's some code:
Adapter
List<ForecastModel> forecastData = new ArrayList<>();
#NonNull
#Override
public ForecastViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_hourly, parent, false);
return new ForecastViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ForecastViewHolder holder, int position) {
ForecastModel model = forecastData.get(position);
holder.hourlyTemperature.setText(String.valueOf(model.getHourlyForecast().get(position).getTemp()));
));
}
#Override
public int getItemCount() {
return forecastData.size();
}
public void setForecastData(List<ForecastModel> list){
this.forecastData = list;
notifyDataSetChanged();
}
class ForecastViewHolder extends RecyclerView.ViewHolder {
TextView hourlyTemperature;
ForecastViewHolder(#NonNull View itemView) {
super(itemView);
hourlyTemperature = itemView.findViewById(R.id.hourly_temperature);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ForecastViewModel mViewModel;
private List<ForecastModel> mForecastList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewModel = new ForecastViewModel(getApplication());
RecyclerView recyclerView = findViewById(R.id.forecastRecyclerView);
recyclerView.setLayoutManager( new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
recyclerView.setHasFixedSize(true);
ForecastAdapter adapter = new ForecastAdapter();
recyclerView.setAdapter(adapter);
mViewModel.getForecastLiveData().observe(this, new Observer<List<ForecastModel>>() {
#Override
public void onChanged(List<ForecastModel> list) {
if (mForecastList.size() > 0){
mForecastList.clear();
}
if (list != null){
mForecastList.addAll(list);
adapter.setForecastData(mForecastList);
}
}
});
}
}
ViewModel
public class ForecastViewModel extends AndroidViewModel {
private MutableLiveData<List<ForecastModel>> forecastData;
private static ForecastRepository repository;
public ForecastViewModel(#NonNull Application application) {
super(application);
repository = ForecastRepository.getInstance();
forecastData = repository.getForecastLiveData();
}
public MutableLiveData<List<ForecastModel>> getForecastLiveData(){
return forecastData;
}
}
Repository
private static ForecastRepository instance;
private ForecastInterface api;
private ForecastRepository(){
api = ForecastRetrofitBuilder.getRetrofitBuilder();
}
public static ForecastRepository getInstance(){
if (instance == null){
instance = new ForecastRepository();
}
return instance;
}
public MutableLiveData<List<ForecastModel>> getForecastLiveData(){
MutableLiveData<List<ForecastModel>> liveData = new MutableLiveData<>();
api.getForecast(35,136,"metric", API_KEY).enqueue(new Callback<ForecastModel>() {
#Override
public void onResponse(Call<ForecastModel> call, Response<ForecastModel> response) {
if (!response.isSuccessful()){
Log.w(TAG, "onResponse: !successful "+response.code());
}
liveData.setValue(Collections.singletonList(response.body()));
}
#Override
public void onFailure(Call<ForecastModel> call, Throwable t) {
Log.w(TAG, "onFailure: "+t.getMessage());
}
});
return liveData;
}
}
ActivityMain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".View.MainActivity"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/forecastRecyclerView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollbars="vertical"/>
</LinearLayout>
forecast_hourly.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/hourly_temperature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
There could be many reasons for this, but one obvious reason is:
liveData.setValue(Collections.singletonList(response.body()));
the live data will always have a single item.
And here, you are adding that list which has a single item always, to mForecastList.
if (mForecastList.size() > 0){
mForecastList.clear();
}
if (list != null){
mForecastList.addAll(list);
adapter.setForecastData(mForecastList);
}

android - FragmentPagerAdapter only showing the first fragment in all views

I want to display Fragments in a ViewPager however it is only showing the first Fragment in the view tabs. The only fragment that gets shown is the one returned at postion 0 in the getItem(0 method - this fragment is displayed in subsequent views.
FragmentPagerAdapter:
public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
public SimpleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new WorldFragment();
} else if (position == 1) {
return new PoliticsFragment();
} else if (position == 2) {
return new TechnologyFragment();
} else if (position == 3) {
return new ScienceFragment();
} else if (position == 4) {
return new SportsFragment();
} else if (position == 5) {
return new FoodFragment();
} else if (position == 6) {
return new TravelFragment();
} else if (position == 7) {
return new MoviesFragment();
} else if (position == 8) {
return new FashionFragment();
} else {
return new OpinionFragment();
}
}
#Override
public int getCount() {
return 10;
}
}
Fragment:
public class WorldFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<Story>> {
public static final String LOG_TAG = WorldFragment.class.getName();
private static final String NY_TIMES_REQUEST_URL = "https://api.nytimes.com/svc/topstories/v2/world.json?api-key=<API KEY REMOVED>;
private StoryAdapter mAdapter;
private TextView mEmptyTextView;
private View rootView;
public WorldFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.story_list, container, false);
mAdapter = new StoryAdapter(getActivity(), new ArrayList<Story>());
final ListView listView = (ListView) rootView.findViewById(R.id.story_list);
mEmptyTextView = (TextView) rootView.findViewById(R.id.empty_textview);
listView.setEmptyView(mEmptyTextView);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Story currentStory = mAdapter.getItem(position);
String url = currentStory.getmURL();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
}
});
ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (isConnected) {
LoaderManager loaderManager = getActivity().getLoaderManager();
loaderManager.initLoader(0, null, this);
} else {
View loadingIndicator = rootView.findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
mEmptyTextView = (TextView) rootView.findViewById(R.id.empty_textview);
mEmptyTextView.setText(R.string.no_internet_connection);
}
return rootView;
}
#Override
public android.content.Loader<List<Story>> onCreateLoader(int i, Bundle bundle) {
return new StoryLoader(getActivity(), NY_TIMES_REQUEST_URL);
}
#Override
public void onLoadFinished(android.content.Loader<List<Story>> loader, List<Story> stories) {
mAdapter.clear();
View loadingIndicator = rootView.findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
mEmptyTextView.setText(R.string.no_new_stories);
if (stories != null && !stories.isEmpty()) {
mAdapter.addAll(stories);
}
}
#Override
public void onLoaderReset(android.content.Loader<List<Story>> loader) {
mAdapter.clear();
}
#Override
public void onStop() {
super.onStop();
}
}
ViewPager XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.topworldstories.MainActivity">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
List XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent">
<ListView
android:id="#+id/story_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="true" />
<TextView
android:id="#+id/empty_textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone"
tools:text="No new stories"/>
<ProgressBar
android:id="#+id/loading_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_centerInParent="true"/>
</LinearLayout>
I am unsure of what is causing this. Any help is appreciated
it is only showing the first Fragment multiple times in the view tabs
Two possibilities I see, both of which are copy-paste errors.
1) You didn't change this URL (notice world.json)
private static final String NY_TIMES_REQUEST_URL = "https://api.nytimes.com/svc/topstories/v2/world.json?api-key=<API KEY REMOVED>";
2) You didn't use a different layout.
rootView = inflater.inflate(R.layout.story_list, container, false);
But since your data seems to be consistent, I'm guessing #1 is true.
If you have 10 different URL's that you want to display in the same "fragment layout", you do not need 10 separate Fragment files.
For example, one Fragment
public class NyTimesFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<Story>> {
public static final String LOG_TAG = NyTimesFragment.class.getName();
private static final String NY_TIMES_URL = "nyTimesURL";
private StoryAdapter mAdapter;
private TextView mEmptyTextView;
private View rootView;
public NyTimesFragment(String url) {
Bundle b = new Bundle();
b.putExtra(NY_TIMES_URL, url); // Pass URL here
setArguments(b);
}
public NyTimesFragment() {
// Required empty public constructor
}
#Override
public android.content.Loader<List<Story>> onCreateLoader(int i, Bundle bundle) {
// Load url here
String url = getArguments().getString(NY_TIMES_URL);
return new StoryLoader(getActivity(), url);
}
That you pass any NyTimes URL to
public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
// List of NyTimes topics
private String[] topics = { "world", "politics" };
// !!! Do NOT store this in your app... !!!
private static final String API_KEY = "XXXXX";
public SimpleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
private String getURL(String apiKey, String topic) {
return String.format(
"https://api.nytimes.com/svc/topstories/v2/%s.json?api-key=%s",
topic, apiKey);
}
#Override
public int getCount() {
return topics.length; // Assuming each fragment goes to NyTimes
}
#Override
public Fragment getItem(int position) {
final String url = getURL(topics[position], API_KEY);
// Call the other constructor
return new NyTimesFragment(url);
} // done... no if statements.
Something to consider to make this somewhat better would be Retrofit + Gson...
Ok so the issue here is I was using the same loader id in initloader for each fragment & this is why the same data was being loaded. The loader id needs to be unique for each fragment for this to work.

Recyclerviews in ViewPager

I'm trying to get this working: I basically want two Recyclerviews in one ViewPager. I followed this Tutorial: http://android-java-development.blogspot.de/2012/05/system.html, but it doesn't seem to work. I looks like the view pager is empty and the recycler view doesn't show up.
Here's my layout code:
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/pager_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="#dimen/tab_height">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/accent"/>
</android.support.v4.widget.SwipeRefreshLayout>
And my PageAdapter:
public class NewsPagerAdapter extends PagerAdapter {
private Context context;
private Vector<RecyclerView> recyclerViewList;
private String[] titles;
public NewsPagerAdapter(Context context, int titlesId) {
this.context = context;
this.recyclerViewList = new Vector<>();
setTitles(titlesId);
}
public void add(RecyclerView recyclerView) {
recyclerViewList.add(recyclerView);
}
public RecyclerView.Adapter getAdapterForViewAtIndex(int index) {
return recyclerViewList.get(index).getAdapter();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(recyclerViewList.get(position),
new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 100)
);
return container;
}
#Override
public int getCount() {
return recyclerViewList.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
public void setTitles(int titles) {
this.titles = context.getResources().getStringArray(titles);
}
}
And my onCreatView method:
GridLayoutManager layoutManager1 = new GridLayoutManager(getActivity(), getResources().getInteger(R.integer.news_column_count));
GridLayoutManager layoutManager2 = new GridLayoutManager(getActivity(), getResources().getInteger(R.integer.news_column_count));
RecyclerView listView1 = new RecyclerView(getActivity());
RecyclerView listView2 = new RecyclerView(getActivity());
listView1.setLayoutManager(layoutManager1);
listView2.setLayoutManager(layoutManager2);
NewsAdapter adapter1 = new NewsAdapter(getActivity(), null);
NewsAdapter adapter2 = new NewsAdapter(getActivity(), null);
adapter1.setOnItemClickListener(this);
adapter2.setOnItemClickListener(this);
listView1.setAdapter(adapter1);
listView2.setAdapter(adapter2);
newsPagerAdapter.add(listView1);
newsPagerAdapter.add(listView2);
newsViewPager.setAdapter(newsPagerAdapter);
Here I'm passing the cursor object to the adapter:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
((NewsAdapter) newsPagerAdapter.getAdapterForViewAtIndex(0)).swapCursor(data);
}
You have to extend FragmentPagerAdapter or FragmentStatePagerAdapter in order to easily embed RecyclerView. If you are going to update your ViewPager contents during its lifecycle it is strictly recommended to use FragmentStatePagerAdapter
You will have to create additional fragment layout, containing RecyclerView.
If you wish to update your ViewPager with SwipeRefreshLayout, don't wrap it with SwipeRefreshLayout. Instead, you must have SwipeRefreshLayout inside fragment layout.
Therefore for your fragment you may get the following xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/categoryList"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
And create additional Fragment class, which will inflate that layout and implement methods, that you will need to update refresh indicator status.
A bit old example is found here:
http://developer.android.com/training/implementing-navigation/lateral.html
If you wish to connect your ViewPager with new support library TabLayout, it is easily one with:
tabLayout.setupWithViewPager(viewPager);
Finally, if you will update your "fragmented" ViewPager, don't try to reset the adapter, as fragments are managed not with adapter, but with FragmentManager. It is wiser to update content of corresponding RecyclerViews
public class MyFragmentedPagerAdapter extends FragmentStatePagerAdapter {
private final TabLayout mTabLayout;
private final SwipeRefreshLayout.OnRefreshListener mRefreshListener;
private Vector<PriceListFragment> fragmentList;
private Vector<String> titles;
public MyFragmentedPagerAdapter(FragmentManager fm, MyComplexData data, OnCartActionListener listener, TabLayout tabLayout, SwipeRefreshLayout.OnRefreshListener refreshListener) {
super(fm);
mTabLayout = tabLayout;
// external refresh listener, that will trigger an updateData()
mRefreshListener = refreshListener;
fragmentList = new Vector<>();
titles = new Vector<>();
updateData(data);
}
public void updateData(MyComplexData data) {
boolean updateTabs = false;
boolean hasNewData = false;
Vector<String> newTitles = new Vector<>();
int position = 0;
for(TabContents tabContents : data.getTabContents()) {
if(tabContents.getListContents() == null)
continue;
hasNewData = true;
boolean isNewFragment;
MyFragment fragment;
try {
fragment = fragmentList.get(position);
isNewFragment = false;
} catch (ArrayIndexOutOfBoundsException e) {
fragment = new MyFragment();
isNewFragment = true;
}
// Update the data, title and hide update indicator of SwipeRefreshLayout
fragment.setTabContents(tabContents);
newTitles.add(tabContents.getName());
if(isNewFragment) {
fragment.setRefreshListener(mRefreshListener);
fragmentList.add(fragment);
}
position++;
}
if(!hasNewData)
return;
// we need to decide, whether to update tabs
if(titles.size() != newTitles.size()) {
updateTabs = true;
} else {
for(position = 0; position < titles.size(); position++) {
if(!titles.get(position).equals(newTitles.get(position))) {
updateTabs = true;
break;
}
}
}
titles = newTitles;
notifyDataSetChanged();
if(updateTabs)
mTabLayout.setTabsFromPagerAdapter(this);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
// You need to override this method as well
#Override
public int getItemPosition(Object object) {
MyFragment fragment = (MyFragment) object;
String title = (String) fragment.getTitle();
int position = titles.indexOf(title);
if (position >= 0) {
return position;
} else {
return POSITION_NONE;
}
}
#Override
public int getCount() {
return titles.size();
}
#Override
public CharSequence getPageTitle(int position) {
return fragmentList.get(position).getTitle();
}
}
Your MyFragment class has to implement getTitle() method.

Printing SQLite entries into a ListView

I am having some trouble learning the ins and outs of the SQLite world. I have some code that is allowing me to enter data into a DB. But what i want to do is return this data into a listview. At the moment all I could figure out to do was to have each row printed in a toast after a new entry is added. Can someone please show me how to alter my code to print it in a listview? Or to even look at my code and see that i am going about it in the right way. Thanks
This is the code i am using which calls a display record function
//---get all Records---
com.example.rory.dbtest.DBAdapter db = new com.example.rory.dbtest.DBAdapter(this);
db.open();
Cursor c = db.getAllRecords();
if (c.moveToFirst())
{
do {
DisplayRecord(c);
} while (c.moveToNext());
}
db.close();
This is the display record function
public void DisplayRecord(Cursor c)
{
Toast.makeText(this,
"id: " + c.getString(0) + "\n" +
"Item: " + c.getString(1) + "\n" +
"Litres: " + c.getString(2),
Toast.LENGTH_SHORT).show();
}
I know i need to change the second function but i dont know how to do that to make it print into a listview
this is the code of getting data from database and insert into Arraylist and insert into arrayAdapter and than display it in listview .
i just done some editing in your existing code.
com.example.rory.dbtest.DBAdapter db = new com.example.rory.dbtest.DBAdapter(this);
db.open();
ArrayList<String> data_list=new ArrayList<String>();
ListView lv=(ListView)findViewById(R.id.listView1);
Cursor c = db.getAllRecords();
if (c.moveToFirst())
{
do {
data_list.add(c.getString(0));
DisplayRecord(c);
} while (c.moveToNext());
}
ArrayAdapter<String> aa=new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, data_list);
lv.setAdapter(aa);
lv - is the object of ListView.
Create a ListView. Then provide cursorAdapter to the ListView as it's adapter to bind the data in the database to the ListView.
There are examples in the samples folder of the SDK you downloaded in the project called ApiDemos.
You need to have, 1) listview, 2) Object class, 3) Custom Adapter
Here I have just tried to implement as per your requirement.
Since I dont have db I did not try to run. The point to is to five you idea.
Because listview is widget that we use more frequently in android. This is the best approach as per my knowledge.
Layouts that required,
activity_list.xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".ListActivity" >
<ListView
android:id="#+id/list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</RelativeLayout>
row_item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp" >
<TextView
android:id="#+id/Item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Item" />
<TextView
android:id="#+id/Litres"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="litres" />
</LinearLayout>
ListActivity.java :
public class ListActivity extends Activity {
ArrayList<RowData> rowDataArrayList = new ArrayList<RowData>();
ListView list;
ListAdapter listAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
list = (ListView) findViewById(R.id.list);
listAdapter = new ListAdapter(ListActivity.this, rowDataArrayList);
list.setAdapter(listAdapter);
getDataFromDB();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.list, menu);
return true;
}
private void getDataFromDB() {
rowDataArrayList.clear();
com.example.rory.dbtest.DBAdapter db = new com.example.rory.dbtest.DBAdapter(
this);
db.open();
Cursor c = db.getAllRecords();
if (c.moveToFirst()) {
do {
/**
* Set your data in class
*/
RowData rowData = new RowData();
rowData.setId(c.getString(0));
rowData.setItem(c.getString(1));
rowData.setLitres(c.getString(2));
rowDataArrayList.add(rowData);
} while (c.moveToNext());
}
db.close();
/**
* To reflect new data set change in listview
*/
listAdapter.notifyDataSetChanged();
}
}
RowData.java : Model[pojo] class to save data and to bind in custom adapter.
public class RowData {
String Id;
String Item;
String Litres;
public String getId() {
return Id;
}
public void setId(String id) {
Id = id;
}
public String getItem() {
return Item;
}
public void setItem(String item) {
Item = item;
}
public String getLitres() {
return Litres;
}
public void setLitres(String litres) {
this.Litres = litres;
}
}
ListAdapter.java : custom adapter to bind in listview
public class ListAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<RowData> rowDataArrayList = new ArrayList<RowData>();
public ListAdapter(Context context, ArrayList<RowData> rowData) {
mContext = context;
rowDataArrayList = rowData;
}
#Override
public int getCount() {
return rowDataArrayList == null ? 0 : rowDataArrayList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
Holder holder = new Holder();
view = View.inflate(mContext, R.layout.row_item, null);
holder.tvtItem = (TextView) view.findViewById(R.id.Item);
holder.tvtLitres = (TextView) view.findViewById(R.id.Litres);
view.setTag(holder);
} else {
view = convertView;
}
Holder holder = (Holder) view.getTag();
holder.tvtItem.setText(rowDataArrayList.get(position).getItem());
holder.tvtLitres.setText(rowDataArrayList.get(position).getLitres());
return view;
}
class Holder {
TextView tvtItem;
TextView tvtLitres;
}
}
public class ListAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<RowData> rowDataArrayList = new ArrayList<RowData>();
public ListAdapter(Context context, ArrayList<RowData> rowData) {
mContext = context;
rowDataArrayList = rowData;
}
#Override
public int getCount() {
return rowDataArrayList == null ? 0 : rowDataArrayList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
if (convertView == null) {
Holder holder = new Holder();
view = View.inflate(mContext, R.layout.row_item, null);
holder.tvtItem = (TextView) view.findViewById(R.id.Item);
holder.tvtLitres = (TextView) view.findViewById(R.id.Litres);
view.setTag(holder);
} else {
view = convertView;
}
Holder holder = (Holder) view.getTag();
holder.tvtItem.setText(rowDataArrayList.get(position).getItem());
holder.tvtLitres.setText(rowDataArrayList.get(position).getLitres());
return view;
}
class Holder {
TextView tvtItem;
TextView tvtLitres;
}
}

Android mapping async downloaded image to listview

I have a ListView that each item in the list contains multiple images.
When I create the list, I want to async download the image so the list can show fast and the images can fill in when they are downloaded.
I have extended the AsyncTask class and implemented a simple download method. However, I am not sure how to update the image back to the correct position in the list view in:
#Override
protected void onPostExecute(Bitmap result) {
// TODO show the downloaded image to the list
super.onPostExecute(result);
}
Here's my class definition:
public class ImageDownloadWorker extends AsyncTask<String, Void, Bitmap>
And my doInBackground method:
#Override
protected Bitmap doInBackground(String... params) {
try {
return downloadBitmap(params[0]);
} catch (ClientProtocolException e) {
return null;
} catch (Exception e) {
return null;
}
}
What is the common pattern we should use to map the downloaded image to the correct ImageView of the correct list item in the list? Thank you!
You need to implement an adapter pattern to populate the listview. In your case, you can create a custom adapter class and extend BaseAdapter and implement all its methods. The pattern goes like this.
MainActivity.java
public class MainActivity extends Activity {
private ListView listView;
private CustomAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listView = findViewById(android.R.id.list);
}
private class ImageDownloader extends AsyncTask<String, Void, Bitmap> {
#Override
protected Bitmap doInBackground(String... strings) {
try {
return downloadBitmap(params[0]);
} catch (ClientProtocolException e) {
return null;
} catch (Exception e) {
return null;
}
}
#Override
protected void onPostExecute(Bitmap bitmap) {
adapter = new CustomAdapter(bitmap);
listView.setAdapter(adapter);
super.onPostExecute(bitmap);
}
}
private class CustomAdapter extends BaseAdapter {
private Bitmap bitmap;
private LayoutInflater inflater = null;
class ViewHolder {
ImageView image;
}
public CustomAdapter(Bitmap bitmap) {
this.bitmap = bitmap;
inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View convertView, ViewGroup parent) {
final ViewHolder holder;
if(convertView == null) {
convertView = inflater.inflate(R.layout.list_item, parent, false);
holder.image = convertView.findViewById(R.id.imageView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.image.setImageBitmap();
return convertView;
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
However, when you are loading many images into the listview, create an ArrayList and send that to the listAdapter
I need to do the same of you in lot of projects and this library is very very helpful and very simple to use:
https://github.com/koush/UrlImageViewHelper

Categories

Resources