How do you keep track of dependant asynchronous tasks? - android

I'm making an Android Application at the moment using MVC. I'm using an Activity as a Controller and a different class as the View.
The View is waiting for two asynchronous tasks, a Google Map and a task sent to fetch data from a database. The View needs the data from the database to place a marker on the map. If the map loads first the we can't place the marker. If the database task finishes then we needs to wait for the map to load.
How do I check that the dependant tasks are finished?
Should I just have a flag to say if the db task is finished and then when the map loads check this to continue and vice versa for the map.
Or is there a better way to do all this.
This is a simplified version of the View:
public class SellerAddView
implements OnChangeListener<Model>, OnMapReadyCallback{
...
public SellerAddView(View view, Model model, Activity activity){
model.addListener(this);
mapFragment = ((MapFragment)activity.getFragmentManager()
.findFragmentById(R.id.add_map));
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
LatLng coords = model.getLatLng();
map.addMarker(new MarkerOptions().position(coords));
}
#Override
public void onChange(SellerAddModel model) {
updateView();
}
}
Here is the simplified Controller:
public class Controller extends Activity{
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View screenView = View.inflate(this, activity_seller_add, null);
model = new Model();
view = new view(screenView, model, this);
populateModel();
setContentView(screenView);
}
public void populateModel(){
handler.post(new Runnable() {
#Override
public void run() {
synchronized (model) {
Model newModel = new ModelDao().getId(id);
model.consume(model);
}
}
});
}
}

So you can use the Splash screen to wait for all data to be loaded, that will be better.
Sample code as following:
public class SplashScreen extends Activity {
private static int SPLASH_DELEY = 3000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(SplashScreen.this, MainActivity.class);
startActivity(intent);
finish();
}
}, SPLASH_DELEY);
}
}
And for activity_splash_screen.xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.bjiang.map_ex.SplashScreen">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageLogo"
android:layout_centerInParent="true"
android:src="#drawable/splash_file"/>
</RelativeLayout>

Related

Two activities using the same fragment - problem

