Perform AsyncTask before displaying the Fragment - java

I am implementing a DrawerLayout and one of the items
or the menu of the drawer displays a gridview with images which is also a fragment.
The problem is by the time I click on the item, there is this delay or lag before the grid
of images will be showed.
Been searching for this, and I'd like to have an AsyncTask to make sure that the GridView fragment
should be completely loaded before displaying which I need to have a ProgressDialog to prevent the lag
effect or to cover up the view. How do I check if the fragment is ready to be displayed? How do
I handle the AsyncTask? Thanks in advance.
ImageGridActivity fragment = new ImageGridActivity();
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.fragment_planet_replace, fragment);
Bundle args = new Bundle();
args.putStringArray(Extra.IMAGES, Constants.IMAGES);
fragment.setArguments(args);
ft.addToBackStack(null);
ft.commit();
EDIT:
I am using an `ImageAdapter` to populate the images to the listview.
`listView.setAdapter(new ImageAdapter());`
I am using Universal-Image-Loader to handle the downloading of images and displaying it.
imageLoader.displayImage

You could launch a new AsyncTask that downloads the images in its doInBackground method (which runs on a background thread) and dismisses the ProgressDialog in its onPostExecute method (which runs on the UI thread).
For example, in your Activity:
final Dialog progressDialog = ProgressDialog.show(this, title, message);
//Should use DialogFragment to wrap the ProgressDialog
new AsyncTask<String, Void, List<byte[]>>(){
#Override
protected List<byte[]> doInBackground(String... urls) {
List<byte[]> imageList = new ArrayList<byte[]>();
HttpURLConnection conn = null;
byte[] buffer = new byte[BUFF_SIZE];
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(BUFF_SIZE);
//Add try - catch - finally block
for(String targetUrl : urls){
conn = (HttpURLConnection)new URL(targetUrl).openConnection();
InputStream iStream = new BufferedInputStream(conn.getInputStream());
int len = 0;
//Alternatively could use Apache Commons IO
while ((len = iStream.read(buffer)) >= 0) {
byteBuffer.write(buffer, 0, len);
}
imageList.add(byteBuffer.toByteArray());
byteBuffer.reset();
}
return imageList;
}
#Override
protected void onPostExecute(List<byte[]> result) {
progressDialog.dismiss();
listView.setAdapter(new ImageAdapter(result)); //Example
super.onPostExecute(result);
}
}.execute(imageUrl1, imageUrl2, imageUrl3);

Related

Fragment in activity startup taking more time than expected

