I have implemented GridView in Android.
The first fragment use AsyncTask to load the file and show on the GridView. When the getView has been call. It will call ExtractThumbnail to read the thumbnail. It works fine.
And it can turn to second fragment via a button.
I click the button and turn to second fragment , when the ExtractThumbnail is reading the thumbnail of video and photo.
It crashes due to java.lang.NullPointerException.
The code of first fragment is like the following:(I have omitted some code that are not important)
public class LocalFileBrowserFragment extends Fragment implements MultiChoiceModeListener{
public static Executor threadpoolexecutor;
public static Activity activity;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mFileListAdapter = new LocalFileListAdapter(inflater, mFileList) ;
mFileListAdapter.GridAdapter(getActivity());
activity = getActivity();
loadfilelistTask = new LoadFileListTask();
new LoadFileListTask().executeOnExecutor(threadpoolexecutor) ;
BackButton = (ImageButton) view.findViewById(R.id.BackButton);
BackButton.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v) {
loadfilelistTask.cancel(true);
Checkurl task = new Checkurl(activity, LocalFileBrowserFragment.this);
task.execute();
}
});
}
public class LocalFileListAdapter extends BaseAdapter {
private LayoutInflater mInflater ;
private ArrayList<FileNode> mFileList ;
private static final String TAG = "LocalFileBrowserFragment" ;
private Context mContext;
public LocalFileListAdapter(LayoutInflater inflater, ArrayList<FileNode> fileList) {
mInflater = inflater ;
mFileList = fileList ;
}
public void GridAdapter(Context ctx) {
// TODO Auto-generated method stub
mContext = ctx;
}
private List<ExtractThumbnail> thumbnailTaskList = new LinkedList<ExtractThumbnail>();
private class ExtractThumbnail extends AsyncTask<ViewTag, Integer, Bitmap> {
//Read the Thumbnail.
ViewTag mViewTag;
#Override
protected void onPreExecute() {
thumbnailTaskList.add(this);
super.onPreExecute();
}
#Override
protected Bitmap doInBackground(ViewTag... params) {
mViewTag = params[0];
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inDither = false;
options.inScaled = false;
BitmapFactory.decodeFile(mViewTag.mFileNode.mName, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
int requestedHeight = 64;
int requestedWidth = 64;
int scaleDownFactor = 0;
options.inJustDecodeBounds = false;
while (true) {
scaleDownFactor++;
if (imageHeight / scaleDownFactor <= requestedHeight
|| imageWidth / scaleDownFactor <= requestedWidth) {
scaleDownFactor--;
break;
}
}
options.inSampleSize = scaleDownFactor;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
float scaleFactor = (float) requestedHeight / imageHeight;
scaleFactor = Math.max(scaleFactor, (float) requestedWidth
/ imageWidth);
Bitmap originalBitmap = BitmapFactory.decodeFile(
mViewTag.mFileNode.mName, options);
if (originalBitmap == null) {
try {
byte[] data = Util.getLibVlcInstance().getThumbnail(
"file://" + mViewTag.mFileNode.mName,
requestedWidth, requestedHeight);
if (data != null) {
Bitmap thumbnail = Bitmap.createBitmap(requestedWidth,
requestedHeight, Bitmap.Config.ARGB_8888);
thumbnail.copyPixelsFromBuffer(ByteBuffer.wrap(data));
thumbnail = Util.cropBorders(thumbnail, requestedWidth,
requestedHeight);
return thumbnail;
}
} catch (LibVlcException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(originalBitmap,
requestedWidth, requestedHeight);
originalBitmap.recycle();
return thumbnail;
}
#Override
protected void onPostExecute(Bitmap thumbnail) {
Log.i(TAG, "thumbnail = " + thumbnail);
if (thumbnail != null) {
mViewTag.mThumbnail.setImageBitmap(thumbnail);
}
thumbnailTaskList.remove(this);
mViewTag.mThumbnailTask = null;
super.onPostExecute(thumbnail);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewTag viewTag ;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.filelist_row, null) ;
viewTag = new ViewTag(mContext , (ImageView) convertView.findViewById(R.id.fileListThumbnail);
convertView.setTag(viewTag) ;
}
//Read the Thumbnail.
viewTag.mThumbnailTask = new ExtractThumbnail() ;
viewTag.mThumbnailTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, viewTag) ;
return convertView ;
}
}
And I create a class , When I click the button at first , it call Checkurl task = new Checkurl(activity, LocalFileBrowserFragment.this);.
The code of Checkurl class is like the following(I have omitted some code that are not important):
public class Checkurl extends AsyncTask<URL, Integer, String>{
Context context;
Fragment current_frag;
public Checkurl(Context contextin , Fragment frag)
{
context = contextin;
current_frag = frag;
// The current_frag.getActivity here is not null
}
#Override
protected String doInBackground(URL... params) {
// TODO Auto-generated method stub
URL url = CameraCommand.commandQueryAV1Url() ;
if (url != null) {
return CameraCommand.sendRequest(url) ;
}
return null ;
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
Fragment newFragment = StreamPlayerFragment.newInstance(liveStreamUrl) ;
FragmentManager fragmentManager = current_frag.getActivity().getFragmentManager() ;
// But the current_frag.getActivity here is null. So it crash here.
if (fragmentManager.getBackStackEntryCount() > 0) {
FragmentManager.BackStackEntry backEntry = fragmentManager.getBackStackEntryAt(fragmentManager
.getBackStackEntryCount() - 1) ;
if (backEntry != null && backEntry.getName().equals(newFragment.getClass().getName()))
return ;
}
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction() ;
fragmentTransaction
.setCustomAnimations(R.anim.right_in, R.anim.right_out, R.anim.left_in, R.anim.left_out)
.replace(R.id.mainMainFragmentLayout, newFragment)
.addToBackStack(newFragment.getClass().getName()).commit() ;
fragmentManager.executePendingTransactions() ;
super.onPostExecute(result) ;
}
}
When the ExtractThumbnail AsyncTask is reading Thumbnail and not reading finish.
I click the button turn to second fragment.
It call Checkurl task = new Checkurl(activity, LocalFileBrowserFragment.this);.
But it always crash at FragmentManager fragmentManager = originalFragment.getActivity().getFragmentManager(); in Checkurl class.
I try to print originalFragment.getActivity() in the log. It show originalFragment.getActivity() is null.
Why the originalFragment.getActivity() is null ?
Thanks in advance.
Your AsyncTask should look like this:
Activity context;
public Checkurl(Activity contextin){
context = contextin;
}
protected void onPostExecute(String result) {
//etc
FragmentManager fragmentManager = context.getFragmentManager() ;
}
Your calling originalFragment.getActivity() is null because your fragment is detached from activity (and you switch to new fragment) when you do task in background.
Also, do not depend on current fragment in your AsyncTask because it may be destroyed when you move to new fragment (it may cause NullPointerException)
try to keep activity reference when onAttach is called and use the activity reference wherever needed, for e.g.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = activity;
}
You shouldn't use getActivity to retrieve it. Override void onAttach(Activity activity) in your fragments and save the argument reference to the activity in a member variable.
Related
I am following this tutorial for implementing ViewPager in my project. I have done that using static images successfully. Now I want to change it so that images are retrieved from urls and displayed in ViewPager. Below is my code.
Where should I add the method for downloading images and how to set it
to my ViewPager?
Any help will be greatly appreciated.
MainActivity:
public class MainActivity extends AppCompatActivity {
private ArrayList<Integer> images;
private BitmapFactory.Options options;
private ViewPager viewPager;
private View btnNext, btnPrev;
private FragmentStatePagerAdapter adapter;
private LinearLayout thumbnailsContainer;
private final static int[] resourceIDs = new int[]{R.mipmap.a, R.mipmap.b,
R.mipmap.c, R.mipmap.d, R.mipmap.e, R.mipmap.f, R.mipmap.g};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
images = new ArrayList<>();
//find view by id
viewPager = (ViewPager) findViewById(R.id.view_pager);
thumbnailsContainer = (LinearLayout) findViewById(R.id.container);
btnNext = findViewById(R.id.next);
btnPrev = findViewById(R.id.prev);
btnPrev.setOnClickListener(onClickListener(0));
btnNext.setOnClickListener(onClickListener(1));
setImagesData();
// init viewpager adapter and attach
adapter = new ViewPagerAdapter(getSupportFragmentManager(), images);
viewPager.setAdapter(adapter);
inflateThumbnails();
}
private View.OnClickListener onClickListener(final int i) {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
if (i > 0) {
//next page
if (viewPager.getCurrentItem() < viewPager.getAdapter().getCount() - 1) {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
}
} else {
//previous page
if (viewPager.getCurrentItem() > 0) {
viewPager.setCurrentItem(viewPager.getCurrentItem() - 1);
}
}
}
};
}
private void setImagesData() {
for (int i = 0; i < resourceIDs.length; i++) {
images.add(resourceIDs[i]);
}
}
private void inflateThumbnails() {
for (int i = 0; i < images.size(); i++) {
View imageLayout = getLayoutInflater().inflate(R.layout.item_image, null);
ImageView imageView = (ImageView) imageLayout.findViewById(R.id.img_thumb);
imageView.setOnClickListener(onChagePageClickListener(i));
options = new BitmapFactory.Options();
options.inSampleSize = 3;
options.inDither = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), images.get(i), options );
imageView.setImageBitmap(bitmap);
//set to image view
imageView.setImageBitmap(bitmap);
//add imageview
thumbnailsContainer.addView(imageLayout);
}
}
private View.OnClickListener onChagePageClickListener(final int i) {
return new View.OnClickListener() {
#Override
public void onClick(View v) {
viewPager.setCurrentItem(i);
}
};
}
}
PageFragment class:
public class PageFragment extends Fragment {
private int imageResource;
private Bitmap bitmap;
public static PageFragment getInstance(int resourceID) {
PageFragment f = new PageFragment();
Bundle args = new Bundle();
args.putInt("image_source", resourceID);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
imageResource = getArguments().getInt("image_source");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_page, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 4;
o.inDither = false;
bitmap = BitmapFactory.decodeResource(getResources(), imageResource, o);
imageView.setImageBitmap(bitmap);
}
#Override
public void onDestroy() {
super.onDestroy();
bitmap.recycle();
bitmap = null;
}
}
ViewPager Adapter class:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private List<Integer> images;
public ViewPagerAdapter(FragmentManager fm, List<Integer> imagesList) {
super(fm);
this.images = imagesList;
}
#Override
public Fragment getItem(int position) {
return PageFragment.getInstance(images.get(position));
}
#Override
public int getCount() {
return images.size();
}
}
To use ViewPager for images you have to make a adapter which extends PagerAdapter like as below:
public class ImagePagerAdapter extends PagerAdapter {
Context context;
LayoutInflater layoutInflater;
ArrayList<String> arrayList;
public ImagePagerAdapter(Context context, ArrayList<String> arrayList) {
this.context = context;
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.arrayList = arrayList;
}
#Override
public int getCount() {
if(arrayList != null){
return arrayList.size();
}
return 0;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((LinearLayout) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View itemView = layoutInflater.inflate(R.layout.image_viewpager_layout, container, false);
ImageView imageView = (ImageView) itemView.findViewById(R.id.viewPagerItem_image1);
Picasso.with(context).load(arrayList.get(position))
.placeholder(R.drawable.image_uploading)
.error(R.drawable.image_not_found).into(imageView);
container.addView(itemView);
return itemView;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((LinearLayout) object);
}
}
And xml layout for adapter is:
<?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" >
<ImageView
android:id="#+id/viewPagerItem_image1"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="fitXY"
android:src="#drawable/ic_launcher"/>
</LinearLayout>
For Download Images from URL you have to use AsyncTask.
For that follow below Example of DownloadImageFromAsyncTask.
new LoadImage().execute("http://www.sumtrix.com/images/sumtrix/Android-Wallpaper-HD.jpg");
Set your url to above url.
private class LoadImage extends AsyncTask<String, String, Bitmap> {
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading Image...");
dialog.show();
}
#Override
protected Bitmap doInBackground(String... params) {
try {
bitmap = BitmapFactory.decodeStream((InputStream) new URL(params[0]).getContent());
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
img.setImageBitmap(result);
dialog.dismiss();
} else {
dialog.dismiss();
Toast.makeText(getApplicationContext(), "Image Does Not Exist...",
Toast.LENGTH_LONG).show();
}
}
}
for that you have to add permission in AndroidManifest.xml file
<uses-permission android:name="android.permission.INTERNET" />
IMO you should set your image here, your imageResource is your imgUrl and using a lib such as: UniversalImageLoader, Volley, Picasso... we have many libs to support loading image with url.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 4;
o.inDither = false;
bitmap = BitmapFactory.decodeResource(getResources(), imageResource, o);
imageView.setImageBitmap(bitmap);
}
you should call the picdownloadertask in onViewCreated()
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
new PicDownladerTask().execute(url)
}
class PicDownloaderTask extends AsyncTask {
#Override
protected Bitmap doInBackground(String... strings) {
Bitmap bitmap = getBitmap(strings[0]);
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 4;
o.inDither = false;
bitmap = BitmapFactory.decodeResource(getResources(), imageResource, o);
imageView.setImageBitmap(bitmap);
}
this is the method to get images from url
public static Bitmap getBitmap(String url)
{
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(70000);
conn.setReadTimeout(70000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
// OutputStream os = new FileOutputStream(f);
// Utils.CopyStream(is, os);
// os.close();
bitmap = BitmapFactory.decodeStream(is);
conn.disconnect();
// bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError){}
// memoryCache.clear();
return null;
}
}
I use Picasso library when I need to show image from a URL. It is extremely simple to use.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
Picasso.with(this)
.load(image_url)
.into(imageView);
}
You can see references and download library from this, Picasso
Hope it's helpful.
Use this code to download and show on imageView.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout_here);
new DownloadImageTask((ImageView) findViewById(R.id.imageView1))
.execute("http://java.sogeti.nl/JavaBlog/wp-content/uploads/2009/04/android_icon_256.png");
}
public void onClick(View v) {
startActivity(new Intent(this, IndexActivity.class));
finish();
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
}
add internet permission in AndroidManifest.xml.
<uses-permission android:name="android.permission.INTERNET" />
see this link for more detail
create a async task and download the image in do in background
#Override
protected Bitmap doInBackground(String... url) {
this.url = url[0];
final DefaultHttpClient client = new DefaultHttpClient();
final org.apache.http.client.methods.HttpGet getRequest = new org.apache.http.client.methods.HttpGet(
url[0]);
try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
LoggerUtils.logWarn("ImageDownloader", "Error "
+ statusCode + " while retrieving bitmap from "
+ url[0]);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory
.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
getRequest.abort();
}
I am trying to set a string to a textview but everytime i click the button Quiz the activity is just refreshing instead going to fragment activity.
This summarize the situation.
I have dynamic viewPager inside activity called Quiz_Container
Use only one fragment(Module_Topics_Content_Quiz) in public Fragment getItem(int position) or FragmentStatePagerAdapter.
I want to change text of a textview in the fragment from activity everytime i swipe.
I am passing the string using newInstance with parameter from activity to fragment
The string came from quizQuestion.get(position)
I'm getting the right value with the Log.d but when setting it to textview the activity is just refreshing.
this is my code.
Quiz_Container.java
public class Quiz_Container extends AppCompatActivity implements Module_Topics_Content_Quiz.OnFragmentInteractionListener {
android.support.v7.app.ActionBar actionBar;
ViewPager quizPager;
private int topicID;
private int moduleID;
private int subModuleID;
private ArrayList<Integer> quizID;
private ArrayList<String> quizQuestion;
private ArrayList<String> choiceA;
private ArrayList<String> choiceB;
private ArrayList<String> choiceC;
private ArrayList<String> choiceD;
private ArrayList<String> quizAnswer;
private FragmentManager fragmentManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quiz__container);
actionBar = getSupportActionBar();
actionBar.setTitle("Quiz");
actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#f1ad1e")));
Bundle extras = getIntent().getExtras();
topicID = extras.getInt("topicID");
moduleID = extras.getInt("moduleID");
subModuleID = extras.getInt("subModuleID");
Log.d("quizTopicID", "" + topicID);
Log.d("quizModuleID", "" + moduleID);
Log.d("quizSubModuleID", "" + subModuleID);
new quizTask().execute();
}
#Override
public void onFragmentInteraction(Uri uri) {
}
public boolean isOnline() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
} else {
return false;
}
} // Check Internet Connection
class quizTask extends AsyncTask<String, String, String> {
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(String... params) {
BufferedReader reader = null;
try {
URL quizURL = new URL("http://192.168.1.110/science/index.php/users/get_quiz_items/" + topicID + "/" + moduleID + "/" + subModuleID + "" );
HttpURLConnection con = (HttpURLConnection)quizURL.openConnection();
StringBuilder sb = new StringBuilder();
reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String quizResponse;
while ((quizResponse = reader.readLine()) != null) {
return quizResponse;
}
return sb.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if(reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
}
#Override
protected void onPostExecute(String quizResponses) {
Log.d("quizResponse", "" + quizResponses);
try {
JSONObject quizObject = new JSONObject(quizResponses);
boolean result = quizObject.getBoolean("success");
if (result) {
JSONArray quizArray = quizObject.getJSONArray("data");
quizID = new ArrayList<>();
quizQuestion = new ArrayList<>();
choiceA = new ArrayList<>();
choiceB = new ArrayList<>();
choiceC = new ArrayList<>();
choiceD = new ArrayList<>();
quizAnswer = new ArrayList<>();
for (int i = 0; i < quizArray.length(); i ++) {
JSONObject dataQuiz = quizArray.getJSONObject(i);
quizID.add(dataQuiz.getInt("id"));
quizQuestion.add(dataQuiz.getString("question"));
choiceA.add(dataQuiz.getString("a"));
choiceB.add(dataQuiz.getString("b"));
choiceC.add(dataQuiz.getString("c"));
choiceD.add(dataQuiz.getString("d"));
quizAnswer.add(dataQuiz.getString("answer"));
}
Log.d("quizSize", "" + quizID.size());
quizPager = (ViewPager) findViewById(R.id.quizPager);
fragmentManager = Quiz_Container.this.getSupportFragmentManager();
quizPager.setAdapter(new quizAdapter(getSupportFragmentManager()));
quizPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
else {
Toast.makeText(getApplication(), "no quiz yet", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} // end of quizTask
class quizAdapter extends FragmentStatePagerAdapter {
public quizAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
for (int i = 0; i < quizID.size; i++) {
if (i == position) {
fragment = Module_Topics_Content_Quiz.newInstance(quizQuestion.get(position));
Log.d("testQuestion", "" + quizQuestion.get(position)); // this code is working
}
}
return fragment;
}
#Override
public int getCount() {
return quizID.size();
}
}
}
Module_Topics_Content_Quiz.java
public class Module_Topics_Content_Quiz extends Fragment {
TextView textQuizQuestion;
private String qQuestion;
public Module_Topics_Content_Quiz() {
// Required empty public constructor
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
}
public static Module_Topics_Content_Quiz newInstance(String question) {
Module_Topics_Content_Quiz fragment = new Module_Topics_Content_Quiz();
Bundle args = new Bundle();
args.putString("question", question);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
qQuestion = getArguments().getString("question");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_module__topics__content__quiz, container, false);
textQuizQuestion = (TextView) getActivity().findViewById(R.id.textQuestion);
Log.d("question", "" + qQuestion); // this is working
// textQuizQuestion.setText(qQuestion); // error if enable
return rootView;
}
}
Please help. Thank you.
In your fragment, try inflating the TextView using the View returned rather than using getActivity()
You need to inflate the Fragment's view and call findViewById() on the View it returns.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_module__topics__content__quiz, container, false);
// inflate the View inside Fragment using the View returned
textQuizQuestion = (TextView) rootView.findViewById(R.id.textQuestion);
Log.d("question", "" + qQuestion); // this is working
textQuizQuestion.setText(qQuestion);
return rootView;
}
You can also use getView() from within the Fragment to get the root view.
If you wanna call from the enclosing Activity, use
getFragmentManager().findFragmentById(R.id.your_fragment_id).getView().findViewById(R.id.your_view);
I'm developing android App. My app is showing many of pictures from server by image_url with ImageLoader Library such as Picasso, Glide or AUIL.
There are five fragments in main activity. and each of fragments have many image list view.
My question is that after I click specific image view, new activity is created, and then fragment is created that have many images list view.
I clicked different images, and new activities are created. When this gesture occurred , heap memory is not fetched ...
Among of three libraries, AUIL is the best of them.
I tried recursing method at base adapter and drawable callback to null etc...
But This situation was not solved.
Here is my example Adapter sourse:
public class MagazineRelBrandItemAdapter extends BaseAdapter {
ArrayList<String> receivedList;
ArrayList<View> brandThumList = new ArrayList<>();
PrintLog printLog = new PrintLog(Application.isDEBUG(), "MagazineRelBrandItemAdap ", "created");
Activity mActivity;
public MagazineRelBrandItemAdapter(ArrayList<String> dataList, Activity activity) {
receivedList = dataList;
mActivity = activity;
}
#Override
public int getCount() {
return receivedList.size();
}
#Override
public String getItem(int position) {
return receivedList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MagazineRelBrandView itemView;
if (convertView == null) {
itemView = new MagazineRelBrandView(Application.getContext(),mActivity);
} else {
itemView = (MagazineRelBrandView) convertView;
}
try {
itemView.setContent(receivedList.get(position));
brandThumList.add(itemView);
} catch (OutOfMemoryError e) {
if (mRecycleList.size() <= parent.getChildCount()) {
printLog.cutsomPrintLog(Application.isDEBUG(), "img recycle size comment>>", mRecycleList.size() + "");
throw e;
}
recycleHalf();
System.gc();
return getView(position, itemView, parent);
}
mRecycleList.add(new WeakReference<View>(itemView));
return itemView;
}
private List<WeakReference<View>> mRecycleList = new ArrayList<WeakReference<View>>();
public void recycleHalf() {
int halfSize = mRecycleList.size() / 2;
List<WeakReference<View>> recycleHalfList = mRecycleList.subList(0, halfSize);
RecycleUtils.recursiveRecycle(recycleHalfList);
for (int i = 0; i < halfSize; i++)
mRecycleList.remove(0);
}
public void recycle() {
RecycleUtils.recursiveRecycle(mRecycleList);
}
}
And Here is my widget :
public class MagazineRelBrandView extends LinearLayout {
Activity mActivity;
public MagazineRelBrandView(Context context,Activity activity) {
super(context);
mActivity = activity;
init();
}
CircleImageView brandLogo;
TextView brandName;
ImageView brandBg;
View clickV;
private void init() {
inflate(getContext(), R.layout.magazine_rel_brand_view, this);
brandBg = (ImageView) findViewById(R.id.magazine_rel_brand_bg);
brandName = (TextView) findViewById(R.id.magazine_rel_brand_name);
brandLogo = (CircleImageView) findViewById(R.id.magazine_rel_brand_icon);
clickV = findViewById(R.id.content_click_view);
brandName.setTypeface(Typeface.createFromAsset(getContext().getAssets(), CommonKeys.FuturaFont));
clickV.setOnClickListener(goBrandDetailPageListener);
}
public void setContent(String brandName) {
this.brandName.setText(brandName);
try {
String brandTitleUrl;
brandTitleUrl = URLEncoder.encode(brandName, "UTF-8");
totalThumbUrl = CommonKeys.brandThumbUrl + brandTitleUrl;
totalBackUrl = CommonKeys.brandBackgroundUrl + brandTitleUrl;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
showBG(brandName);
showLogo(brandName);
}
String totalThumbUrl;
String totalBackUrl;
public void showLogo(final String brandName){
Glide.with(mActivity).load(totalThumbUrl).override(DpToPxUtil.dp2px(38),DpToPxUtil.dp2px(38)).into(brandLogo);
}public void showBG(final String brandName){
Glide.with(mActivity).load(totalBackUrl).override(DpToPxUtil.dp2px(120),DpToPxUtil.dp2px(144)).into(brandBg);
}
public String getBrandName() {
return brandName.getText().toString();
}
Handler brandHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
MyToast.show("" + msg.obj);
break;
case 1:
BrandInfoZip brandInfoZip = (BrandInfoZip) ((BrandInfoParentZip) msg.obj).getData();
BrandListZip getBrandZip = new BrandListZip();
getBrandZip.setIs_following(brandInfoZip.is_following());
getBrandZip.setBrand_name(getBrandName());
Intent goBrandPage = new Intent(Application.getContext(), BrandDetailActivity.class);
goBrandPage.putExtra("brandZip", getBrandZip);
goBrandPage.putExtra("title", getBrandName());
goBrandPage.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Application.getContext().startActivity(goBrandPage);
break;
}
}
};
OnClickListener goBrandDetailPageListener = new OnClickListener() {
#Override
public void onClick(View v) {
BrandDescriptionZip brandDescriptionZip = new BrandDescriptionZip();
brandDescriptionZip.setBrand_name(getBrandName());
new GetBrandInfoFromServer(brandHandler).execute(brandDescriptionZip);
}
};
}
And fragment onDestroyView sourse :
#Override
public void onStop() {
super.onStop();
if (upperBgImgV.getDrawable() != null) {
upperBgImgV.getDrawable().setCallback(null);
}
if (writerThumb.getDrawable() != null) {
writerThumb.getDrawable().setCallback(null);
}
if (otherContentV.getDrawable() != null) {
otherContentV.getDrawable().setCallback(null);
}
}
#Override
public void onDestroyView() {
Glide.clear(writerThumb);
magazineRelBrandItemAdapter.recycle();
unbindDrawables(getView());
//unbindDrawables(writerThumb);
//unbindDrawables(otherContentV);
System.gc();
super.onDestroyView();
Log.i(TAG, "onDestroyView-");
}
private void unbindDrawables(View view) {
if (view == null)
return;
if (view instanceof ImageView) {
((ImageView) view).setImageDrawable(null);
}
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
view.setBackgroundResource(0);
view.setBackgroundDrawable(null);
}
}
and Here is activity onDestroy() course :
#Override
protected void onDestroy() {
RecycleUtils.recursiveRecycle(getWindow().getDecorView());
System.gc();
Glide.get(this).clearMemory();
FlurryAgent.onEndSession(Application.getContext());
printLog.cutsomPrintLog(Application.isDEBUG(),"Magazine Detail Activity onDestroy-","onDestroy-");
super.onDestroy();
finish();
}
These course is used to clear memory heap. But Memory leak is continue....
Please help me.
I have a FragmentActivity that has 5 Fragments
On my 2nd fragment is a gridview that displays many images.
That GridFragment is starting an AsyncTask with callback to get the arraylist of images.
It then sets an adapter using the following as arguments (listener, context, arraylist) context is getActivity()
when adapter starts it tries to do LayoutInflater.from(Context);
That is where im getting my null pointer. If the async task is complete it will not crash. but it i rotate while async task is working it crashes.
Is there any way around this?
Fragment
public class IconsFrag extends GridFragmentIcons implements AdapterIcons.AdapterListener {
AsyncTaskIconsAll aTask;
Button button;
final String TAG = "IconsFrag";
private ArrayList<Integer> mThumbs;
private final String KEY_LIST_DATA = "icons_cache";
private final String KEY_LIST_POSITION = "icons_position";
private int mPosition = -1;
private AdapterIcons mAdapter;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
Log.i(TAG, "onActivityCreated");
super.onCreate(savedInstanceState);
if (savedInstanceState == null){
Log.i(TAG, "savedInstanceState null");
aTask = new AsyncTaskIconsAll();
aTask.updateActivity(this, getActivity(), new AsyncTaskIconsAll.Callback() {
#Override
public void onData(ArrayList<Integer> data) {
mThumbs = data;
mAdapter = new AdapterIcons(IconsFrag.this, getActivity(), mThumbs);
getGridView().setNumColumns(getResources().getInteger(R.integer.column_count_icon));
setGridAdapter(mAdapter);
getGridView().setOnItemClickListener(null);
}
});
aTask.execute();
}
AsyncTask
public class AsyncTaskIconsAll extends AsyncTask<Void, Integer, ArrayList<Integer>> {
private Activity mContext;
private Fragment mFragment;
private ArrayList<Integer> mThumbs;
final String TAG = "AsyncTaskIconsAll";
Callback mCallback;
public static interface Callback{
public void onData(ArrayList<Integer> data);
}
public void updateActivity(Fragment f, Activity a, final Callback c) {
Log.i(TAG, "updateActivity");
mContext = a;
mFragment = f;
mCallback = c;
if(mThumbs != null)
Log.i(TAG, "Callback not null");
mCallback.onData(mThumbs);
}
#Override
protected void onPreExecute() {
}
#Override
protected ArrayList<Integer> doInBackground(Void... unused){
Log.i(TAG, "doInBackground");
mThumbs = new ArrayList<Integer>();
final String[] extras = mContext.getResources().getStringArray(R.array.icon_pack);
for (String extra : extras) {
String uri = "drawable/" + extra;
int res = mContext.getResources().getIdentifier(uri, null, mContext.getPackageName());
if (res != 0) {
mThumbs.add(res);
}
}
return mThumbs;
}
protected void onProgressUpdate(Integer... progress) {
}
#Override
protected void onPostExecute(ArrayList<Integer> icons) {
Log.i(TAG, "onPostExecute");
mThumbs = icons;
mCallback.onData(mThumbs);
ProgressBar mProgess = (ProgressBar) mFragment.getView().findViewById(R.id.pending);
mProgess.setVisibility(mFragment.getView().GONE);
}
}
Adapter
public class AdapterIcons extends BaseAdapter implements SpinnerAdapter {
private final String TAG = "AdapterIcons";
private AdapterListener mListener;
private ArrayList<?> mData;
private final LayoutInflater mInflater;
public AdapterIcons(AdapterListener listener, Activity activity) {
this.mData = new ArrayList<Object>();
this.mInflater = LayoutInflater.from(activity);
this.mListener = listener;
}
public AdapterIcons(AdapterListener listener, Context Context, ArrayList<?> data) {
this.mData = (data == null) ? new ArrayList<Object>() : data;
this.mInflater = LayoutInflater.from(Context);
this.mListener = listener;
}
public ArrayList<?> getData () {
return this.mData;
}
public void setData (ArrayList<?> data) {
this.mData = data;
}
public void clearData () {
this.mData.clear();
}
public static abstract interface AdapterListener
{
public abstract View getView(int paramInt, View paramView, ViewGroup paramViewGroup);
}
public Intent.ShortcutIconResource getResource(int position){
Icons icons= new Icons();
ArrayList<Integer> list = (ArrayList<Integer>) mData;
return Intent.ShortcutIconResource.fromContext(icons.getBaseContext(), list.get(position));
}
#Override
public int getCount () {
if (mData == null)
Log.d(TAG, "getCount() Data Set Is Null");
return (mData != null) ? mData.size() : 0;
}
#Override
public Object getItem (int position) {
if (mData == null)
Log.d(TAG, "getItem(int position) Data Set Is Null");
return (mData != null) ? mData.get(position) : null;
}
#Override
public long getItemId (int position) {
if (mData == null)
Log.d(TAG, "getItemId(int position) Data Set Is Null");
return (mData != null) ? position : 0;
}
#Override
public View getView (int position, View convertView, ViewGroup parent) {
return (mListener == null) ? new LinearLayout(mInflater.getContext()) : this.mListener.getView(position, convertView, parent);
}
#Override
public View getDropDownView (int position, View convertView, ViewGroup parent) {
return (mListener == null) ? new LinearLayout(mInflater.getContext()) : this.mListener.getView(position, convertView, parent);
}
}
Take a look on this answer. It's pretty much the same problem. You need to handle orientation changes which changes the activity state in default(if you don't override).
https://stackoverflow.com/a/7618739/1080954
so in your onPostExecute() you try to add items to an activity which is (temporarily) destroyed. Check if your getActivity() == null before doing stuff with the context. Something like:
public void onPostExecute(){
if(getActivity() == null){
// activity is destroyed... skip
return;
}
// proceed like normal
}
This is the best I can do without anymore code. Good luck
Did you notice that you should use brackets {} in here, otherwise mCallback.onData(mThumbs) will always be called:
if(mThumbs != null){
Log.i(TAG, "Callback not null");
mCallback.onData(mThumbs);
}
Also you're passing the fragment and the activity in asyncTask updateActivity() method when you create the asyncTask but they will be null when you rotate your device, the activity is going to be recreated, so when you use them in asyncTask doInBackground() and onPostExecute() you have to check first if they are not null, otherwise you could end up with a NullPointerException.
I have a FragmentActivity with a FragmentMediaOverview containing a list of MediaItemViews (each with a imageview and some text) and a click on one of the items opening a detail-Fragment.
Now when I go back (via back button) and forth (click on listitem) several times from list to detail fragment I eventually run into OOM-Errors. I use SoftReferences for the bitmaps in the listitems as well as in the detail fragment.
According to MAT there is an incresing number of MediaItemViews as well as FragmentMediaOverview instances, but I just cannot figure out why.
I read this Android: AlertDialog causes a memory leak , but couldn't solve it nulling out listeners.
Here is my code:
FragmentMediaOverview.java
(This is not a ListFragment because for a tablet-layout the MediaAdapter needs to connect to a gridview)
public class FragmentMediaOverview extends Fragment {
private static String TAG = FragmentMediaOverview.class.getSimpleName();
private MediaAdapter adapter;
private OnMediaSelectedListener selListener;
private ArrayList<BOObject> mediaItems;
private ViewGroup layoutContainer;
private AdapterView itemContainer; // list or gridview
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
layoutContainer = (ViewGroup) inflater.inflate(R.layout.fragment_media_overview, null);
return layoutContainer;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
selListener = (OnMediaSelectedListener) activity;
}
#Override
public void onDestroy() {
super.onDestroy();
itemContainer.setOnItemClickListener(null);
selListener = null;
adapter = null;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initUi(layoutContainer);
displayMedia();
}
private void initUi(ViewGroup layoutContainer) {
itemContainer = (AdapterView) layoutContainer.findViewById(android.R.id.list);
itemContainer.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
BOMedia mediaItem = ((BOMedia) mediaItems.get(position));
//the FragmentActivity is coordinating the FragmentTransactions
selListener.onMediaSelected(mediaItem);
}
});
}
private void displayMedia() {
Log.d(TAG, "Displaying List");
if (mediaItems == null) {
loadMedia();
return;
}
Log.d(TAG, "List: " + mediaItems.size() + ", adapter: " + itemContainer.getAdapter());
if (adapter == null) {
Log.d(TAG, "Create Adapter with " + mediaItems.size());
adapter = new MediaAdapter(getActivity(), mediaItems);
}
if (itemContainer.getAdapter() == null) {
itemContainer.setAdapter(adapter);
} else {
adapter.setItems(mediaItems);
adapter.notifyDataSetChanged();
}
}
private void loadMedia() {
FragmentHelper.showProgressSpinner(layoutContainer, android.R.id.list);
DbHelper.getInstance().getMedia(mediaType, new DbQueryFinishListener() {
#Override
public void onDbCallFinish(ArrayList<BOObject> objects) {
if (!getActivity().isFinishing()) {
mediaItems = objects;
Collections.sort(mediaItems, new Comparator<BOObject>() {
final Collator c = Collator.getInstance(Locale.GERMAN);
#Override
public int compare(BOObject s1, BOObject s2) {
if (s2 != null && ((BOMedia) s2).getTitle() != null && s1 != null
&& ((BOMedia) s1).getTitle() != null) {
return c.compare(((BOMedia) s1).getTitle(),((BOMedia) s2).getTitle());
} else {
return 0;
}
}
});
displayMedia();
FragmentHelper.hideProgressSpinner(layoutContainer, android.R.id.list);
}
}
#Override
public void onDbCallException(Exception exception) {
if (!getActivity().isFinishing()) {
FragmentHelper.hideProgressSpinner(layoutContainer, android.R.id.list);
}
}
});
}
}
MediaAdapter.java
public class MediaAdapter extends BaseAdapter {
private static final String TAG = MediaAdapter.class.getSimpleName();
private Context context;
private ArrayList<BOObject> mediaItems;
public MediaAdapter(Context c, ArrayList<BOObject> mediaItems) {
super();
context = c;
this.mediaItems = mediaItems;
}
#Override
public int getCount() {
return mediaItems.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) {
if (convertView == null) {
convertView = new MediaItemView(context);
}
((MediaItemView)convertView).initialize((BOMedia) mediaItems.get(position));
return convertView;
}
public void setItems(ArrayList<BOObject> mediaItems) {
this.mediaItems = mediaItems;
}
}
MediaItemView.java
public class MediaItemView extends LinearLayout {
private static final String TAG = MediaItemView.class.getSimpleName();
private BOMedia item;
private SoftReference<Bitmap> bm;
private ImageView iv;
private Context ctx;
public MediaItemView(Context context) {
super(context);
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.view_media_item, this);
this.ctx = context;
}
/** Init the view with a new BOMedia object
* #param mediaItem
*/
public void initialize(BOMedia mediaItem) {
this.item = mediaItem;
initUI();
}
private void initUI() {
TextView title = (TextView) findViewById(R.id.itemText);
iv = (ImageView) findViewById(R.id.itemImage);
title.setText(Html.fromHtml(item.getTitle()));
iv.setImageBitmap(null);
bm = null;
System.gc();
iv.invalidate();
if (item.getFilepathThumb() != null && !item.getFilepathThumb().equals("")) {
ExpansionPackManager.getInstance().getBitmapResource(item.getFilepathThumb(), false,
new BitmapReadListener() {
#Override
public void onFileRead(BitmapResponseMessage message) {
Log.d(TAG, "Bitmap read: " + message.getFilepath());
Bitmap image = message.getBitmap();
if (image != null && message.getFilepath().equals(item.getFilepathThumb())) {
bm = new SoftReference<Bitmap>(image);
iv.setImageBitmap(bm.get());
Log.d(TAG, "image set");
} else {
Log.d(TAG, "image too late: " + image);
}
}
#Override
public void onFileException(Throwable exception) {
Log.d(TAG, "image exception");
}
});
}
}
}
In MediaItemView the size of your bitmap must be too big. If the bitmap is 600x600 and you want to display a image with a size of 50x50 you can use Bitmap.createScaledBitmap. You should also use bitmap cache while loading your bitmap.
This is because the View for rach child in the ListView is recreated as you scroll through. This is very heavy on resources. To avoid this use a holder class in adapters getView() to hold and reuse the views. This is called an Efficient Adapter. For example see Efficient List Adapter in API demos. http://developer.android.com/tools/samples/index.html
You can also use:
android:hardwareAccelerated = true
Beginning in Android 3.0 (API level 11), the Android 2D rendering pipeline is designed to better support hardware acceleration. Hardware acceleration carries out all drawing operations that are performed on a View's canvas using the GPU.
For more info http://developer.android.com/guide/topics/graphics/hardware-accel.html