Two activities using the same fragment. The fragment has a text view.
Main activity writes “message 1” into the text view and it shows up.
A button in the main activity launches the second activity “for result”.
The Second activity writes “message 2” into the text view and it shows up.
A button in the second activity does set Result Activity.RESULT_OK and then finish().
The main activity gets the “onActivityResult” Result OK and writes “message 3” into the text view.
However “Message 3” does not show up in the text view. Instead “message 1” shows up.
public class MainActivity extends AppCompatActivity {
private static Context context;
private static Button btn_main;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
btn_main = findViewById(R.id.btn_main);
FragmentDisplay.setMessage1("Message 1");
btn_main.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
secondactivityLauncher.launch(intent);
}
});
}
ActivityResultLauncher<Intent> secondactivityLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
FragmentDisplay.setMessage1("Message 3");
}
}
});
public static Context getContext(){
return context;
}
}
public class SecondActivity extends AppCompatActivity {
private static Button btn_second;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
btn_second = findViewById(R.id.btn_second);
FragmentDisplay.setMessage1("Message 2");
btn_second.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = getIntent();
setResult(Activity.RESULT_OK, intent);
finish();
}
});
}
}
public class FragmentDisplay extends androidx.fragment.app.Fragment {
private static TextView textView1;
public FragmentDisplay() {
// Required empty public constructor
}
RecyclerView mRecyclerView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.display_fragment, null);
textView1 = (TextView)view.findViewById(R.id.tv1);
return view;
}
public static void setMessage1(String str){
textView1.setText(str);
}
} // end of class
//activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">
<fragment
android:id="#+id/display_fragment"
android:name="ddi.pos.display.FragmentDisplay"
android:layout_width="700dp"
android:layout_height="180dp"
android:background="#00CC00"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="80dp" />
<Button
android:id="#+id/btn_main"
android:layout_below="#+id/display_fragment"
android:layout_marginTop="100dp"
android:layout_marginLeft="50dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#FFFFFF00"
android:textSize="25sp"
android:text="Start Second Activity"
/>
//second_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainActivity">
<fragment
android:id="#+id/display_fragment"
android:name="ddi.pos.display.FragmentDisplay"
android:layout_width="700dp"
android:layout_height="180dp"
android:background="#00CC00"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="80dp" />
<Button
android:id="#+id/btn_second"
android:layout_below="#+id/display_fragment"
android:layout_marginTop="100dp"
android:layout_marginLeft="300dp"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#000000"
android:textSize="25sp"
android:text="Finish Second Activity"
/>
//display_fragment.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#CC5500"
>
<TextView android:id="#+id/tv1"
android:background="#0055FF"
android:layout_height="60dp"
android:layout_width="600dp"
android:text=""
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:textSize="20dp"
android:textColor="#ff000000"
/>
Caveat: I suspect that what you posted is not what you actually want to do, but a workaround of some kind so this answer may or may not actually address your use-case. It does, however, produce the behavior you asked for in the question. You said you are not trying to send data between activities, but you want the message in the first activity to change in response to actions in the second activity which implies information may be shared.
Main Answer:
The example below, using a shared ViewModel between Activity and Fragment and using data transfer across activities using intents has the behavior you describe in your question.
The ViewModel allows sharing of data between the Activity and Fragment, since the Fragment can observe the LiveData and respond when the activity changes it. Since the question calls startActivityForResult and handles the result, I used those to handle passing data back to change the message.
MainActivity.java
public class MainActivity extends AppCompatActivity {
ActivityResultLauncher<Intent> secondActivityLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// as you indicated:
//viewModel.setMessage("Message 3");
// or like this if you sent data
Intent data = result.getData();
if( data != null ) {
Bundle extras = data.getExtras();
if( extras != null ) {
String msg = extras.getString("response");
viewModel.setMessage(msg);
}
}
}
}
});
private MainViewModel viewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewModel = new ViewModelProvider(this).get(MainViewModel.class);
// Always initialize the message to "Message 1"
viewModel.setMessage("Message 1");
Button btn = findViewById(R.id.btn_main);
btn.setOnClickListener(view -> {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("message", "Message 2");
secondActivityLauncher.launch(intent);
});
}
}
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// This ViewModel instance is "not" the same instance as the one from MainActivity, it is
// just to facilitate communication between the Activity and Fragment
MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class);
// as you had it with hard-coded message 2
// viewModel.setMessage("Message 2");
// or like this if you sent the message
Intent i = getIntent();
Bundle b = i.getExtras();
if( b != null ) {
String msg = b.getString("message");
viewModel.setMessage(msg);
}
Button btn = findViewById(R.id.btn_second);
btn.setOnClickListener(view -> {
Intent intent = new Intent();
intent.putExtra("response", "Message 3");
setResult(Activity.RESULT_OK, intent);
finish();
});
}
}
MainViewModel.java
public class MainViewModel extends ViewModel {
private final MutableLiveData<String> message_to_display = new MutableLiveData<>();
LiveData<String> message() { return message_to_display; }
void setMessage(String msg) {
message_to_display.postValue(msg);
}
}
DisplayFragment.java
public class DisplayFragment extends Fragment {
public DisplayFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_display, container, false);
}
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView txt = view.findViewById(R.id.tv1);
// Get the ViewModel from the hosting activity, could be
// Main or Second, and observe its message. Update the
// TextView if the message is changed.
MainViewModel viewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
viewModel.message().observe(getViewLifecycleOwner(), s -> {
txt.setText(s);
});
}
}

Reverse Geocoding using HERE maps SDK gives error