I am a beginner-intermediate android developer. I started working with fragments in my this app. The structure of the app is:
Main activity where some important links are embedded with buttons
On clicking button from main activity, some DB tasks completed (with Room Library so all tasks are using AsyncTask) and new activity opens with link in intent extra
On getting the link, the new activity-2 adds a fragment (in itself) and also performs some DB tasks in background and then opens the link in webview of fragment.
The problem is, from 1-2 it is taking merely 0.1-0.15 seconds while on starting the task 3, it is taking 0.3-0.45 seconds so on clicking from main activity, user is getting the link opened in fragment (which has webview) in about 0.6 seconds which is making feel like app is freezing.
Here are some codes:
Activity-2:
#Override
protected void onCreate(Bundle savedInstanceState) {
prefSingleton = PrefSingleton.getInstance();
if (prefSingleton.getStorage().getBoolean(Constants.STORAGE_ENABLE_NIGHTMODE,false)){
setTheme(R.style.DarkTheme);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_website_view);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
closeWebview = toolbar.findViewById(R.id.closeWebview);
downArrow = toolbar.findViewById(R.id.downArrow);
allTabs = toolbar.findViewById(R.id.allTabs);
searchIcon = toolbar.findViewById(R.id.search);
clearEditText = toolbar.findViewById(R.id.clearEditText);
selectedSEImage = toolbar.findViewById(R.id.selectedSEImage);
searchEditText = toolbar.findViewById(R.id.searchEditText);
searchEngineFrame = toolbar.findViewById(R.id.searchEngine);
searchBarLayout = toolbar.findViewById(R.id.searchBarLayout);
toolbarTitle = toolbar.findViewById(R.id.toolBarTitle);
navFrame = findViewById(R.id.navFrame);
navRecView = findViewById(R.id.navRecView);
if (prefSingleton.getStorage().getBoolean(Constants.STORAGE_ENABLE_NIGHTMODE,false)){
navFrame.setBackgroundColor(getResources().getColor(R.color.night_mode_toolbar));
}
//Activity toolbar views
closeWebview.setOnClickListener(this);
closeWebview.setOnLongClickListener(this);
downArrow.setOnClickListener(this);
allTabs.setOnClickListener(this);
searchIcon.setOnClickListener(this);
clearEditText.setOnClickListener(this);
searchEngineFrame.setOnClickListener(this);
searchEditText.setOnClickListener(this);
searchEditText.setOnKeyListener(this);
//Intent from main activity
Intent i = getIntent();
String urlType = i.getStringExtra(String.valueOf(EnumVal.SiteInfoToSend.TYPE));
final String url = i.getStringExtra(String.valueOf(EnumVal.SiteInfoToSend.URL));
String title = i.getStringExtra(String.valueOf(EnumVal.SiteInfoToSend.TITLE));
String searchedText = i.getStringExtra(String.valueOf(EnumVal.SiteInfoToSend.SEARCHED_TEXT));
fragCounter = 0;
fragTags = new ArrayList<>();
//Fragment opening
if (savedInstanceState == null){
openFragment(url, EnumVal.FragStatus.NEW, null);
}
//AdMob Ads
if (!BuildConfig.PAID_VERSION){
mInterstitialAd = new InterstitialAd(this);
mInterstitialAd.setAdUnitId(getResources().getString(R.string.interstitial_webview));
mInterstitialAd.setAdListener(new AdListener() {
#Override
public void onAdFailedToLoad(int errorCode) {
if(ConsentInformation.getInstance(WebsiteView.this).getConsentStatus() ==
ConsentStatus.NON_PERSONALIZED){
Bundle extras = new Bundle();
extras.putString("npa", "1");
mInterstitialAd.loadAd(new AdRequest.Builder()
.addNetworkExtrasBundle(AdMobAdapter.class,extras).build());
} else {
mInterstitialAd.loadAd(new AdRequest.Builder().build());
}
}
});
if(ConsentInformation.getInstance(WebsiteView.this).getConsentStatus() == ConsentStatus.NON_PERSONALIZED){
Bundle extras = new Bundle();
extras.putString("npa", "1");
mInterstitialAd.loadAd(new AdRequest.Builder()
.addNetworkExtrasBundle(AdMobAdapter.class,extras).build());
} else {
mInterstitialAd.loadAd(new AdRequest.Builder().build());
}
}
//Toolbar search edit text will be enabled in below case
if (urlType.equals(EnumVal.Type.SEARCHED_TEXT.toString())){
searchBarLayout.setVisibility(View.VISIBLE);
searchIcon.setImageResource(R.drawable.close_icon);
searchEditText.setText(searchedText);
searchEditText.clearFocus();
searchEditText.setCursorVisible(false);
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
if (searchEditText.hasFocus())
searchEditText.setCursorVisible(true);
}
searchEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
clearEditText.setVisibility(View.VISIBLE);
}
});
//Navigation view in toolbar
navRecView.setLayoutManager(new LinearLayoutManager(this));
mViewModel = ViewModelProviders.of(this).get(DbViewModel.class);
mViewModel.getSitesWithClicksByIsShown().observe(this, new Observer<List<SitesWithClicks>>() {
#Override
public void onChanged(#Nullable List<SitesWithClicks> sitesWithClicks) {
if (sitesWithClicks!= null && sitesWithClicks.size()>0){
int reArrSite = prefSingleton.getStorage().getInt(Constants.STORAGE_REARRANGESITE_NAV,
Constants.SORTING_PRIORITY);
sitesWithClicks = Utility.sortSitesData(reArrSite, sitesWithClicks);
navAdapter = new ListRecViewAdapter(EnumVal.DialogType.NAVBAR_ITEMS,
sitesWithClicks, WebsiteView.this);
navRecView.setAdapter(navAdapter);
}
}
});
}
Open-fragment method:
public void openFragment(String url, EnumVal.FragStatus fragStatus, String toOpenTag){
if(navFrame.getVisibility() == View.VISIBLE)
downArrow.performClick();
if(fragStatus == EnumVal.FragStatus.NEW){
String fragTag = getNextFragTag();
WebsiteViewFragment fragment = WebsiteViewFragment.newInstance(url, fragTag);
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if(fragCounter == 1){
fragmentTransaction.replace(R.id.fragment, fragment, fragTag);
currentFrag = fragTag;
} else {
if(getSupportFragmentManager().findFragmentByTag(currentFrag) != null){
fragmentTransaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
fragmentTransaction.hide(getSupportFragmentManager().findFragmentByTag(currentFrag));
}
fragmentTransaction.add(R.id.fragment, fragment, fragTag);
currentFrag = fragTag;
}
fragmentTransaction.commit();
fragTags.add(new TabDetail(fragTag,"Tab - 1",null));
} else if (fragStatus == EnumVal.FragStatus.OLD){
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if(getSupportFragmentManager().findFragmentByTag(currentFrag) != null){
fragmentTransaction.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
fragmentTransaction.hide(getSupportFragmentManager().findFragmentByTag(currentFrag));
}
fragmentTransaction.show(getSupportFragmentManager().findFragmentByTag(toOpenTag));
fragmentTransaction.commit();
currentFrag = toOpenTag;
}
}
And Fragment has just Webview in it where webview is loading lot of websettings. But thing is reaching till fragment is taking time ,like user clicks from main activity and after about 0.6 seconds, fragment is opening while activity which has fragment is taking just 0.1 second to open so this time is (maybe) related to attaching fragment or something?
Can anyone please explain me, where am I making mistake?
I had some doubt regarding this:
Is the problem webview (in fragment), which has a bunch of websettings ?
Is attaching fragment to activity-2 taking more time?
Is UI part of activity-2 taking time (like toolbar setup which has 4 buttons) and after that fragment is attaching to it, which is resulting in more time consumption ?
Or it is a normal situation ?
Can someone, please, explain me the way to make it to <0.2 seconds for whole tasks? Thanks in advance.

