Efficently Loading large amount of data in a fragment - java

I am making an application that shows a list of my Custom Model. Take example of Facebook News feed. My custom model contains byte arrays of images. For efficiency I am getting only thumb byte arrays.
Now each listView item contain comments, likes and many other things just like Facebook. I am creating a custom adapter in which i am passing Arraylist of my custom Model and showing in ListView.
Everything is working fine however, i am most concerned about memory issues with android. Since i have thumbs to show and also comments and etc.
My listView is inside a Fragment. How can I show listView items that can contain images, Comments etc, without crashing because of memory or slowing down. Example being Facebook feed page. Or more openly, How can I make something similar to Facebook feed page without getting trouble because of Memory or slowing down issues.
What kind of strategy should I adopt

1 - Universal Image Loader To work with images
2 - Use load more in your listview.
Example:
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(this));
list.setOnScrollListener(new PauseOnScrollListener(imageLoader, false, true) {
#Override
public void onScroll(AbsListView view, int firstItem, int itemsInScreen, int totalItems) {
super.onScroll(view, firstItem, itemsInScreen, totalItems);
int lastItemInScreen = firstItem + itemsInScreen;
if (lastItemInScreen == totalItems) {
//load more items in your listview
}
});

Related

I want to see data in gridview by using sqlite (data) but my app become too slow

I am developing an application. In this I am using the sqlite database.
And I want to show data in gridview and data is above 15k that why my app become very slow.Screen going to black for a second after that data is showing.
When data is below 5k then its working fine but when data is across 10k then app become too slow.
Showing all data but screen blink a second.
GridView is so Old same ListView also old. Use RecyclerView.
What is the problem?
GridView or ListView are hold or load full list of data where as RecyclerView only hold the data that are currently showing in Screen mean Visible screen. [you can hold means processing or somethings similar that].
So what you have to do?
If you want to show data as like Grid you can use GridLayoutManager with RecyclerView
You can use pagination with recyclerView . And good news is google has own Pagination library for android. You can get details here.
Add your http call in background thread and show data in UI thread.
Maybe try to load datas in an AsyncTask in background and then display these datas when there are completely load.
While the datas are loading, your screen show a loading logo or a progress bar, and then, display your datas in your gridview.
Somtehing like this :
new AsyncTask<Void, String, String>(){
#Override
protected void onPreExecute() {
//Display your loader
}
#Override
protected String doInBackground(Void... voids) {
//Load your datas
return null;
}
#Override
protected void onPostExecute(String msg) {
//Close your loader
//Display your datas
}
}.execute(null,null,null);
By this way, the UI Thread won't be blocked and the display still be smooth.

Saving state of UI in Android

I'm making a to-do list app and after user presses the button I create a new GridLayout(and all the data about time and name of the task inside of it) and add it into my RelativeLayout. How do I save those GridLayouts in UI so after the activity is destroyed and launched again those layouts are there.
After pressing the button I trigger the Create Activity method
public void CreateActivity(String name,int hours, int minutes,int i)
{
RelativeLayout.LayoutParams relparams= new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.WRAP_CONTENT);
relparams.addRule(RelativeLayout.BELOW,i);
relparams.setMargins(0,50,0,100);
Glayouts.add(new GridLayout(this));
Glayouts.get(i+1).setBackgroundColor(Color.GRAY);
Glayouts.get(i+1).setMinimumWidth(relative.getWidth());
Glayouts.get(i+1).setId(i+1);
Glayouts.get(i+1).setPadding(10,0,0,0);
GridLayout.LayoutParams namee = new GridLayout.LayoutParams();
namee.columnSpec = GridLayout.spec(0);
namee.rowSpec = GridLayout.spec(0);
namee.setGravity(Gravity.LEFT);
final TextView Actname = new TextView(this);
Actname.setText(name);
GridLayout.LayoutParams checkbox = new GridLayout.LayoutParams();
checkbox.columnSpec = GridLayout.spec(1);
checkbox.rowSpec = GridLayout.spec(0);
checkbox.setGravity(Gravity.RIGHT);
CheckBox check = new CheckBox(this);
// ADDING TO LAYOUT
Glayouts.get(i+1).addView(Actname,namee);
Glayouts.get(i+1).addView(check,checkbox);
relative.addView(Glayouts.get(i+1),relparams);
Theoretically when you extends View, then you can also override onSaveInstanceState and onRestoreInstanceState methods, where you must provide your own SavedState class that typically extends BaseSavedState. You can find info on that here
In your case, your layout is dynamic, therefore this doesn't really work. To tell you the truth, your layout probably shouldn't be constructed this way, you should be rendering the grid using a RecyclerView based on a "model" that describes this layout, render the items of the grid via the RecyclerView.Adapter, and you should persist either the "model", or the data you use to construct this model along with the user-inputted state so that you can re-construct the model that will be rendered via your RecyclerView.
You can read more about RecyclerView here.
You can read more about data persistence here.
You can read about using onSaveInstanceState to save data in Activities/Fragments across config change and process death (but not finishing then restarting the app) here.
You can’t. The best way to save state is to use some persistence mechanism, for example database (I’d recommend Room as it is officially supported by Google).
After clicking a button, you should put all the needed information (name, hours, minutes) in the database and when Activity is created, you can read all persisted data and - basing on it - create all needed layouts again.
Another option is storing data in SharedPreferences - it is much easier to setup, so you can also start with this solution. Please note, I'm suggesting it as a first step in the world of persistency in Android, not as a preferred solution for storing data.

RecyclerView taking too long to populate a large number of Videos from User Storage

So I'm using Glide to load video thumbnails, but it takes a while to load a large number of videos to view, whats the best/fastest way to load a list of videos in users phone with each respective video thumbnail, in Recycler view.
Populating the list
public static ArrayList<String> getAllMedia(Context context) {
HashSet<String> videoItemHashSet = new HashSet<>();
String[] projection = { MediaStore.Video.VideoColumns.DATA ,MediaStore.Video.Media.DISPLAY_NAME};
Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
try {
cursor.moveToFirst();
do{
videoItemHashSet.add((cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))));
}while(cursor.moveToNext());
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
ArrayList<String> downloadedList = new ArrayList<>(videoItemHashSet);
return downloadedList;
}
The Glide Method
public static void displayImageOriginal(Context ctx, ImageView img, String url) {
try {
Glide.with(ctx).load(url)
.transition(DrawableTransitionOptions.withCrossFade())
.apply(RequestOptions.centerCropTransform().skipMemoryCache(false).diskCacheStrategy(DiskCacheStrategy.ALL))
.into(img);
} catch (Exception e) {
}
}
Here's the adapter view Binder
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final YVideos obj = items.get(position);
if (holder instanceof OriginalViewHolder) {
OriginalViewHolder view = (OriginalViewHolder) holder;
view.video_title.setText(obj.title);
view.duration_size.setText(obj.getDurSize());
Tools.displayImageOriginal(ctx, view.video_thumbnail, obj.name);
} else {
SectionViewHolder view = (SectionViewHolder) holder;
view.title_section.setText(obj.title);
}
}
This all looks like standard RecyclerView usage, so provided your adapter is assigned to the RecyclerView in isolation, i.e. without definining any properties that limit performance, such as setItemViewCacheSize(), setMaxRecycledViews() and the likes, your issue is unlikely to be a client-side one.
Are you relying on Glide to generate the thumbnails for you, at runtime? If so, you'll be really putting the library through its paces with a lot of processing, since it has to work through the original quality, original resolution video on the fly. Would it not be possible to generate the thumbnails beforehand? These will load much faster and unburden your app from a lot of computation. If the thumbnails are going to stay the same forever, then why not compute them once and let every user benefit, rather than have every user compute the same result every time you wish to render?
It's likely to me that your issue comes from the fact that you're expecting to fetch the images and render them to the user whilst they're already looking at the content. This means that you load up the screen, and onBindViewHolder() is called, and you make an attempt to fetch the images from a network; but at this stage, the user is already looking at the list and ready to browse. In a way, you're a little too late, and your List will only be as fast as your network connection/image server.
What you can do is prepare the image cache before you ever try to draw the RecyclerView. You know before you reach that screen what range of images you wish to render; it would be possible to load these into Glide and define an appropriate diskStrategy before you're even ready to draw. This way, you can initialize the List of content the moment the user is looking. The predictive image caching strategy wouldn't end here; you know what rows of images you're ready to load next; so you can fetch those in the background too. The drawback with this approach is that it has the potential to waste a lot of bandwidth fetching images your user may never even scroll down to; therefore you may need to experiment with request rate limits.
There are also sneakier ways to go about solving this problem. Even the most well funded, well researched applications depend on simple tricks to work around the bottleneck of network performance... Have you considered using a placeholder animation to keep your app looking active? You'll be surprised how well these work!