I am trying to retrieve Address for a particular GeoCoordinate using Reverse Geo coding, But I am getting some errors in executing the Reverse GeoCode Request. I am getting Error:400 Bad Request. Here is my full code:
public class Address_Service extends AppCompatActivity {
String Location1,Address;
double Lat,Lng;
private ListView list;
private boolean isMapInitialized = false;
//LIST OF ARRAY STRINGS WHICH WILL SERVE AS LIST ITEMS
ArrayList<String> listItems=new ArrayList<String>();
//DEFINING A STRING ADAPTER WHICH WILL HANDLE THE DATA OF THE LISTVIEW
ArrayAdapter<String> adapter;
private BroadcastReceiver BUS_COD=new BroadcastReceiver() { //this receiver recieves new location from Database service
#Override
public void onReceive(Context context, Intent intent) {
Location1=intent.getStringExtra("BUS_LOC");
Lat = Double.valueOf(Location1.substring(0, 9));//extracting latitude
Lng = Double.valueOf(Location1.substring(10, Location1.length()));//extracting longitude
Log.e("Got new loc from FB",Location1);
get_address();
}
};
public void get_address()
{
ReverseGeocodeRequest2 request = new ReverseGeocodeRequest2(new GeoCoordinate(Lat,Lng,0.0));
request.execute(new ResultListener<com.here.android.mpa.search.Location>() {
#Override
public void onCompleted(com.here.android.mpa.search.Location location, ErrorCode errorCode) {
if(errorCode!=ErrorCode.NONE){
Log.e("Error",errocode.getmessage());
}else{
if (location != null) {
Address = location.getAddress().toString();
listItems.add(Address_of_Bus);
}
}
}
});
}
#Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reverse_geocode_layout);
list=(ListView) (findViewById(R.id.listView));
adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,listItems);
list.setAdapter(adapter);
initialize();
}
public void initialize() {
MapEngine mapEngine= MapEngine.getInstance();
mapEngine.init(this, new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(Error error) {
if (error == OnEngineInitListener.Error.NONE) {
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("GOT_NEW_L_M");
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(BUS_COD,intentFilter);
Intent intent=new Intent(Address_Service.this,Database_service.class);
startService(intent);
isMapInitialized = true;
} else {
Log.e("Initialization", "ERROR: Cannot initialize Map Fragment");
}
}
});
}
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(BUS_COD);
this.stopService(new Intent(Address_Service.this,Database_service.class));
super.onDestroy();
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(BUS_COD);
super.onPause();
}
#Override
protected void onResume()
{
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("GOT_NEW_L_M");
LocalBroadcastManager.getInstance(this).registerReceiver(BUS_COD,intentFilter);
super.onResume();
}
}
And this is the Logcat with Error:
E/NativeCrypto: ssl=0x5466b490 cert_verify_callback calling
verifyCertificateChain authMethod=ECDHE_RSA
09-27 17:24:35.352 3554-3770/
E/NETWORK: Request:
https://places.hybrid.api.here.com/places/v1/meta/offline?
app_id=HxZCZftG2X5aQ0Bhlg1W&app_code=TF3wLtVoLtqhmTi1FOcSaw Error: 400 Bad
Request
I am using this on real device operating at API19.I am actually populating listView with addresses received via Reverse Geocoding.
Here is my layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1">
<ListView
android:layout_width="match_parent"
android:layout_height="430dp"
android:layout_marginTop="30dp"
android:layout_gravity="center"
android:id="#+id/listView" />
</LinearLayout>
HERE provides different product which are covering also specific features and capabilities:
Forward geocoding
Reverse geocoding
Multi-reverse geocoding
Batch geocoding
Geocoding autocomplete
Places (Search)
Please have a look here for an overview: https://developer.here.com/products/geocoding-and-search

Android Map loading very slow/not loading at all in started activity until clicking on it