how to receive data from service when fragment is resumed?

I have a side menu drawer in my activity that has 2 options ("My files" and "Sync"), each of which is a fragment. When I am in "Sync" fragment, there is a button to start downloading files from the server. This is done through an intent service which is running in the background. I use a result receiver in my fragment which keeps getting the download progress (%) from the service and displays it in the fragment.
The problem is that if I switch to the "My Files" fragment while the download is going on and come back to the "Sync" fragment, the view is reset and the progress is lost. The service keeps running in the background but the fragment does not show the progress.
My question is that when I switch the fragment, does the "Sync" fragment still receive the progress from the service that keeps running in the background. How do I start receiving the progress updates from the service when I go back to the "Sync" fragment.
Below is the code in the fragment that starts the service.
intent.putExtra("link", downloadLink);
syncReceiver = new SyncReceiver(new Handler());
intent.putExtra("result_receiver", syncReceiver);
getContext().startService(intent);
Code in the service that sends the download progress to the fragment.
resultReceiver = intent.getParcelableExtra("result_receiver");
link = intent.getStringExtra("link");
while ((bytesRead = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, bytesRead);
byteCount += bytesRead;
String kbs = String.valueOf(byteCount / 1024);
bundle = new Bundle();
bundle.putString("response", kbs);
bundle.putString("total_data", total_file_size);
resultReceiver.send(CONTENT_PROGRESS, bundle);
}
The progress receiving code in the fragment.
public class SyncReceiver extends ResultReceiver {
private static final int CONTENT_PROGRESS = 2;
public SyncReceiver(Handler handler) {
super(handler);
}
public void onReceiveResult(int resultCode, Bundle data) {
super.onReceiveResult(resultCode, data);
String response = data.getString("response");
if (resultCode == CONTENT_PROGRESS) {
updateContentProgress(response, data.getString("total_file_size");
}
}
}
private void updateContentProgress(String progress, String total_file_size) {
double current = Double.parseDouble(progress);
double totalData = 0;
totalData = Double.parseDouble(total_file_size);
String percent = String.valueOf((current / totalData) * 100);
status.setText(R.string.download_progress);
status.append(" " + percent + "%");
}
First move your classes that do the downloading into you Activity. Then from You fragment call into the Classes to to check on status of Your Download with Snippet below...Since activity will still hold reference to your Initial Download you will be able to Track progress. When you switch fragments your activity automatically kills reference to download thread since fragment is removed. Keeping reference in activity allows you to track across multiple fragments.Make sure you classes are public.
((YourBaseActivityWithProperClasses) getActivity()).trackDownloadProgress();
The Fragment won't get updates since it might get destroyed and recreated.
I had a similar problem and my solution was to have an extra background-Fragment to keep the ResultReceiver, that doesn't get destroyed by setting setRetainInstance(true).
An explanation and a possible solution can be found here: https://stanmots.blogspot.com/2016/10/androids-bad-company-intentservice.html
Another good read concerning this problem:
https://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
So my solution was to hold the ResultReceiver inside an extra Fragment having setRetainInstance(true).
To get the right state when (re-)creating the View, I do the following in my onCreate():
final FragmentManager manager = ((Activity) getContext()).getFragmentManager();
// Try to find the Fragment by tag
final IntentObserverFragment intentObserverFragment =
(IntentObserverFragment) manager.findFragmentByTag(IntentObserverFragment.TAG);
if (intentObserverFragment == null) {
// Service is not active
this.progressBar.setVisibility(View.GONE);
} else {
// Service is working - show ProgressBar or else
this.progressBar.setVisibility(View.VISIBLE);
// Stay informed and get the result when it's available
intentObserverFragment.setCallbackClass( this );
}
In my IntentObserverFragment I start the work at onAttach() - not at onCreate(), because the needed Context isn't available yet, which would result in a NPE using e.g. getActivity()!
#Override
public void onAttach(Context context) {
super.onAttach(context);
final MyResultReceiver myResultReceiver = new MyResultReceiver();
final Intent intent = new Intent( context, MyIntentService.class );
intent.putExtra(MyIntentService.BUNDLE_KEY_RECEIVER, myResultReceiver);
context.startService(intent);
}

How to fill ListView with Adapters

I'm aware that this is very simple question but I'm a newbie in Android development so please go easy on me.
Problem that I have is in one of the fragments (AsyncTask specifically) that lays in my main activity.
AsyncTask sends out data to php script which then returns according data in json format. This is then processed and saved to jsonlist array. Up until post execute everything works fine data is downloaded, processed etc. However when program reaches post execute problems start to pop out. And basically i'm unable to list out all the data from jsonlist to listview
//setting up an array
ArrayList<HashMap<String, String>> jsonlist = new ArrayList<HashMap<String, String>>();
//creating list view variable
ListView listview;
//Define work in progress dialog
private ProgressDialog mProgressDialog;
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
mProgressDialog = new ProgressDialog(getActivity());
// Set progressdialog title
mProgressDialog.setTitle("Please wait");
// Set progressdialog message
mProgressDialog.setMessage("Fetching data...");
mProgressDialog.setIndeterminate(false);
}
#Override
protected Boolean doInBackground(String... params) {
//To do in the background
//Define variable of JSON parser type
JSONParser jParser = new JSONParser();
//Pass url to json parser class to fetch and save it into array variable
JSONArray json = jParser.getJSONFromUrl(url);
//loop from 0 to length of an array by increasing by 1
for (int i = 0; i < json.length(); i++) {
//Try and catch routine to prevent any crashes
try {
//Get an object defined in { ... } in original json file
JSONObject c = json.getJSONObject(i);
//Separate object by obtaining values for each of the sections
String vtitle = c.getString(title);
String vcontent = c.getString(content);
String vuser = c.getString(user);
HashMap<String, String> map = new HashMap<String, String>();
//Fill up an array with data extracted
map.put(title, vtitle);
map.put(content, vcontent);
map.put(user, vuser);
//Add values into jsonlist
jsonlist.add(map);
} catch (JSONException e)
{
//In case of any error Stack trace will be returned
e.printStackTrace();
}
}
//Once everything has been done return null value
return null;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
//Insert all data downloaded through list adapter
ListAdapter adapter = new SimpleAdapter(getActivity(), jsonlist, R.layout.list_activity, new String[] { title, content, user }, new int[] { R.id.title, R.id.content, R.id.user });
// Locate the listview
//listview = (ListView) findViewById(R.id.list);
// Set the adapter to the ListView
//listview.setAdapter(adapter);
//Get rid off dialog when operation of fetching data has been done
if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
}
}
As you can see i have tried the commented code but listview = (ListView) findViewById(R.id.list); returns following error:
Cannot resolve method findViewById(int)
which prevents me from executing program. This is very upsetting because I literally have all the data i need in an array but only one line of code stops me from displaying it.
I have also tried:
ListAdapter adapter = new SimpleAdapter(context, jsonlist, R.layout.list_activity, new String[] { title, content, user }, new int[] { R.id.title, R.id.content, R.id.user });
setListAdapter(adapter);
lv = getListView();
But as in previous case error of unresolved method is returned. Which is due to the fact that fragment is extended by fragment and adding anything to it crashes it
public class Fragment2 extends Fragment, ListActivity {...}
Add this to your code in Fragment2 class.
private ListView listview;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.YOUR_FRAGMENT_LAYOUT, container, false);
listview = (ListView) v.findViewById(R.id.R.id.list);
return v;
}
Since you are in a Fragment you have to call getView() before findViewById, like this
//Insert all data downloaded through list adapter
ListAdapter adapter = new SimpleAdapter(getActivity(), jsonlist, R.layout.list_activity, new String[] { title, content, user }, new int[] { R.id.title, R.id.content, R.id.user });
// Locate the listview
listview = (ListView) getView().findViewById(R.id.list);

