I am getting this error while calling my player.pause(); method in my application. I am pausing music using ImageButton. I am calling method from song_list class to pause the track. But, following exception occurs:
Attempt to invoke virtual method 'void android.media.MediaPlayer.pause()' on a null object reference
My MainActivity:
public class MusicKom extends AppCompatActivity {
private static String TAG = "PermissionDemo";
public static final int REQUEST_READ_STORAGE = 112;
private ImageButton btplay;
private ImageButton pausemusic;
public void playbutton(int playbuttonid){
btplay=(ImageButton)findViewById(R.id.play);
btplay.setBackgroundResource(playbuttonid);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music_kom);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
// Create an adapter that knows which fragment should be shown on each page
final viewpageadapter adapter = new viewpageadapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
Button bt1 = (Button)findViewById(R.id.song_list);
Button bt2 = (Button)findViewById(R.id.album_list);
Button bt3 = (Button)findViewById(R.id.artist_list);
pausemusic = (ImageButton)findViewById(R.id.play);
bt1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setCurrentItem(0);
}
});
bt2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setCurrentItem(1);
}
});
bt3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setCurrentItem(2);
}
});
pausemusic.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
songs_list sl=new songs_list();
sl.pauseplay();
pausemusic.setBackgroundResource(R.drawable.stop);
}
});
}
}
My song_list Fragment:
public class songs_list extends Fragment {
// Adapter that exposes data from a Cursor to a ListView widget.
private MediaCursorAdapter mediaAdapter = null;
public MediaPlayer player;
private String currentFile="";
private boolean isStarted = true;
private TextView selelctedFile = null;
private View v=null;
private String selectedtitem=null;
private int fileposition;
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
player = new MediaPlayer();
// Use cursor to get data from external resource
final Cursor cursor = getActivity().getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
// check Cursor has data or not
if (null != cursor) {
cursor.moveToFirst();
mediaAdapter = new MediaCursorAdapter(getActivity().getApplicationContext(), R.layout.list_layout, cursor);
v=inflater.inflate(R.layout.fragment_songs_list, container, false);
ListView lv = (ListView)v.findViewById(android.R.id.list);
lv.setAdapter(mediaAdapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedtitem = (String) view.getTag();
startPlay(selectedtitem);
}
});
}
return v;
}
private void startPlay(String file) {
player.stop();
player.reset();
try {
player.setDataSource(file);
player.prepare();
player.start();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
((MusicKom) getActivity()).playbutton(R.drawable.play);
}
public void pauseplay(){
Log.i(TAG, "pauseplay: ");
player.pause();
}
}
How can you call another activity method without actually launching the activity. In your case the another activity is not loaded and hence media player object is not created.
please post the whole code to get more information.
You are using a Fragment as a regular java class. Fragment's onCreateView() is not called when you instantiate Fragment. It is only called when you show a fragment with a valid FragmentTranscation. See Fragment Life cycle.
Comment down if you want the fragment to show up when you have to call pauseplay();, I will add the relevant code.
Otherwise, you should be using a regular java class to create and play/pause a media player from anywhere. Something like:
// package com.example.package_name;
import android.media.MediaPlayer;
public class SoundPlayer {
private MediaPlayer mediaPlayer;
// rawSongId is in form of 'R.id.song_name'
public SoundPlayer(Context context, int rawSongId){
mediaPlayer = MediaPlayer.create(context, rawSongId);
}
public SoundPlayer(Context context, String dataSource){
// handle media player with your data source
}
public void start(){
if(mediaPlayer != null) {
mediaPlayer.start();
}
}
public void pause(){
if(mediaPlayer != null) {
mediaPlayer.pause();
}
}
public void stop(){
if(mediaPlayer != null) {
mediaPlayer.stop(); // reset(); ?
}
}
}
Now, instead of
songs_list sl = new songs_list();
sl.pauseplay();
you can,
String dataSource = ""; // generate your dataSource here
// initialize MediaPlayer with dataSource
SoundPlayer soundPlayer = new SoundPlayer(this, dataSource);
// Use its methods
soundPlayer.start();
soundPlayer.pause();
soundPlayer.stop();
please try to use proper camelCase coding conventions. Your pauseplay() should be pausePlay(); or pauseOrPlay().
Related
I have a main_activity containing two fragments. When a button is clicked on beatTimeFragment, I want beatTimeFragment to determine the msec past 1970 that the button was pressed and pass it to toneTimeFragment by way of the main activity. The toneTimeFragment will then compare the response to a standard beat and give an offSet.
Every example i have seen passes string data rather than long data. In my code, I tried passing String data then converting it to long data. The string data gets transfered (i can was it show string). But the long gives a response of 0 or it kick me out if i do not have the exception.
Is there a way to get the conversion to work or if not, how do i set up for a long data transfer rather than String by removing the
beatTimeDisplay.getText().toString()
at the end of the beatTimeFragment?
main_activity
public class MainActivity extends AppCompatActivity implements
BeatTimeFragment.BeatTimeListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//Get called by BeatTimeFragment when button is pushed
#Override
public void sendBeatData(String beatTime) {
ToneTimeFragment toneFragment = (ToneTimeFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
toneFragment.setBeatLong(beatTime);
}
}
toneTimeFragment
public class ToneTimeFragment extends Fragment {
public void setBeatLong(String beatTime) {
try {
beatTimeL = Long.parseLong(beatTime);
} catch (NumberFormatException e) {
System.out.println("NumberFormatException: " + e.getMessage());
}
// beatTimeL = Long.parseLong(beatTime);
offSet = beatTimeL - toneTime;
offSetView.setText(beatTime + " msec");
beatTimeFragment
public class BeatTimeFragment extends Fragment {
private static Button beatBtn;
private static TextView beatTimeDisplay;
int q = 0;
long beatTime = 0;
//set up sending beatTime
BeatTimeListener activityCommander;
public interface BeatTimeListener{
public void sendBeatData(String beatTime);
}
//setup to send data to top
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
activityCommander = (BeatTimeListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString());
}
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.beat_time_fragment, container, false);
beatTimeDisplay = (TextView) view.findViewById(R.id.beatTimeDisplay);
final Button beatBtn = (Button) view.findViewById(R.id.beatBtn);
beatBtn.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v){
long beatTime= System.currentTimeMillis();
TextView view1 = (TextView) view.findViewById(R.id.beatTimeDisplay);
view1.setText(beatTime + " msec");
readySendBeat(v);
}
}
);
return view;
}
//calls to send data when button clicked
public void readySendBeat(View v) {
activityCommander.sendBeatData(beatTimeDisplay.getText().toString());
}
}
While debugging, i realized that i was not passing my beatTime value into the readySendBeat method in the BeatTimeFragment. When i added the object to the method then I was able to pass the data and no longer get a value of 0.
public void readySendBeat(Long beatTime){
activityCommander.sendBeatData(beatTime);
}
Try this, you dont need call to findViewById inside button listener, neither create duplicate long field:
MainActivity:
public class MainActivity extends AppCompatActivity implements
BeatTimeFragment.BeatTimeListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//Get called by BeatTimeFragment when button is pushed
#Override
public void sendBeatData(long beatTime) {
ToneTimeFragment toneFragment = (ToneTimeFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
toneFragment.setBeatLong(beatTime);
}
}
ToneTimeFragment:
public class ToneTimeFragment extends Fragment {
public void setBeatLong(long beatTime) {
try {
beatTimeL = beatTime;
} catch (NumberFormatException e) {
System.out.println("NumberFormatException: " + e.getMessage());
}
offSet = beatTimeL - toneTime;
offSetView.setText(beatTime + " msec");
BeatTimeFragment:
public class BeatTimeFragment extends Fragment {
private static Button beatBtn;
private static TextView beatTimeDisplay;
int q = 0;
long beatTime = 0;
//set up sending beatTime
BeatTimeListener activityCommander;
public interface BeatTimeListener{
public void sendBeatData(String beatTime);
}
//setup to send data to top
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
activityCommander = (BeatTimeListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString());
}
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.beat_time_fragment, container, false);
beatTimeDisplay = (TextView) view.findViewById(R.id.beatTimeDisplay);
final Button beatBtn = (Button) view.findViewById(R.id.beatBtn);
beatBtn.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v){
beatTime= System.currentTimeMillis();
beatTimeDisplay.setText(beatTime + " msec");
readySendBeat(v);
}
}
);
return view;
}
//calls to send data when button clicked
public void readySendBeat() {
activityCommander.sendBeatData(beatTime);
}
}
I have a problem when I want to use getApplication() for this class, error is take plaaaaaaace...what should I use instead of getApplication() (Becaus I want to use the method of TestClass is named setNamePermit) or how I should setNamePermit() method of test class.
public class CustomSwipeAdapter01 extends PagerAdapter{
private int[] image_Resources = {R.drawable.sample_01,R.drawable.sample_02,R.drawable.sample_03,R.drawable.sample_04,R.drawable.sample_05,R.drawable.sample_06,R.drawable.sample_07};
private Context ctx;
private LayoutInflater layoutInflater;
public TestClass app;
public CustomSwipeAdapter01(Context ctx) {
this.ctx = ctx;
}
#Override
public int getCount() {
return image_Resources.length;
}
#Override
public boolean isViewFromObject(View view, Object o) {
return (view == (RelativeLayout) o);
}
#Override
public Object instantiateItem(final ViewGroup container, final int position) {
layoutInflater=(LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View item_view=layoutInflater.inflate(R.layout.activity_story01,container,false);
ImageView imageView=(ImageView)item_view.findViewById(R.id.image_view);
TextView textView=(TextView)item_view.findViewById(R.id.image_count);
Button btn_back_story01 = (Button) item_view.findViewById(R.id.btn_back_story01);
imageView.setImageResource(image_Resources[position]);
int itemNo=position+1;
textView.setText(itemNo + "/" + getCount());
container.addView(item_view);
//what should use instead of getApplication() in below line:
app = (TestClass)getApplication();
btn_back_story01.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((Activity) ctx).finish();
app.setNewPermit(false);
ctx.startActivity(new Intent(ctx, MainStory01.class));
}
});
return item_view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((RelativeLayout)object);
}
}
Test Class is:
public class TestClass extends Application {
public Boolean getMedia_state() {
return media_state;
}
public void setMedia_state(Boolean media_state) {
this.media_state = media_state;
}
Boolean media_state;
Boolean checkPlaying;
public Boolean getNewPermit() {
return newPermit;
}
public void setNewPermit(Boolean newPermit) {
this.newPermit = newPermit;
}
Boolean newPermit;
MediaPlayer media;
#Override
public void onCreate() {
super.onCreate();
setMedia_state(true);
setNewPermit(true);
media = new MediaPlayer();
media = MediaPlayer.create(getApplicationContext(), R.raw.music);
}
public void musicRestart() {
media = MediaPlayer.create(getApplicationContext(), R.raw.music);
media.start();
media.setLooping(true);
}
public void musicPlay() {
media.start();
media.setLooping(true);
}
public boolean checkPlaying() {
if (media.isPlaying()) {
checkPlaying = true;
} else {
checkPlaying = false;
}
return checkPlaying;
}
public void musicStop() {
media.stop();
}
}
TestClass tc = new TestClass();
Accessing methods in TestClass:
tc.setNewPermit(false);
UPDATE: in your pager adapter, you can now pass any of those values around. For example, change your btn_back_story01 onClick() to:
btn_back_story01.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(CustomSwipeAdapter01.this, MainStory01.class);
intent.putExtra("is_new_permit", tc.getNewPermit());
startActivity(intent);
}
});
In MainStory01 activity's onCreate() you can now get the extras passed in your Intent, via Bundle...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getIntent().getExtras();
if(bundle != null) {
boolean isNewPermit = bundle.getBoolean("is_new_permit");
}
}
There may be some errors in the code, I am not at my work computer at the moment, but this should give you an idea of how to proceed.
I am using View Pager with fragment to showing image and video, I am able to show image and video properly but I have problem, when I swipe for video, then video is playing, but I swipe next or previous then video is still playing on just next or previous screen but when I move two slide next or previous then video is being stop, but why not on next or previous slide.
I search it more but I did not get any solution, any help will be appreciable.
Thanks in advance.
Here is my code:
This is Fragment Class
public class ContentFragment extends Fragment {
private final String imageResourceId;
private String type;
public ContentFragment(String imageResourceId,String type) {
System.out.println("Path In cons="+imageResourceId+"and type is="+type);
this.imageResourceId = imageResourceId;
this.type= type;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("Test", "hello");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.content_layout, container, false);
TouchImageView imageView = (TouchImageView) view.findViewById(R.id.touchImage);
imageView.setImageResource(R.id.touchImage);
imageView.setMaxZoom(10f);
VideoView videoView =(VideoView) view.findViewById(R.id.videoView1);
if(type.equals("image")) {
imageView.invalidate();
imageView.setVisibility(View.VISIBLE);
videoView.setVisibility(View.GONE);
try {
System.out.println("IN Content Fragment"+imageResourceId.toString());
Bitmap bmp = BitmapFactory.decodeFile(imageResourceId.toString());
imageView.setImageBitmap(bmp);
} catch(Exception e) {
System.out.println("Error Of image File"+e);
}
} else
try {
if(type.equals("video")){
videoView.invalidate();
videoView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
String path = imageResourceId.toString();
videoView.setVideoURI(Uri.parse(path));
videoView.setMediaController(new MediaController(getActivity()));
videoView.setFocusable(true);
videoView.start();
}
} catch(Exception e) {
e.printStackTrace();
}
return view;
}
}
This is pager adapter activity
public class MediaActivity extends FragmentActivity {
private MyAdapter mAdapter;
private ViewPager mPager;
public ArrayList<Content> contentList;
Context context;
LinearLayout numberOfPageLayout;
SharedPreferences sharedPreferences;
Handler progressHandler;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media);
context=(Context) getApplicationContext();
mPager = (ViewPager) findViewById(R.id.pager);
progressHandler = new Handler();
contentList=new ArrayList<Content>();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
contentList=new ContentDBAdapter(context).getAllContent();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
mAdapter = new MyAdapter(getSupportFragmentManager(),contentList);
mPager.setAdapter(mAdapter);
}
}.execute();
mPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
}
public static class MyAdapter extends FragmentPagerAdapter {
ArrayList <Content>contList=new ArrayList<Content>();
public MyAdapter(FragmentManager fm,ArrayList<Content> cont) {
super(fm);
this.contList=cont;
}
#Override
public int getCount() {
totalPage=contList.size();
return contList.size();
}
#Override
public Fragment getItem(int position) {
Content con=contList.get(position);
return new ContentFragment(con.getPath(),con.getType());
}
}
}
It is because ViewPager keeps offscreen fragments started. For instance you have a fragment visible to the user. ViewPager will try to keep the previous fragment (on the left side) and the next fragment (on the right side) started. This allows ViewPager performing smooth sliding when user decides to change the page, because the next and the previous pages are already prepared.
In your case the video player is not visible (offscreen), but ViewPager keeps it started as due to the behaviour described above. You can use setOffscreenPageLimit() method to change this behaviour. If you set page limit to 0, then offscreen fragments will be paused immediately. Unfortunately they will not only be paused, but stopped and detached from the activity too. This means when you return back to your fragment, it will recreate the whole layout anew. That's why you can try to override either Fragment.setUserVisibleHint() or Fragment.onHiddenChanged() and execute your pause/play logic there. ViewPager will update hidden state of a fragment depending on whether the fragment is actually visible to user or not.
Hope this helps.
You have to override setUserVisibleHint method in a fragment where u play video.
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible())
{
if (!isVisibleToUser) // If we are becoming invisible, then...
{
//pause or stop video
}
if (isVisibleToUser)
{
//play your video
}
}
}
I handle the problem like this:
boolean isVisible = false;
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
isVisible = isVisibleToUser;
if(player!=null)
player.pause();
super.setUserVisibleHint(isVisibleToUser);
}
then in onCreateView method:
SimpleExoPlayer player;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_screen_slide_page, container, false);
PlayerView playerView = v.findViewById(R.id.playerView);
playerView.getLayoutParams().width = ListPager.widthPixels;
playerView.getLayoutParams().height = ListPager.widthPixels;
if(player!=null)
player.release();
player = new SimpleExoPlayer.Builder(App.applicationContext).build();
playerView.setPlayer(player);
MediaItem mediaItem = MediaItem.fromUri(url);
player.setMediaItem(mediaItem);
player.prepare();
//---------The following code is important because if you remove the following if
// then if the next page is displaying, android will automatically initiate the
// previous and the next page, and the player will start playing :|
if(isVisible)
player.play();
}
I'm stuck with communication between activity and fragment using interface. I have created activity with child fragment. I wanna do some stuff with continuous thread defined in activity and during that thread when I'm getting some result at that time I wanna trigger to child fragment to do something.
My Container Activity
public class MySpaceActivity extends BaseDrawerActivity {
private OnSetLastSeenListener mListner;
public static Thread mThread = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setHeaders(Const.MY_SPACE);
super.setSubmenus(Const.MY_SPACE,
Utils.getSubmenuList(Const.MY_SPACE, MySpaceActivity.this),
submenuBean);
// super.attachFragment(submenuBean);
}
#Override
public void setHeaderSubMenu(SubmenuBean subMenuBean) {
// txt_submenu.setText(subMenuBean.getSubmenu_name());
this.submenuBean = subMenuBean;
Log.print("::::: setHeaderSubMenu ::::");
super.attachFragment(submenuBean);
}
public void setsubFragment(SubmenuBean subMenuBean) {
this.submenuBean = subMenuBean;
super.attachSubFragment(submenuBean);
}
#Override
public void onBackPressed() {
super.onBackPressed();
popLastFragment();
}
private void popLastFragment() {
if (super.getNumberOfChilds() > 1) {
super.popSubFragment();
} else {
finish();
}
}
#Override
protected Fragment getFragement() {
StudentsFragment fragment = new StudentsFragment(Const.MY_SPACE,
getSubmenubean());
return fragment;
}
public SubmenuBean getSubmenubean() {
return submenuBean;
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mThread = new Thread(new CountDownTimer(MySpaceActivity.this));
mThread.start();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if (mThread.isAlive()) {
mThread.interrupt();
mThread = null;
}
}
public void updateLastSeen(){
Log.print("::::::Call Interface::::::");
mListner.updateLastSeen();
}
class CountDownTimer implements Runnable {
private Context mContext;
private JSONObject mJsonObject;
private JSONArray mJsonArray;
public CountDownTimer(Context mContext) {
this.mContext = mContext;
}
// #Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
HttpChatLastSeen mChat = new HttpChatLastSeen();
mJsonObject = mChat.Http_ChatLastSeen(mContext);
String mResult = mJsonObject.getString("Result");
if (mResult.equalsIgnoreCase(String
.valueOf(Const.RESULT_OK))) {
mJsonArray = mJsonObject.getJSONArray("UserData");
for (int i = 0; i < mJsonArray.length(); i++) {
mJsonObject = mJsonArray.getJSONObject(i);
new DbStudentMasterBll(mContext).update(
"last_seen", mJsonObject
.getString("LastSeen"), Integer
.parseInt(mJsonObject
.getString("UserId")));
}
} else {
Log.print("MY LAST SEEN Response : "
+ mJsonObject.toString());
}
updateLastSeen();
Thread.sleep(15000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
Log.print("ChatLastSeenThread : ", e.getMessage());
}
}
}
}
}
My Child Fragment With Interface :
public class StudentsFragment extends Fragment implements OnSetLastSeenListener{
TextView txt_submenu;
ListView list_students;
SubmenuBean submenuBean;
int Mainmenu;
MySpaceActivity mMySpaceActivity;
ArrayList<DbStudentMasterBean> studentsList;
StudentsAdapter mAdapter = null;
OnSetLastSeenListener mListner;
public StudentsFragment() {
super();
}
public StudentsFragment(int Mainmenu, SubmenuBean submenuBean) {
this.submenuBean = submenuBean;
this.Mainmenu = Mainmenu;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_students, container,
false);
mMySpaceActivity = (MySpaceActivity) getActivity();
txt_submenu = (TextView) view.findViewById(R.id.txt_submenu);
txt_submenu.setText(submenuBean.getSubmenu_name());
txt_submenu.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mMySpaceActivity.openDrawer();
}
});
list_students = (ListView) view.findViewById(R.id.list_colleagues);
studentsList = new DbStudentMasterBll(getActivity()).getAllRecords();
mAdapter = new StudentsAdapter(getActivity(), studentsList, handler);
list_students.setAdapter(mAdapter);
list_students.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
DbStudentMasterBean bean = (DbStudentMasterBean) parent
.getAdapter().getItem(position);
Message msg = new Message();
msg.what = CHAT;
msg.obj = bean;
handler.sendMessage(msg);
}
});
return view;
}
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case CHAT:
submenuBean.setTag(VIEWCHATSTUDENT);
DbStudentMasterBean bean = (DbStudentMasterBean) msg.obj;
mMySpaceActivity.setsubFragment(submenuBean);
break;
}
};
};
#Override
public void updateLastSeen() {
// TODO Auto-generated method stub
Log.print("!!!!!!!!!Refresh Adapter!!!!!!!!!!!");
mAdapter.notifyDataSetChanged();
}
}
My Interface :
public interface OnSetLastSeenListener {
public void updateLastSeen();
}
So I have implemented interface OnSetLastSeenListener with my child fragment StudentsFragment . Now I'm calling method of tht interface updateLastSeen() from my container activity with thread. But it is not getting trigger to child fragment where I have implemented interface. So I don't know whether it is good way to communicate or not? Let me take your help to suggest on this solution or best way to communicate from child fragment to parent activity.
Thanks,
It is better to use interface when you want to communicate something from Fragment to Activity and not vice versa.
In your case, you can directly call the method in Fragment from Activity through fragment object. No need to use interface.
Something like this (For static fragments)
StudentsFragment fragment = (StudentsFragment) getFragmentManager()
.findFragmentById(R.id.fragmentid);
if (fragment != null && fragment.isInLayout()) {
fragment.updateLastSeen();
}
For dynamic fragment you can use the fragment object directly.
I have an activity that contains a View Pager that has an adapter FragmentStatePagerAdapter.
each time enter the activity it will take up 200mb of memory, after going back out of the activity(finish()) and then re entering it it will append and double the memory used on the phone.
After troubleshooting the problem it seems as if the fragment manager is not releasing the fragments although im trying to remove them but its just not working.
I tried emptying the fragment that is being added to make sure its not something internal inside the fragment the the problem remains.
my adapter code is
private class ChildrenPagerAdapter extends FragmentStatePagerAdapter
{
private List<ChildBean> childrenBean;
public ChildrenPagerAdapter(FragmentManager fm, List<ChildBean> bean)
{
super(fm);
this.childrenBean = bean;
}
#Override
public int getItemPosition(Object object)
{
return PagerAdapter.POSITION_NONE;
}
#Override
public Fragment getItem(int position)
{
ReportFragment reportFragment = new ReportFragment();
reportFragment.childBean = childrenBean.get(position);
reportFragment.position = position;
reportFragment.mPager = mPager;
if(position == 0)
{
reportFragment.mostLeft = true;
}
if(position == childrenNumber - 1)
{
reportFragment.mostRight = true;
}
return reportFragment;
}
#Override
public int getCount()
{
return childrenNumber;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object)
{
// TODO Auto-generated method stub
super.destroyItem(container, position, object);
}
}
my activity code is
public class ReportActivity extends CustomActivity
{
public ImageLoader imageLoader;
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
private int childrenNumber;
private int currentChild;
#Override
protected void onDestroy()
{
mPager.removeAllViews();
mPager.removeAllViewsInLayout();
mPager.destroyDrawingCache();
mPagerAdapter = null;
mPager = null;
System.gc();
super.onDestroy();
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setCustomTitle(string.title_activity_reports);
this.currentChild = getIntent().getIntExtra("itemselected", -1);
getSupportFragmentManager().
}
#Override
protected void onResume()
{
super.onResume();
mPager = (ViewPager) findViewById(R.id.vpchildren);
mPager.setOffscreenPageLimit(6);
childrenNumber = MainActivity.bean.size();
mPagerAdapter = new ChildrenPagerAdapter(getSupportFragmentManager(), MainActivity.bean);
mPager.setAdapter(mPagerAdapter);
mPager.setCurrentItem(currentChild);
}
}
Fragment code :
public class ReportFragment extends Fragment
{
public ChildBean childBean;
public int position;
public ImageView img;
public ImageLoader imageLoader;
public DisplayImageOptions options;
private int pee = 0;
private int poop = 0;
private double sleep = 0.0;
public ViewPager mPager;
public boolean mostLeft = false;
public boolean mostRight = false;
public ReportFragment()
{
}
#Override
public void onDestroyView()
{
super.onDestroyView();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.report_fragment, container, false);
if(mostLeft)
{
rootView.findViewById(id.btnleft).setVisibility(View.GONE);
}
if(mostRight)
{
rootView.findViewById(id.btnright).setVisibility(View.GONE);
}
rootView.findViewById(id.btnleft).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
});
rootView.findViewById(id.btnright).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
mPager.setCurrentItem(mPager.getCurrentItem() + 1);
}
});
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
Date dobchild = new Date();
((TextView) rootView.findViewById(id.tvday)).setText(sdf.format(dobchild));
ImageView childimg = (ImageView) rootView.findViewById(id.img_child);
((TextView) rootView.findViewById(id.tvchildname)).setText(childBean.childname);
((TextView) rootView.findViewById(id.tvclassname)).setText(((CustomApplication) getActivity().getApplication()).preferenceAccess.getCurrentClassName());
Date dob = null;
String age = "";
try
{
dob = sdf.parse(childBean.childdob);
age = GeneralUtils.getAge(dob.getTime(), getString(string.tv_day), getString(string.tv_month), getString(string.tv_year));
}
catch(ParseException e)
{
// TODO:
}
((CustomTextView) rootView.findViewById(id.tvchildage)).setText(age);
DisplayImageOptions options =
new DisplayImageOptions.Builder().showImageForEmptyUri(drawable.noimage).showImageOnFail(drawable.noimage).showStubImage(drawable.noimage).cacheInMemory()
.imageScaleType(ImageScaleType.NONE).build();
imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(childBean.childphoto, childimg, options);
final TextView tvpee = (TextView) rootView.findViewById(id.tvpeetime);
final TextView tvpoop = (TextView) rootView.findViewById(id.tvpootimes);
final TextView tvsleep = (TextView) rootView.findViewById(id.tvsleeptime);
rootView.findViewById(id.btnaddpee).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
pee = pee + 1;
if(pee > 9)
{
Toast.makeText(getActivity(), getString(string.tvareyousurepee), Toast.LENGTH_LONG).show();
}
tvpee.setText(String.format(getString(string.tvtimes), pee));
}
});
rootView.findViewById(id.btnminuspee).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if(pee > 0)
{
pee = pee - 1;
tvpee.setText(String.format(getString(string.tvtimes), pee));
}
}
});
rootView.findViewById(id.btnpluspoo).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
poop = poop + 1;
if(poop > 9)
{
Toast.makeText(getActivity(), getString(string.tvareyousurepoop), Toast.LENGTH_LONG).show();
}
tvpoop.setText(String.format(getString(string.tvtimes), poop));
}
});
rootView.findViewById(id.btnminuspoo).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if(poop > 0)
{
poop = poop - 1;
tvpoop.setText(String.format(getString(string.tvtimes), poop));
}
}
});
rootView.findViewById(id.btnaddsleep).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
sleep = sleep + 0.25;
tvsleep.setText(String.format(getString(string.tvhours), sleep));
}
});
rootView.findViewById(id.btnminussleep).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if(sleep > 0)
{
sleep = sleep - 0.25;
tvsleep.setText(String.format(getString(string.tvhours), sleep));
}
}
});
rootView.findViewById(id.btnsave).setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Toast.makeText(getActivity(), "Report Saved.", Toast.LENGTH_LONG).show();
getActivity().finish();
}
});
return rootView;
}
}
Please advise... Thanks
ViewPager itself has a method setOffscreenPageLimit which allows you to specify number of pages kept by the adapter. So your fragments that are far away will be destroyed.
First of all looking at your code I don't see you doing any memory releasing measures in your fragments onDestroy(). The fact that fragment itself is destroyed and gc'ed does not mean all resources you allocated were removed too.
For example, my big concern is:
imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(childBean.childphoto, childimg, options);
From what I see here it seems that there is a static instance of ImageLoader that gets poked every time a new fragment appears, but I can't see where a dying fragment would ask ImageLoader to unload its stuff. That looks suspicious to me.
If I were you I would dump an HPROF file of my application the moment it took extra 200mb (as you claim) after activity restart and analyze references via MAT (memory analyzer tool). You are clearly having memory leaks issue and I highly doubt the problem is in Fragments themselves not being destroyed.
In case you don't know how to analyze memory heap, here is a good video. I can't count how many times it helped me identifying and getting rid of memory leaks in my apps.
Don't store 'strong' references to ViewPager or ImageView in your Fragment. You're creating a cyclical reference that will keep everything in memory. Instead, if you must keep a reference to ViewPager or any other element that references its context outside of your Activity, try using a WeakReference, e.g:
private WeakReference<ViewPager> mPagerRef;
...
mPagerRef = new WeakReference<ViewPager>(mPager);
...
final ViewPager pager = mPagerRef.get();
if (pager != null) {
pager.setCurrentItem(...);
}
Following this pattern with Objects that store a reference to the Activity or Application context (hint: any ViewGroup, ImageView, Activity, etc.) should prevent "memory leaks" in the form of "retain cycles" from occurring.
it seems that your code is not destroying the view, check this Destroy item from the ViewPager's adapter might solve this issue.
After using the memory analyzer tool in eclipse i found out that what is sticking in my memory is the actual layout of my fragments.
Relative layout in specific.
The reason for this is a CustomTextView that i created that has a custom font set as a typeface.
Typeface face=Typeface.createFromAsset(context.getAssets(), "Helvetica_Neue.ttf");
this.setTypeface(face);
To solve the memory leak i simply did the following answer found here:
public class FontCache {
private static Hashtable<String, Typeface> fontCache = new Hashtable<String, Typeface>();
public static Typeface get(String name, Context context) {
Typeface tf = fontCache.get(name);
if(tf == null) {
try {
tf = Typeface.createFromAsset(context.getAssets(), name);
}
catch (Exception e) {
return null;
}
fontCache.put(name, tf);
}
return tf;
}
}