When starting a new map activity the map loads really slow and doesn't start the loading until clicking the screen.
The Layout is the following:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.example.android.momintuition.DirectionsActivity">
<com.google.android.gms.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/mapView"
android:paddingTop="62px"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
map:uiCompass="true"
map:zOrderOnTop="true"
map:uiZoomControls="true"
android:background="#00000000" />
</RelativeLayout>
The new activity looks like this:
public class DirectionsActivity extends AppCompatActivity implements OnMapReadyCallback {
GoogleMap mMap; // Might be null if Google Play services APK is not available.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_directions);
MapView mv = (MapView) findViewById(R.id.mapView);
mv.onCreate(savedInstanceState);
mMap = mv.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
this.map = googleMap;
CameraUpdate cameraUpdate =
CameraUpdateFactory.newLatLngZoom(new LatLng(43.1, -87.9), 10);
map.animateCamera(cameraUpdate);
}
}
I am new to Android. Am I missing something? Thank you!
The problem in this case was that I didn't implement the following methods(even if it was specified in the documentation):
#Override
public void onResume() {
mapView.onResume();
super.onResume();
}
#Override
public void onPause() {
super.onPause();
mapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
It is counterintuitive to me why this methods might affect showing the map but it does fix the problem.
TL;DR These lines made my map load.
itemMap.onResume();
mapView.onEnterAmbient(null);
For people having the same problem:
I'm using maps inside a RecyclerView, and I was having the same problem, so I implemented racula's answer by having an ArrayList of type MapView, and I would add the mapView to the list when it was initialized.
And in the Activity Lifecycle methods I would get the mapViewList from the adapter, and call the appropriate method. And now the map was loading when I resumed the application.
//In the Activity
#Override
protected void onResume() {
super.onResume();
for(MapView mapView : adapter.getMapViewList()){
if (mapView != null){
mapView.onResume();
}
}
}
So finally I tested a few things, and added the "itemMap.onResume();" and the "mapView.onEnterAmbient(null);" methods, and the map started loading and working just fine.
Here's a simple version of my Adapter class
//RecyclerView Adapter and inside it the ViewHolder
class ReminderAdapter extends RecyclerView.Adapter<ReminderAdapter.MyViewHolder> {
private ArrayList<MapView> mapViewList;
#Override
public RecyclerViewAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_layout, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final ReminderAdapter.MyViewHolder holder, int position) {
(...)
holder.initializeMapView(new LatLng(getLat(), getLng()));
}
ArrayList<MapView> getMapViewList(){
return mapViewList;
}
(...)
class MyViewHolder extends RecyclerView.ViewHolder implements OnMapReadyCallback{
#Override
public void onMapReady(GoogleMap googleMap) {
MapsInitializer.initialize(context);
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f));
googleMap.addMarker(new MarkerOptions().position(latLng));
this.googleMap = googleMap;
itemMap.onResume(); //The methods
itemMap.onEnterAmbient(null); // that made my map work
}
void initializeMapView(LatLng latLng){
if(itemMap != null){
this.latLng = latLng;
itemMap.onCreate(bundle);
itemMap.getMapAsync(this);
mapViewList.add(itemMap); // adds the MapView to the list
}
}
}
}

How get JSON data while in splash view in Android

Here I try to make a app.
First it shows a home page.It will display 2 sec.
Here is the code...
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int secondsDelayed = 3;
new Handler().postDelayed(new Runnable() {
public void run() {
startActivity(new Intent(MainActivity.this,SocondActivity.class));
finish();
}
}, secondsDelayed * 1000);
}
}
Then my second activity want to show a splash view until json string download from the rest service.
Here is my code....
public class SocondActivity extends Activity {
private static final String TAG = "SocondActivity";
//please assume my url is OK
private static String url = "my url";
private String jsonStr;
private final int SPLASH_DISPLAY_LENGTH = 5000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
new GetContacts().execute();
Log.d(TAG,jsonStr);
Intent mainIntent = new Intent(SocondActivity.this,
ThirdActivity.class);
SocondActivity.this.startActivity(mainIntent);
SocondActivity.this.finish();
}
}, SPLASH_DISPLAY_LENGTH);
}
private class GetContacts extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected Void doInBackground(Void... arg0) {
//please assume that my Server Handler class is working fine
ServiceHandler sh = new ServiceHandler();
jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);
return null;
}
}
}
Then I got this error......
java.lang.NullPointerException: println needs a message
Because the jsonStr was empty....
Why is that ??
Here is my R.layout.splash_screen
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/loadingPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:scaleType="center"
android:src="#drawable/calendar_50" />
<ProgressBar
android:layout_below="#id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</RelativeLayout>
</LinearLayout>
Can someone please tell me Is this method is correct and what should I change to make this correct ??
You have a race case. You need to do something like this.
Instead of utilizing a handler in onCreate like you are below (which is only serving to create a layer of complexity that isn't functioning like you expect)
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
new GetContacts().execute();
Log.d(TAG,jsonStr);
Intent mainIntent = new Intent(SocondActivity.this,
ThirdActivity.class);
SocondActivity.this.startActivity(mainIntent);
SocondActivity.this.finish();
}
}, SPLASH_DISPLAY_LENGTH);
Just call this in your onCreate()
new GetContacts().execute();
And in your AsyncTask, override the method onPostExecute like so
#Override
public void onPostExecute(Void voidParam){
Log.d(TAG,jsonStr);
Intent mainIntent = new Intent(SocondActivity.this,ThirdActivity.class);
SocondActivity.this.startActivity(mainIntent);
SocondActivity.this.finish();
}
This will tell your app that you want to execute the AsyncTask, and when you are done (and only when you are done) you want to launch your next Activity. This removes the race case as well as the need for a handler/runnable.