MainActivity.this is not an enclosing class AsyncTask

I'm trying to create an AsyncTask for the 1st time, but I don't have much luck.
My AsyncTask needs to get some information from a server and then add new layouts to the main layout to display this information.
Everything seems to be more or less clear but, the error message "MainActivity is not an enclosing class" is bothering me.
Nobody else seems to have this problem, so I think I miss something very obvious, I just don't know what it is.
Also, I'm not sure if I used the right way to get the context, and because my application doesn't compile so I can't test it.
Your help is much appreciated.
Here is my code:
public class BackgroundWorker extends AsyncTask<Context, String, ArrayList<Card>> {
Context ApplicationContext;
#Override
protected ArrayList<Card> doInBackground(Context... contexts) {
this.ApplicationContext = contexts[0];//Is it this right way to get the context?
SomeClass someClass = new SomeClass();
return someClass.getCards();
}
/**
* Updates the GUI before the operation started
*/
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
/**
* Updates the GUI after operation has been completed
*/
protected void onPostExecute(ArrayList<Card> cards) {
super.onPostExecute(cards);
int counter = 0;
// Amount of "cards" can be different each time
for (Card card : cards) {
//Create new view
LayoutInflater inflater = (LayoutInflater) ApplicationContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewSwitcher view = (ViewSwitcher)inflater.inflate(R.layout.card_layout, null);
ImageButton imageButton = (ImageButton)view.findViewById(R.id.card_button_edit_nickname);
/**
* A lot of irrelevant operations here
*/
// I'm getting the error message below
LinearLayout insertPoint = (LinearLayout)MainActivity.this.findViewById(R.id.main);
insertPoint.addView(view, counter++, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
}
Eclipse is probably right, and you are trying to access a class (MainActivity) that is inside it's own file from another class that is in its own file (BackgroundWorker) . There is no way to do that - how is one class supposed to know about the other's instance magically? What you can do:
Move the AsyncTask so it is an inner class in MainActivity
Pass off your Activity to the AsyncTask (via its constructor) then acess using activityVariable.findViewById(); (I am using mActivity in the example below) Alternatively, your ApplicationContext (use proper naming convention, the A needs to be lowercase) is actually an instance of MainActivity you're good to go, so do ApplicationContext.findViewById();
Using the Constructor example:
public class BackgroundWorker extends AsyncTask<Context, String, ArrayList<Card>>
{
Context ApplicationContext;
Activity mActivity;
public BackgroundWorker (Activity activity)
{
super();
mActivity = activity;
}
//rest of code...
As for
I'm not sure if I used the right way to get the context
It is fine.
Above example is inner class, here is standalone class...
public class DownloadFileFromURL extends AsyncTask<String, String, String> {
ProgressDialog pd;
String pathFolder = "";
String pathFile = "";
Context ApplicationContext;
Activity mActivity;
public DownloadFileFromURL (Activity activity)
{
super();
mActivity = activity;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(mActivity);
pd.setTitle("Processing...");
pd.setMessage("Please wait.");
pd.setMax(100);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setCancelable(true);
pd.show();
}
#Override
protected String doInBackground(String... f_url) {
int count;
try {
pathFolder = Environment.getExternalStorageDirectory() + "/YourAppDataFolder";
pathFile = pathFolder + "/yourappname.apk";
File futureStudioIconFile = new File(pathFolder);
if(!futureStudioIconFile.exists()){
futureStudioIconFile.mkdirs();
}
URL url = new URL(f_url[0]);
URLConnection connection = url.openConnection();
connection.connect();
// this will be useful so that you can show a tipical 0-100%
// progress bar
int lengthOfFile = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(url.openStream());
FileOutputStream output = new FileOutputStream(pathFile);
byte data[] = new byte[1024]; //anybody know what 1024 means ?
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
// After this onProgressUpdate will be called
publishProgress("" + (int) ((total * 100) / lengthOfFile));
// writing data to file
output.write(data, 0, count);
}
// flushing output
output.flush();
// closing streams
output.close();
input.close();
} catch (Exception e) {
Log.e("Error: ", e.getMessage());
}
return pathFile;
}
protected void onProgressUpdate(String... progress) {
// setting progress percentage
pd.setProgress(Integer.parseInt(progress[0]));
}
#Override
protected void onPostExecute(String file_url) {
if (pd!=null) {
pd.dismiss();
}
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(new File(file_url)), "application/vnd.android.package-archive" );
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(i);
}
}

How to display images on ImageView from json data in android

I am getting json data. In that json I have a url for an image. Now I want to display that Image in ImageView. How can I do acheive this? Here is my code
class LoadInbox extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(Home.this);
pDialog.setMessage("Loading Inbox ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting Inbox JSON
* */
protected String doInBackground(String... arg0) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
JSONObject json = userFunctions.homeData();
Log.e("Data", json.toString());
// Check your log cat for JSON reponse
Log.d("Inbox JSON: ", json.toString());
try {
data = json.getJSONArray(TAG_DATA);
Log.d("inbox array: ", data.toString());
// looping through All messages
for (int i = 0; i < data.length(); i++) {
JSONObject c = data.getJSONObject(i);
// Storing each json item in variable
String profile_img = c.getString(TAG_PROFILE_IMG);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_PROFILE_IMG, profile_img);
// adding HashList to ArrayList
inboxList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all products
pDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
Home.this, inboxList,
R.layout.home_list_item, new String[] { TAG_PROFILE_IMG },
new int[] { R.id.profile_img2 });
// updating listview
setListAdapter(adapter);
}
});
}
here is my layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/profile_img2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="8dip"
android:paddingLeft="8dip"
android:paddingBottom="4dip" />
</RelativeLayout>
So you'll want to create another AsyncTask that given a URL will load the image, and populate some control. I typically do something like this:
ImageView imageView = (ImageView)findById(R.id.blah);
new ImageLoader( person.getImageUri(), imageView, 128, 128 ).execute();
The ImageLoader would be another AsyncTask like this:
public class ImageLoader extends AsyncTask<URI,Integer,BitmapDrawable> {
private Uri imageUri;
private ImageView imageView;
private int preferredWidth = 80;
private int preferredHeight = 80;
public ImageLoader( URI uri, ImageView imageView, int scaleWidth, int scaleHeight ) {
this.imageUri = uri;
this.imageView = imageView;
this.preferredWidth = scaleWidth;
this.preferredHeight = scaleHeight;
}
public BitmapDrawable doInBackground(URI... params) {
if( imageUri == null ) return null;
String url = imageUri.toString();
if( url.length() == 0 ) return null;
HttpGet httpGet = new HttpGet(url);
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute( httpGet );
InputStream is = new BufferedInputStream( response.getEntity().getContent() );
try {
Bitmap bitmap = BitmapFactory.decodeStream(is);
if( preferredWidth > 0 && preferredHeight > 0 && bitmap.getWidth() > preferredWidth && bitmap.getHeight() > preferredHeight ) {
return Bitmap.createScaledBitmap(bitmap, preferredWidth, preferredHeight, false);
} else {
return bitmap;
}
} finally {
is.close();
}
}
}
public void onPostExecute( BitmapDrawable drawable ) {
imageView.setImageBitmap( drawable );
}
}
Then you can kick this AsyncTask off when the image is being bound in your ListView by creating your own subclass ListAdapter. So you'll have to ditch using SimpleAdapter because things aren't simple anymore. This has a lot of advantages so you only load the images being displayed. That means a very small number is loaded out of the total. Also your user can see the data before the image loads so quicker access to the data. If you did this in your existing AsyncTask you'd load every image, and the user would have to wait for every single one to finish before the data is shown to the user. There are somethings that can be improved by this. One AsyncTask uses its own thread so you'll be running a lot of threads potentially (10 or more) all at once. That can kill your server with lots of clients. You can centralize these using an ExecutorService (ie thread pool) but you'll have to ditch using AsyncTask and implement your own facility to run the job off the UI thread and post the results back on the UI thread. Second, your images will load every time the user scrolls. For this I implemented my own caching scheme based on the URI of the image so I only load the image once and return it from the cache. It's a little too much code to post here, but these are exercises for the reader.
Also notice I'm not posting back to the UI thread in onPostExecute(). That's because AsyncTask does that for me I don't have to do it again as your code above shows. You should just remove that extra runnable and inline the code in onPostExecute().
you can try picasso is really easy to use and works really well.
Picasso.with(this.getActivity()).load(person.getImageUri()).into(imageView); // if person.getImageUri() has the url image loaded from json
And that's it.
As it looks you are getting the more than one url (as in array)
1- Keep all the url in an hastable with key as url and value as image View.
2- Show your UI and with loading image.
3- create the other task download image one by one and update in the image view.
as example lazy imageloader......
http://iamvijayakumar.blogspot.in/2011/06/android-lazy-image-loader-example.html
http://codehenge.net/blog/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/
Android Out of Memory error with Lazy Load images
Android lazy loading images class eats up all my memory
Lazy Load images on Listview in android(Beginner Level)?
Lazy load of images in ListView

Categories

Resources