VideoView onTouch events: pause/resume video, and show/hide MediaController and ActionBar - java

Question summary:
1) How to first display the video as paused, and not play it immediately?
2) How to pause/un-pause the video on touch, and also hide/show the ActionBar and MediaController.
I'd appreciate any advice. Thanks! (Relevant Code is attached)
Update 1
Found somewhat of a solution to question 2 (needed to return false), but I still don't know how to answer question 1.
When the user presses a button in my app, it takes them to watch their video. When they first open that screen, I'd like the video to be paused and not play immediately. I'd also like to be able to pause playback of the video by tapping the screen. When the video is paused, I'd like to show the ActionBar and the MediaController. When the video is resumed, I'd like to hide the ActionBar and MediaController (possibly after a slight delay?)
I've tried a few things, but I end up with problems, like the video will pause but not resume, or the ActionBar and MediaController will not show or hide properly.
Update 2
I have found a partial solution to question 1 and have updated the code to display the video as paused the first time it is opened. However, when it is opened for the first time, it only shows a black screen until I touch the videoview to play it. After watching the video once, it will reset to the beginning and pause, waiting to be played again, and will show the correct image from the beginning of the video. But I don't know how to get around the black screen at the beginning.
Relevant code:
public class ViewImageVideoFragment extends Fragment
{
private int position = 0;
private MediaController mMediaController;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mMediaController = new MediaController(getActivity());
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
if (savedInstanceState != null)
{
position = savedInstanceState.getInt("position");
}
View v = inflater.inflate(R.layout.fragment_video_view, parent, false);
mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
mVideoView.setVideoPath(videoPath);
mVideoView.setMediaController(mMediaController);
mVideoView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
if (mVideoView.isPlaying())
{
mVideoView.pause();
if (!getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().show();
mMediaController.show(0);
}
position = mVideoView.getCurrentPosition();
return false;
}
else
{
if (getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().hide();
mMediaController.hide();
}
mVideoView.seekTo(position);
mVideoView.start();
return false;
}
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mediaPlayer)
{
mVideoView.seekTo(0);
}
});
if (position != 0)
{
mVideoView.seekTo(position);
mVideoView.start();
}
else
{
mVideoView.seekTo(0);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
if (mVideoView != null)
{
savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
}
mVideoView.pause();
}
}

To first show the video as paused, simply change seekTo(0) to seekTo(1) in your code. This will move the video to the time at 1 millisecond and you can take it from there.
//edited here
private int position = 1;
private MediaController mMediaController;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mMediaController = new MediaController(getActivity());
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
if (savedInstanceState != null)
{
position = savedInstanceState.getInt("position");
}
View v = inflater.inflate(R.layout.fragment_video_view, parent, false);
mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
mVideoView.setVideoPath(videoPath);
mVideoView.setMediaController(mMediaController);
mVideoView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
if (mVideoView.isPlaying())
{
mVideoView.pause();
if (!getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().show();
mMediaController.show(0);
}
position = mVideoView.getCurrentPosition();
return false;
}
else
{
if (getActivity().getActionBar().isShowing())
{
getActivity().getActionBar().hide();
mMediaController.hide();
}
mVideoView.seekTo(position);
mVideoView.start();
return false;
}
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mediaPlayer)
{
//here
mVideoView.seekTo(1);
}
});
//here
if (position != 1)
{
mVideoView.seekTo(position);
mVideoView.start();
}
else
{
//here
mVideoView.seekTo(1);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
if (mVideoView != null)
{
savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
}
mVideoView.pause();
}
}