RecyclerView doesn't refresh after modifying database's row

I am programming an app for Android. I uploaded it to GitHub: app
I have a ViewPager (MainActivity.java) controlling two Fragments. On the first Fragment (FirstFragment.java) you can add People (People.java) which appears on the RecyclerView (also on FirstFragment.java). When you click one of the list items on the RecyclerView its details (name and id) appear on the second fragment (SecondFragment.java). The SecondFragment.java also contains a button you can delete the selected People with.
To store the People objects I used a List of People and managed it with the methods in PeopleLab.java. The program was working fine: I could add/remove People objects to the list and it appeared on the RecyclerView fine.
After that, I decided to replace the List with a database. It only meant creating the database (the 3 files in database folder) and editing the already existing and two new methods in PeopleLab.java. The other files remained untouched.
The database is working as expected (checked it with sqlite3), I can add/remove People like before and the queries work. My only problem is that the changes don't appear on the RecyclerView. But if I close and reopen the app, the changes appear.
It's like the RecyclerView doesn't care about the database in runtime, only do when the app starts (or closes, not sure).
Do you have any idea what could cause the problem? My only guess is I miss something about how Android apps handle databases.
P.S.: sorry for my English.
You do call notifyDataSetChanged() on the adapter but you don't provide any new data for that adapter.
In your FirstFragment :
private void updateUI() {
PeopleLab peopleLab = PeopleLab.get(getActivity());
List<People> peoples = peopleLab.getPeople();
if(mAdapter == null) {
mAdapter = new PeopleAdapter(peoples);
mRecyclerView.setAdapter(mAdapter);
} else {
// You actually have to change your dataset
mAdapter.changeDataSet(peoples);
}
}
And in your Adapter :
public void changeDataSet(List<People> people) {
this.mPeoples = people;
notifyDataSetChanged();
}
This some brutal way to do it though.
It would be better to notify your adapter on insertion / removal calling notifyItemInserted(int itemPosition) or notifyItemRemoved(int itemPosition). (And refreshing your dataset, by the way)
It will not work automatically.You can either use to notify the adapter the underlying data has been changed so that adapter can fetch and reload the data.It can be done using adapter.notifyDataSetChanged()
Or use can use CursorLoader to achieve the same