Android: When watching a youtube video fullscreen I press back and the Activity finish

I've read all around the way of leaving fullscreen from a YouTube video is by pressing back, but in my Activity it's not working like this but I'd like it to.
I post you the code:
public class MainActivity extends YouTubeFailureRecoveryActivity {
public static String prefix = "https://gdata.youtube.com/feeds/api/playlists/";
public static String sufix = "?v=2&alt=jsonc";
private String myPlayList = "PLZGKlf2ZwY7ua0C2oeUaXQKeLKNGy3mkh";
private VideosListFragment videosFragment;
// The next video to play
private Video actualVideo;
// This is the handler that receives the response when the YouTube read
private Handler responseHandler;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videosFragment = (VideosListFragment) getFragmentManager().findFragmentById(R.id.videosListView);
getUserYouTubeFeed();
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer player, boolean wasRestored) {
if (!wasRestored) {
player.loadVideo(actualVideo.getVideoId());
}
}
#Override
protected YouTubePlayer.Provider getYouTubePlayerProvider() {
return (YouTubePlayerFragment) getFragmentManager().findFragmentById(
R.id.youtube_fragment);
}
public void getUserYouTubeFeed() {
responseHandler = new Handler() {
public void handleMessage(Message msg) {
populateListWithVideos(msg);
};
};
// We start a new AsyncTask that does its work on its own thread
// We pass in a handler that will be called when the task has finished
LoadPlayListElements bgTask = new LoadPlayListElements(responseHandler);
bgTask.execute(myPlayList);
}
/**
* This method retrieves the Library of videos from the task and passes them
* to our ListView
*
* #param msg
*/
private void populateListWithVideos(Message msg) {
Library lib = (Library) msg.getData().get(
LoadPlayListElements.LIBRARY);
VideosAdapter videos = new VideosAdapter(this, lib.getVideos());
videosFragment.setListAdapter(videos);
}
#Override
protected void onStop() {
// Make sure we null our handler when the activity has stopped
responseHandler = null;
super.onStop();
}
public void setVideo(Video _item, boolean _activate) {
actualVideo = _item;
if (_activate){
YouTubePlayerFragment fragment = (YouTubePlayerFragment) getFragmentManager()
.findFragmentById(R.id.youtube_fragment);
if (fragment != null && fragment.isInLayout()) {
fragment.initialize(DeveloperKey.DEVELOPER_KEY, this);
}
}
}
}
and the layout:
<?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="horizontal"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin" >
<fragment
android:id="#+id/videosListView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginTop="?android:attr/actionBarSize"
class="com.vivoenmimundo.sc2hotsepicreplays.ui.phone.fragment.VideosListFragment" >
</fragment>
<fragment
android:name="com.google.android.youtube.player.YouTubePlayerFragment"
android:id="#+id/youtube_fragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:layout_gravity="center_vertical"/>
</LinearLayout>
Any idea? I've tried to not do anything too strange, just copy/paste from YouTube's API examples.
It was, as said before, the correct behaviour - because the player was inside a fragment, I had to catch the back button with:
#Override
public void onBackPressed() {
if (fullScreen){
videoPlayer.setFullscreen(false);
} else{
super.onBackPressed();
}
}
and set my "fullScreen" boolean like this:
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer player, boolean wasRestored) {
if (!wasRestored) {
showPlayer();
videoPlayer = player;
videoPlayer.setOnFullscreenListener(new OnFullscreenListener() {
#Override
public void onFullscreen(boolean _isFullScreen) {
fullScreen = _isFullScreen;
}
});
videoPlayer.loadVideo(actualVideo.getVideoId());
}
}
thanks all!
Step1 : Follow Answer 16 by Nhano
Step2 : add below line in your Menifest YoutubeActivity tag.
android:configChanges="orientation|screenSize"
this solution worked for me..
You could try to detect the back button press and custom define what it does.
// Sets functionality of the hard buttons on the device
#Override
public boolean onKeyUp(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK) {
// Custom define what you want to happen
}
return true;
}

Categories

Resources