If I understand correctly, you want to display a frame from the video as a placeholder until you are ready to start the video. There's two ways I know to accomplish this:
seekTo
You can use MediaPlayer.seekTo to move the video some frames ahead, for example using the value 150 to display the frame at the 150th millisecond in the video file. The video does not need to be started in order to seek.
MediaMetadataRetriever
MediaMetadataRetriever met = new MediaMetadataRetriever();
try {
met.setDataSource(data[0], new HashMap<String, String>()); //use this constructor, other one has a bug...
Bitmap b = met.getFrameAtTime();
if (b == null)
b = met.getFrameAtTime(150, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
met.release();
return b;
} catch (Exception e) {
Log.d(TAG, "MediaMetadata failed", e);
}
This will give you a Bitmap which you can then throw in an ImageView and set in place of the video. However, this API has always been buggy for me depending on the types of video codecs you are dealing with.

My sources --
show()
show(int timeout)
hide()
isShowing()
onTouchEvent()
All notes are in the code
public class ViewImageVideoFragment extends Fragment
{
private int position = 0;
private MediaController mMediaController;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mMediaController = new MediaController(getActivity());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
if (savedInstanceState != null)
{
position = savedInstanceState.getInt("position");
}
v = inflater.inflate(R.layout.fragment_video_view, parent, false);
mVideoView = (VideoView) v.findViewById(R.id.fragmentVideoView);
mVideoView.setVideoPath(videoPath);
mVideoView.setMediaController(mMediaController);
mVideoView.setOnTouchListener(
new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent motionEvent)
{
if (mVideoView.isPlaying())
{
mVideoView.pause();
/*
Ok, so now you want to use that show(), preferrably without the int timeout
I didn't add it in myself but you should be able to handle it yourself
*/
return true;
}
else /* I changed it to else, change it to if else if you have something specific you want to deal with */
{
/*
I would use that hide method I linked here, then start the
video, I assume you know how to play the video yourself
*/
}
return false;
}
});
mVideoView.seekTo(position);
mVideoView.start();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
if (mVideoView != null)
{
savedInstanceState.putInt("position", mVideoView.getCurrentPosition());
}
mVideoView.pause();
}
}
I provided the other methods because, depending on how you may continue, they may or may not prevent future questions.

Related

WearOS onGenericMotionListener not called

I am trying to catch the action when I rotate my bezel on my Samsung Galaxy Watch 4, but it never "runs".
Here is my code:
findViewById(R.id.Badtunna).setOnGenericMotionListener(new View.OnGenericMotionListener() {
#Override
public boolean onGenericMotion(View view, MotionEvent motionEvent) {
System.out.println("GUM");
if(motionEvent.getAction() == MotionEvent.ACTION_SCROLL &&
motionEvent.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)) {
System.out.println("BUBBEL");
return true;
}
return false;
}
});
My view is a normal TextView:
<TextView
android:id="#+id/Badtunna"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Badtunna" />
Here is my onCreate() in MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
// Add all the domoticz devices
domoticz_devices.put(766, "idx_766");
domoticz_devices.put(17, "idx_17");
findViewById(R.id.Skymningssensor).requestFocus();
findViewById(R.id.Skymningssensor).setOnGenericMotionListener(new View.OnGenericMotionListener() {
#Override
public boolean onGenericMotion(View view, MotionEvent motionEvent) {
System.out.println("GUM");
if(motionEvent.getAction() == MotionEvent.ACTION_SCROLL &&
motionEvent.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)) {
System.out.println("BUBBEL");
return true;
}
return false;
}
});
TextView idx_17_button = findViewById(R.id.idx_17);
idx_17_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
toggleDomoticzDevice(17, "idx_17");
} catch (IOException e) {
e.printStackTrace();
}
}
});
TextView idx_657_button = findViewById(R.id.idx_657);
idx_657_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
toggleDomoticzDevice(657, "idx_657");
} catch (IOException e) {
e.printStackTrace();
}
}
});
handler.postDelayed(new Runnable() {
#Override
public void run() {
for (Integer i : domoticz_devices.keySet()) {
getDomoticzDeviceAndSetTextview(i, domoticz_devices.get(i));
}
handler.postDelayed(this, delay);
}
}, delay);
}
When focus is "working" should the keyboard pop up?
I have also updated my TextView and added focusable:true and focusableintouchmode:true
Thanks in advance!
Best regards Max
Docs here
https://developer.android.com/training/wearables/user-input/rotary-input#custom-scrolling
Likely issue is focus
Remember to make sure your view gains focus, otherwise the events will not come through.
https://developer.android.com/training/wearables/user-input/rotary-input#custom-scrolling
By default, launching an activity or even tapping on a view does not give it focus, even if it is focusable. To give your view focus, the view must use the tag or manually call View.requestFocus().

Android QR Code Scanner camera not opening in Fragment