Adapter for a custom layout of listview

I am developing an android project in which I have to load from group of String arrays(say title,description,id) to the listview item TextView.
I did something similar with a database using a cursor like this
String[] from = new String[]{"medicine","healthsystem"};
int[] to = new int[] {R.id.textlist1,R.id.textlist2};
// Now creating an array adapter and set it to display using my row
SimpleCursorAdapter notes =new SimpleCursorAdapter(this,R.layout.notes_row, c, from, to);
I listed all the targets in "from" and all the origin in "to".
Now my problem is I don't have a database so cant use a cursor.
I have 3 arrays of strings which i want to load into textviews(title,description,id) of each item
How to do this
Please kindly help me out
thank you :)
If you don't have a cursor, why are you using a SimpleCursorAdapter?
Read this article about creating a SimpleListView using SimpleAdapter for alternate ideas.
There are lots of examples of populating lists from various data sources in the ApiDemos project that comes with the Android SDK - browse through those, and you should find one that fits what you're trying to do.
First of all you need to create a Class that holds that information, something like:
public class StringHolder{
String titte;
String description;
int id;
}
Then you create the layout of your row that says where you want your title, your description and your image.
Then you create an Adapter. The adapter will hold your data and will say for each position in the list what information should be loaded.
At last you need to use your adapter in an activity.
For more information you can see a tutorial here: http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/

Categories

Resources