I try to create QR Code scanner in fragment, but camera won't showing in surfaceview and just turn black.
here's my java class:
public class ScanFragment extends Fragment {
SurfaceView surfaceView;
CameraSource cameraSource;
TextView textView;
BarcodeDetector barcodeDetector;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_scan, container, false);
surfaceView = (SurfaceView) view.findViewById(R.id.cameraPreview);
textView = (TextView) view.findViewById(R.id.scanText);
barcodeDetector = new BarcodeDetector.Builder(view.getContext().getApplicationContext())
.setBarcodeFormats(Barcode.QR_CODE).build();
cameraSource = new CameraSource.Builder(view.getContext().getApplicationContext(), barcodeDetector)
.setRequestedPreviewSize(640, 480).build();
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (ActivityCompat.checkSelfPermission(getContext().getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
cameraSource.start(holder);
}catch (IOException e){
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> qrCodes = detections.getDetectedItems();
if(qrCodes.size() != 0){
textView.post(new Runnable() {
#Override
public void run() {
Vibrator vibrator = (Vibrator) getContext().getApplicationContext().getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(1000);
textView.setText(qrCodes.valueAt(0).displayValue);
}
});
}
}
});
return view;
}
}
I gave the uses permissions from the android manifest file. compiles seamlessly in android studio but when I run it on the phone the camera just turn black and no crash from that.
Anyone know how to fix this?
From Android 6.0(API 23) on, you need to request runtime permission from the users. That is why your camera doesn't show anything. Permission is only defined in AndroidManifest, but the user did not agree to allow your application to use a camera. You have a good example of how to request runtime permissions here.
If you want to read more about this, there is also documentation available on Android developer:
https://developer.android.com/distribute/best-practices/develop/runtime-permissions
https://developer.android.com/training/permissions/requesting

Autocomplete search bar using Google Places API in a fragment

My app currently looks like this:
I want to add a search bar where I can search any place as Google maps. The search bar should be in an Auto Complete way.I got this code from https://examples.javacodegeeks.com/android/android-google-places-autocomplete-api-example/
Have a look at the above link.
And these codes where for an ORDINARY APP to get Auto Complete search bar. It doesnt suit for app using fragment. And I dont know how to do it with fragments.
Here is my code
For the Main Activity (ProfileActivity)
public class ProfileActivity extends AppCompatActivity {
final String TAG = this.getClass().getName();
BottomBar mBottomBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
mBottomBar = BottomBar.attach(this, savedInstanceState);
mBottomBar.setItemsFromMenu(R.menu.menu_user, new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int i) {
if(i == R.id.ButtonBarFeed)
{
NewsFragment f = new NewsFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,f).commit();
}
else if(i == R.id.ButtonBarMap)
{
MapFragment f = new MapFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,f).commit();
}
else if(i == R.id.ButtonBarUser)
{
UserFragment f = new UserFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame,f).commit();
}
}
#Override
public void onMenuTabReSelected(#IdRes int menuItemId) {
}
});
mBottomBar.mapColorForTab(0,"#28809f");
}
public boolean googleServicesAvailable(){
GoogleApiAvailability api = GoogleApiAvailability.getInstance();
int isAvailable = api.isGooglePlayServicesAvailable(this);
if(isAvailable == ConnectionResult.SUCCESS){
return true;
}else if(api.isUserResolvableError(isAvailable)){
Dialog dialog = api.getErrorDialog(this, isAvailable, 0);
dialog.show();
} else {
Toast.makeText(this,"Can't connet to Play Services", Toast.LENGTH_LONG).show();
}
return false;
}
boolean twice;
#Override
public void onBackPressed() {
Log.d(TAG, "click");
if(twice == true){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
System.exit(0);
}
twice = true;
Log.d(TAG, "twice:" + twice);
Toast.makeText(ProfileActivity.this, "Please press BACK again to exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
twice = false;
Log.d(TAG, "twice:" + twice);
}
}, 3000);
}
}
MapFragment
public class MapFragment extends Fragment implements OnMapReadyCallback {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.map, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
SupportMapFragment fragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.mapView1);
fragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap){
}
}
I have to add a search bar with Auto Complete like Google map.Please with reference of the Link which I have given at starting, Can Anyone code for my MapFragment?

How to create a class or method for multiple instance of webview

I have 3 fragments with their 3 layouts in tablayout. All three layout have their individual webview, swipeRefreshLayout and a progress bar. Currently I copy paste the same code in all three fragments . I want to make a class or a single method such that the changes i make in it will reflect on all three webview setting in the fragment
Below is my fragment, I just copy and paste the code below in all three fragments & only change the url.
public class Yahoo extends Fragment {
final String url = "http://www.yahoo.com/";
private WebView webView;
private ProgressBar progressBar1;
private SwipeRefreshLayout mSwipeRefreshLayout1;
public Yahoo() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_tab13, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
progressBar1 = (ProgressBar) view.findViewById(R.id.progressBar1);
webView = (WebView) view.findViewById(R.id.website_detail_1);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int progress) {
progressBar1.setProgress(progress);
if (progress == 100) {
progressBar1.setVisibility(View.GONE);
if (mSwipeRefreshLayout1.isRefreshing()) {
mSwipeRefreshLayout1.setRefreshing(false);
}
} else {
progressBar1.setVisibility(View.VISIBLE);
}
}
});
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
webView.loadUrl(url);
mSwipeRefreshLayout1 = (SwipeRefreshLayout) view.findViewById(R.id.swipe1);
mSwipeRefreshLayout1.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
webView.loadUrl(url);
}
});
webView.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
return false;
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
// Log.d("Yahoo webview", "destroy");
if (webView != null) {
webView.removeAllViews();
webView.destroy();
}
webView = null;
}
}
Could you help me out as how to create a class and and handle objects like webview , progress bar & swipeRefreshLayout such that I dont have to duplicate the same code in all three fragments ?
One thing I can suggest is that you create a single Fragment class, then create 3 instances of it using different urls.
So you will have one fragment class and one layout for it. And then you just instantiate them with different urls (if url is the only difference between them)

how android GC exactly works?

i know that GC take care of objects that there is no Reference to it , but i do not know how it works exactly.
in this simple android code we have an activity and textview in it, i know when screen rotates the entire activity destroyed and android create a new one.
GC can destroy the previous activity?
is it right that because textview hold a Reference to the activity the entire activity survive from GC ?
do i need do something in activity onfinish(or something similar) to release Reference ?
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView textview = new TextView(this);
textview .setText("Leaks are bad");
setContentView(textview );
}
Edite:
this my codes.
i used MAT:
Biggest Object :com.android.internal.policy.impl.PhoneWindow$DecorView
by using MAT i found that DecorView object is the problem, when i rotate screen 7 times app crash with OOM and exactly there is 7 DecorView Object in MAT report.
package atsoft.law.reader;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import atsoft.law.R;
import atsoft.law.selecttext.NewHighlightDialog;
public class ReaderActivity extends BaseReaderActivity
{
Bundle bundle;
MainDialogFragment mainDialogFragment;
NewHighlightDialog newHighlightDialog;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
bundle = getIntent().getExtras();
setLawID(bundle.getInt("law_id", 0));
setCurrentPage(bundle.getInt("madde_id", 0));
mainDialogFragment = new MainDialogFragment();
adapter.setMainDialogFragment(mainDialogFragment);
requestLaw(lawID);
}
/////////////////OnLawReceived//////////////
#Override
protected void OnLawReceived()
{
adapter.PrePairAdapter(getSupportFragmentManager(),null, this, lawID);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(getCurrentPage());
Log.i("total", String.valueOf(Runtime.getRuntime().totalMemory()));
Log.i("max", String.valueOf(Runtime.getRuntime().maxMemory()));
Log.i("free", String.valueOf(Runtime.getRuntime().freeMemory()));
}
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putInt("current_viewpager_page", viewPager.getCurrentItem());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
if(savedInstanceState != null)
{
setCurrentPage(savedInstanceState.getInt("current_viewpager_page", 0));
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(keyCode==KeyEvent.KEYCODE_MENU)
{
adapter.Prepair2();
mainDialogFragment.Initialize(this, viewPager, adapter);
mainDialogFragment.show(getSupportFragmentManager(),null);
return true;
}
else if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
{
viewPager.setCurrentItem(viewPager.getCurrentItem()+1);
return true;
}
else if(keyCode == KeyEvent.KEYCODE_VOLUME_UP)
{
viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
return true;
}
else if(keyCode == KeyEvent.KEYCODE_BACK)
{
if(mainDialogFragment.isAdded())
{
mainDialogFragment.dismiss();
}
}
return super.onKeyDown(keyCode, event);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.reader, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings)
{
return true;
}
return super.onOptionsItemSelected(item);
}
/////////ViewPager Page Events/////
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
if (newHighlightDialog != null) newHighlightDialog.dismissAndDeactivateTextSelector();
}
#Override
public void onPageScrollStateChanged(int i) {
}
public NewHighlightDialog getHighlightDialog()
{
if(this.newHighlightDialog == null) this.newHighlightDialog = new NewHighlightDialog(this);
return this.newHighlightDialog;
}
#Override
protected void onDestroy()
{
Log.i("BaseReaderActivity", "onDestroy ");
super.onDestroy();
unbindDrawables(findViewById(R.id.root_in_readeractivity_layout));
mainDialogFragment.releaseReference();
mainDialogFragment = null;
if(newHighlightDialog != null)
{
newHighlightDialog.realestReference();
newHighlightDialog = null;
}
getAdapter().releaseReference();
System.gc();
}
private void unbindDrawables(View view) {
if (view.getBackground() != null)
view.getBackground().setCallback(null);
if (view instanceof ImageView) {
ImageView imageView = (ImageView) view;
imageView.setImageBitmap(null);
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++)
unbindDrawables(viewGroup.getChildAt(i));
if (!(view instanceof AdapterView))
viewGroup.removeAllViews();
}
}
}
public abstract class BaseReaderActivity extends ActionBarActivity implements OnThreadFinishListener, ViewPager.OnPageChangeListener
{
protected int lawID = 0;
protected int vpCurrentPage = 0;
protected FragmentAdapter adapter;
protected ViewPager viewPager;
private GlobalData globalData;
ProgressDialog progressDialog;
private void Init()
{
globalData= (GlobaData) this.getApplicationContext();
adapter = FragmentAdapter.getInstance(getSupportFragmentManager());
viewPager = (ViewPager) findViewById(R.id.vp);
viewPager.setOnPageChangeListener(this);
progressDialog = new ProgressDialog(this);
}
protected FragmentAdapter getAdapter()
{
return FragmentAdapter.getInstance(getSupportFragmentManager());
}
protected ViewPager getPager()
{
return this.viewPager;
}
protected GlobalStack getGlobalData()
{
return this.globalData;
}
protected DbCenter getDb()
{
return DbCenter.getInstance(this);
}
protected void setLawID(int id)
{
this.lawID = id;
}
protected int getLawID()
{
return this.lawID;
}
protected void setCurrentPage(int page)
{
this.vpCurrentPage = page;
}
protected int getCurrentPage()
{
return this.vpCurrentPage;
}
protected void requestLaw(int lawID)
{
if(!getGlobalData().checkLawAvailability(lawID))
{
this.UploadLawToGlobalData(lawID);
return;
}
else
{
this.OnLawReceived();
}
}
protected abstract void OnLawReceived();
protected void UploadLawToGlobalData(int lawID)
{
progressDialog.setText(LawIDs.getFaNameById(lawID));
progressDialog.show();
getDb().Prepair(lawID, this);
}
public Law getCurrentLaw()
{
return getGlobalData().getTheLaw();
}
#Override
public void threadFinished() throws IOException, XmlPullParserException
{
getGlobalData().UploadToGlobalData(getDb().getLaw());
this.OnLawReceived();
Log.i("BaseReaderActivity","upload completed !");
Log.i("BaseReaderActivity", "OnLawReceived");
progressDialog.hide();
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.activity_main_);
Init();
getGlobalData().Init();
viewPager.setOffscreenPageLimit(2);
viewPager.setSoundEffectsEnabled(true);
adapter.setViewPager(viewPager);
}
}
GC is cleaning your objects and (in practise) you can't do anything with that, this is language property (awesome feature in my opinion). you don't have to do anything in "onFinish", system will clean stuff for you, yes - all your objects, widgets etc. if you want to keep some data when device rotate (so like you said Activity is destroyed and all it's references) you might use onSaveInstanceState. More about saving data against GC HERE
Based on your scenario, you just want to destroy the previous setup from your previous orientation, right?
The best way to do it is
android:configChanges="orientation|screenSize"
On-topic question, check this Why is it bad practice to call System.gc()?
calling system.gc in your app you don't have the control of what might the collector kill in your app and it might cause a lot of trouble like nullpointers and etc.

Categories