I'm trying to hook up Spotify with my Android app. I want to be able to hit a button and have the user be able to start playing from their library on the 4th tab of the TabLayout, and have the ability to swipe back and forth from one tab to another without the music stopping. Here is my current view:
Tabbed View
When I hit start broadcast, I just have it hooked up to SpotifyActivity.java where I've logged in and it starts playing a song. However, I want to have it so that I don't have to invoke a new activity when I want to start accessing my library and playing music so that I can switch between tabs and use the rest of the functionality of the app while the music plays. I recently learned about Services in Android and I was wondering if there was a way to use that. I basically want the flow to be like this:
The 4th tab presents a "start broadcast" button. Once this is hit, you log in to Spotify (or continue if you're already logged in), and a new view (activity?) pops up that gets Spotify and a UI working. Once the music starts, I can switch back to any of the first three tabs and interact with those while the music plays, and then when I go back to the first tab the activity pops up again with the music player UI and Spotify stuff. Here is my code for PageFragment:
public class PageFragment extends Fragment {
public static final String ARG_PAGE = "ARG_PAGE";
private static User thisUser;
private int mPage;
public static PageFragment newInstance(int page, User localUser) {
Bundle args = new Bundle();
thisUser = localUser;
args.putInt(ARG_PAGE, page);
PageFragment fragment = new PageFragment();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPage = getArguments().getInt(ARG_PAGE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = null;
TextView textView;
if (mPage == 1) {
//inflate the fragment_home_page
v = inflater.inflate(R.layout.fragment_home_page, container, false);
//handle profile and username information
}
else if (mPage == 2) {
//inflate the fragment_play_page
v = inflater.inflate(R.layout.fragment_play_page, container, false);
//handle music library information
}
else if(mPage == 3) {
//inflate the fragment_live_page
v = inflater.inflate(R.layout.fragment_live_page, container, false);
//handle live information
}
else if (mPage == 4) {
//inflate the fragment_nowplaying_page
v = inflater.inflate(R.layout.fragment_nowplaying_page, container, false);
Button startBroadcast = (Button) v.findViewById(R.id.start_broadcast);
//Links to SpotifyActivity
startBroadcast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(), SpotifyActivity.class);
startActivity(intent);
}
});
}
else {
Log.e("PageFragment ", "Unknown error occurred");
}
return v;
}
}
Here is my code for SpotifyActivity:
public class SpotifyActivity extends AppCompatActivity implements SpotifyPlayer.NotificationCallback, ConnectionStateCallback {
//CLIENT_ID=
//Callback
// Request code that will be used to verify if the result comes from correct activity
// Can be any integer
private static final int REQUEST_CODE = 1337;
private Player mPlayer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spotify);
AuthenticationRequest.Builder builder = new AuthenticationRequest.Builder(CLIENT_ID,
AuthenticationResponse.Type.TOKEN,
REDIRECT_URI);
builder.setScopes(new String[]{"user-read-private", "streaming"});
AuthenticationRequest request = builder.build();
AuthenticationClient.openLoginActivity(this, REQUEST_CODE, request);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
//After the user logs in to authorize the application's scopes
// Check if result comes from the correct activity
if (requestCode == REQUEST_CODE) {
AuthenticationResponse response = AuthenticationClient.getResponse(resultCode, intent);
if (response.getType() == AuthenticationResponse.Type.TOKEN) {
Config playerConfig = new Config(this, response.getAccessToken(), CLIENT_ID);
Spotify.getPlayer(playerConfig, this, new SpotifyPlayer.InitializationObserver() {
#Override
public void onInitialized(SpotifyPlayer spotifyPlayer) {
mPlayer = spotifyPlayer;
mPlayer.addConnectionStateCallback(SpotifyActivity.this);
mPlayer.addNotificationCallback(SpotifyActivity.this);
}
#Override
public void onError(Throwable throwable) {
Log.e("MainActivity", "Could not initialize player: " + throwable.getMessage());
}
});
}
}
}
#Override
protected void onDestroy() {
Spotify.destroyPlayer(this);
super.onDestroy();
}
#Override
public void onPlaybackEvent(PlayerEvent playerEvent) {
Log.d("MainActivity", "Playback event received: " + playerEvent.name());
switch (playerEvent) {
// Handle event type as necessary
default:
break;
}
}
#Override
public void onPlaybackError(Error error) {
Log.d("MainActivity", "Playback error received: " + error.name());
switch (error) {
// Handle error type as necessary
default:
break;
}
}
#Override
public void onLoggedIn() {
Log.d("MainActivity", "User logged in");
mPlayer.playUri(null, "spotify:track:2TpxZ7JUBn3uw46aR7qd6V", 0, 0);
}
#Override
public void onLoggedOut() {
Log.d("MainActivity", "User logged out");
}
#Override
public void onLoginFailed(Error error) {
Log.d("MainActivity", "Login failed");
}
#Override
public void onTemporaryError() {
Log.d("MainActivity", "Temporary error occurred");
}
#Override
public void onConnectionMessage(String s) {
Log.d("MainActivity", "Received connection message: " + s);
}
}
Is there a way to set up Spotify's music player without losing it when I switch to other tabs?
Related
So I have been trying to change the TTS language inside a fragment but it isn't working but same code works fine inside MainActivity. I don't understand why. I have checked other solutions but none worked for me. I have tried different solution , solution but even this isn't working.
public class HomeFragment extends Fragment implements TextToSpeech.OnInitListener{
private static final int TTS_DATA_CHECK = 1;
private TextToSpeech engine;
private SettingsViewModel settingsViewModel;
private EditText textMsg;
private Button button;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
engine = new TextToSpeech(getContext(),this);
settingsViewModel = new ViewModelProvider(getActivity()).get(SettingsViewModel.class);
return inflater.inflate(R.layout.fragment_home, container, false);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
textMsg = view.findViewById(R.id.textMsg);
button = view.findViewById(R.id.playButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
engine.speak(textMsg.getText().toString(), TextToSpeech.QUEUE_FLUSH, null,null);
}
});
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
settingsViewModel.getLanguage().observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(String s) {
Log.d("LANGUAGE_SELECTED",s);
switch (s){
case "ENGLISH":
engine.setLanguage(Locale.ENGLISH);
break;
case "FRENCH":
engine.setLanguage(Locale.FRENCH);
break;
}
}
});
}
#Override
public void onInit(int status) {
if(status==TextToSpeech.SUCCESS){
int result = engine.setLanguage(Locale.ENGLISH);
if(result == TextToSpeech.LANG_MISSING_DATA
|| result== TextToSpeech.LANG_NOT_SUPPORTED){
Toast.makeText(getContext(),"Not supported",Toast.LENGTH_LONG).show();
}
}else{
Toast.makeText(getContext(),"TTS is missing",Toast.LENGTH_LONG).show();
}
}
}
First you need to initialize TTS in main activity like this -
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {
private static final int TTS_DATA_CHECK = 101;
static TextToSpeech engine;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
engine = new TextToSpeech(this,this);
}
#Override
public final void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 101)
{
if (resultCode != TextToSpeech.Engine.CHECK_VOICE_DATA_PASS)
{
final Intent tnt = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(tnt);
}
}
}
#Override
public void onInit(int status) {
if(status==TextToSpeech.SUCCESS){
if(TTS_DATA_CHECK == TextToSpeech.LANG_MISSING_DATA
|| TTS_DATA_CHECK== TextToSpeech.LANG_NOT_SUPPORTED){
Toast.makeText(this,"Not supported",Toast.LENGTH_LONG).show();
}
}
}
static public TextToSpeech getInstance() {
return engine;
}
}
Then you have to call the TTS instance inside Fragment like this. Note that, MainActivity is the parent activity of the given Fragment.
Now replace the following code in your Fragment with this code -
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d("VMA","OnActivityCreated");
settingsViewModel.getLanguage().observe(getViewLifecycleOwner(), new Observer<String>() {
#Override
public void onChanged(String s) {
Log.d("VMA","LANGUAGE_SELECTED " + s);
switch (s){
case "FRENCH":
MainActivity.getInstance().setLanguage(Locale.FRENCH);
break;
case "ENGLISH":
MainActivity.getInstance().setLanguage(Locale.ENGLISH);
break;
}
}
});
}
Also, you can remove the rest of the TTS code from Fragment. You don't that anymore.
I have written the following code to set the String of fragment. By using startActivityForResult I am getting the value and set the to fragment string i.e (firstString, secondString)
But the problem is that whenever I call startActivityForResult the fragment is recreated and the previous data is lost. For example when I set secondString than the value of firstString is lost.
I have referred to few answers to save and restore the fragment data, but unable to do so.
boolean isEditing = true;
LinearLayout first_layout, second_layout;
TextView first_textview, second_textview;
String firstString, secondString;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_profile);
if(savedInstanceState!=null)
{
if(savedInstanceState.getBoolean("isEditing",false))
{
Log.e("onSaveInstanceState","Restored");
isEditing=true;
firstString = savedInstanceState.getString(firstString);
secondString = savedInstanceState.getString(secondString);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.mf_postload, container, false);
// Linearlayout
first_layout = (LinearLayout) view.findViewById(R.id.payment_layout_MF_PostLoad);
second_layout = (LinearLayout) view.findViewById(R.id.remark_layout_MF_PostLoad);
// TextView
first_textview = (TextView) view.findViewById(R.id.payment_MF_PostLoad);
second_textview = (TextView) view.findViewById(R.id.remark_MF_PostLoad);
first_textview.setText(firstString);
second_textview.setText(firstString);
// Listner
first_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity().getApplicationContext(), Remark.class);
Integer requestCode = 1;
intent.putExtra("requestCode", requestCode);
startActivityForResult(intent, requestCode);
}
});
second_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity().getApplicationContext(), Remark.class);
Integer requestCode = 2;
intent.putExtra("requestCode", requestCode);
startActivityForResult(intent, requestCode);
}
});
return view;
}
#Override
public void onSaveInstanceState(Bundle bundle)
{
super.onSaveInstanceState(bundle);
Log.e("onSaveInstanceState","Called");
try
{
if(isEditing)
{
bundle.putBoolean("isEditing",true);
bundle.putString("firstString",firstString);
bundle.putString("secondString",secondString);
Log.e("onSaveInstanceState","Called and Saved");
}
else
{
bundle.putBoolean("isEditing",false);
Log.e("onSaveInstanceState","Called and not Saved");
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
// Call Back method to get the Message form other Activity
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// First
if (requestCode == 1) {
if (resultCode == Activity.RESULT_OK && data != null) {
firstString = data.getStringExtra("remark_string");
first_textview.setText(firstString);
}
}
// Second
if (requestCode == 2) {
if (resultCode == Activity.RESULT_OK && data != null) {
secondString = data.getStringExtra("remark_string");
second_textview.setText(secondString);
}
}
}
Here is the overriding of onSaveInstance
//Like you see here am using a boolean to determine if i need to save the variable of not
//because if i am finishing the activity normally and its not the case where system kills it
//so i dont need to save these and if case that this boolean is true than the system is
//killing my activity and i need to save the values
#Override
public void onSaveInstanceState(Bundle bundle)
{
super.onSaveInstanceState(bundle);
Log.e("onSaveInstanceState","Called");
try
{
if(isEditing)
{
bundle.putBoolean("isEditing",true);
bundle.putString("photoFile", photoFile.getAbsoluteFile()+"");
bundle.putString("birthday",birthdayText.getText().toString());
bundle.putString("phone",phoneText.getText().toString());
bundle.putString("gender",genderText.getText().toString());
bundle.putString("martial",martialText.getText().toString());
bundle.putString("email",emailText.getText().toString());
bundle.putString("first",editFirstName.getText().toString());
bundle.putString("last",editLastName.getText().toString());
Log.e("onSaveInstanceState","Called and Saved");
}
else
{
bundle.putBoolean("isEditing",false);
Log.e("onSaveInstanceState","Called and not Saved");
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
Here is the overriding of onCreate
//In onCreate am checking if i need to restore these values or not according
//to what i saved and in this way its like my activity never got killed
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
if(savedInstanceState!=null)
{
if(savedInstanceState.getBoolean("isEditing",false))
{
Log.e("onSaveInstanceState","Restored");
isEditing=true;
photoFile =new File(savedInstanceState.getString("photoFile"),"") ;
birthdayText.setText(savedInstanceState.getString("birthday","1/1/1980"));
phoneText.setText(savedInstanceState.getString("phone",""));
genderText.setText(savedInstanceState.getString("gender","Please specify gender"));
martialText.setText(savedInstanceState.getString("martial","Please specify marital"));
emailText.setText(savedInstanceState.getString("email",""));
editFirstName.setText(savedInstanceState.getString("first",""));
editLastName.setText(savedInstanceState.getString("last",""));
}
}
}
After some debugging I have solved, Thanks Haider.
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
Log.e("onSaveInstanceState", "Called");
bundle.putString("firstString", firstString);
bundle.putString("secondString", secondString);
Log.e("onSaveInstanceState", "Called and Saved" + firstString + " " + secondString);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("onSaveInstanceState", "Restored Called");
if (savedInstanceState != null) {
firstString = savedInstanceState.getString("firstString");
secondString = savedInstanceState.getString("secondString");
Log.e("onSaveInstanceState", "Restored" + firstString + " " + secondString);
}
}
I am using Firebase for my apps back end and I am retrieving my data as excepted. After I retrieve my data, I am posting it by using otto bus and the code can be seen below.
#Subscribe
public void loadBrothers(ServiceCalls.SearchBrothersRequest request) {
final ServiceCalls.SearchBrothersResponse response = new ServiceCalls.SearchBrothersResponse();
response.Brothers = new ArrayList<>();
Firebase reference = new Firebase("my data's url here");
reference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
int index = 0;
for (DataSnapshot brotherSnapchat : dataSnapshot.getChildren()) {
BrotherFireBase bro = brotherSnapchat.getValue(BrotherFireBase.class);
Log.i(LOG_TAG, bro.getName());
Log.i(LOG_TAG, bro.getWhy());
Log.i(LOG_TAG, bro.getPicture());
Log.i(LOG_TAG, bro.getMajor());
Log.i(LOG_TAG, bro.getCross());
Log.i(LOG_TAG, bro.getFact());
Brother brother = new Brother(
index,
bro.getName(),
bro.getWhy(),
bro.getPicture(),
bro.getMajor(),
bro.getCross(),
bro.getFact());
response.Brothers.add(brother);
index++;
}
bus.post(response);
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Once the data is in my RecyclerView, I am to click an item and it's respective activity is to pop up in a custom activity dialog. However, since the activity is a dialog, you can see the RecyclerView reloading in the background. This does not happen when I do not retrieve the data from the internet. After a few clicks around, the app crashes due to an out of memory exception. Is there something I am missing?
Here is the activity where the recyclerView is found:
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_meet_a_brother, container, false);
adapter = new BrotherRecycleAdapter((BaseActivity) getActivity(),this);
brothers = adapter.getBrothers();
recyclerView =(RecyclerView) view.findViewById(R.id.fragment_meet_a_brother_recycleView);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),3));
setUpAdapter();
bus.post(new ServiceCalls.SearchBrothersRequest("Hello"));
return view;
}
private void setUpAdapter(){
if(isAdded()){
recyclerView.setAdapter(adapter);
}
}
#Subscribe
public void onBrosLoaded(final ServiceCalls.SearchBrothersResponse response){
int oldBrotherLength = brothers.size();
brothers.clear();
adapter.notifyItemRangeRemoved(0, oldBrotherLength);
brothers.addAll(response.Brothers);
//Delete for Debug method...
adapter.notifyItemRangeChanged(0,brothers.size());
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
#Override
public void onBrotherClicked(Brother brother) {
Intent intent = BrotherPagerActivity.newIntent(getActivity(),brother);
Log.i(LOG_TAG,brother.getBrotherName() + " was Clicked");
startActivity(intent);
}
Just in case, here is also the activity that is started when a list item is clicked, it is a viewPager activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_brother_pager);
brothers = new ArrayList<>();
bus.post(new ServiceCalls.SearchBrothersRequest("Hello"));
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager = (ViewPager) findViewById(R.id.activity_brother_viewPager);
viewPager.setAdapter(new FragmentStatePagerAdapter(fragmentManager) {
#Override
public Fragment getItem(int position) {
Brother brother = brothers.get(position);
return BrotherDetailsFragment.newInstance(brother);
}
#Override
public int getCount() {
return brothers.size();
}
});
}
#Subscribe
public void onBrosLoad(final ServiceCalls.SearchBrothersResponse response){
brothers.clear();
brothers.addAll(response.Brothers);
viewPager.getAdapter().notifyDataSetChanged();
Brother brother = getIntent().getParcelableExtra(BROTHER_EXTRA_INFO);
int brotherId = brother.getBrotherId();
for(int i=0;i<brothers.size();i++){
if(brothers.get(i).getBrotherId() == brotherId){
viewPager.setCurrentItem(i);
break;
}
}
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
public static Intent newIntent(Context context, Brother brother){
Intent intent = new Intent(context,BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO,brother);
return intent;
}
Any help is greatly appreciated thank you!
in public void onBrotherClicked(Brother brother) where RecyclerView resides, you call:
Intent intent = BrotherPagerActivity.newIntent(getActivity(),brother);
which will call
Intent intent = new Intent(context,BrotherPagerActivity.class);`
in newIntent of your viewPager activity.
This could be a recursive call.
try adding:
public static Intent newIntent(Context context, Brother brother){
Intent intent = new Intent(context,BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO,brother);
return intent;
}
in Activity where your RecyclerView resides. And call your ViewPage activity there.
-- UPDATE --
Call your viewpager activity (which is used to show Brother data) with the following code:
private void showBrotherData(Brother brother){
Intent intent = new Intent(this, BrotherPagerActivity.class);
intent.putExtra(BROTHER_EXTRA_INFO, brother);
this.startActivity(intent);
}
I found the answer! I changed my recyclerView to only updated if the size of the array was zero.
#Subscribe
public void onBrosLoaded(final ServiceCalls.SearchBrothersResponse response){
int oldBrotherLength = brothers.size();
Log.i(LOG_TAG, "Brother lists old size" + Integer.toString(oldBrotherLength));
if(oldBrotherLength ==0){
brothers.clear();
adapter.notifyItemRangeRemoved(0, oldBrotherLength);
brothers.addAll(response.Brothers);
//Delete for Debug method...
adapter.notifyItemRangeChanged(0,brothers.size());
} else{
return;
}
Log.i(LOG_TAG, Integer.toString(brothers.size()));
}
I don't know how good this solution is in terms of cleaness but it works for me. I hope this helps someone.
I have a SignupActivity which will go through several fragments as users go through a signup process. On the last fragment, I'm calling
getActivity().setResult(Activity.RESULT_OK)
since SingupActivity intent was started for result. Some users are crashing at this point, because getActivity() is producing a NPE. I'm not able to figure out what is causing this. Screen rotation is disabled, so there is no reason that I know of for the fragment to detach from the Activity.
Any insight as to what may be causing this, and how I can resolve it?
public class SignupConfirmationFragment extends Fragment {
public static final String TAG = SignupConfirmationFragment.class.getSimpleName();
private User mNewUser;
private myAppClient mmyAppClient;
private Animation rotateAnimation;
private ImageView avatar;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNewUser = ((SignUpActivity) getActivity()).getNewUser();
mmyAppClient = ((SignUpActivity) getActivity()).getmyAppClient();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_signup_confirmation, null);
((TextView) v.findViewById(R.id.username_textView)).setText(((SignUpActivity) getActivity()).getNewUser().getName());
avatar = (ImageView) v.findViewById(R.id.avatar);
if (mNewUser.getAvatarImage() != null) {
avatar.setImageBitmap(mNewUser.getAvatarImage());
}
rotateAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.progress_rotate);
v.findViewById(R.id.progress_loading).startAnimation(rotateAnimation);
if (mNewUser.getAvatarImage() != null) {
startAvatarUpload();
} else if (mNewUser.getNewsletter()) {
setNewsletterStatus();
} else {
pauseForOneSecond();
}
return v;
}
private void startAvatarUpload() {
mmyAppClient.uploadUserAvatar(mNewUser.getAvatarImage(), new FutureCallback<JsonObject>() {
#Override
public void onCompleted(Exception e, JsonObject result) {
if (mNewUser.getNewsletter()) {
setNewsletterStatus();
} else {
updateFragment();
}
}
},
null,
null);
}
private void setNewsletterStatus() {
mmyAppClient.setNewsletter(mNewUser.getEmail(), mNewUser.getFirstName(), mNewUser.getLastName(), new FutureCallback<String>() {
#Override
public void onCompleted(Exception e, String result) {
//Log.d(TAG, "Result: " + result);
updateFragment();
}
});
}
private void pauseForOneSecond() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
updateFragment();
}
}, 1000);
}
private void updateFragment() {
rotateAnimation.cancel();
if (isAdded()) {
getActivity().setResult(Activity.RESULT_OK);
AnalyticsManager.logUIEvent("sign up completed");
getActivity().finish();
} else {
AnalyticsManager.logUIEvent("sign up failed");
}
}
}
According to Fragment lifecycle in Android OS, you cannot get the Activity associated with the fragment in the onCreateView, because the Activity with which the Fragment is associated will not be created at that stage.
See the figure below:
Also, refer to this link, http://developer.android.com/guide/components/fragments.html
As you can see the Activity is created in onActivityCreated which is after onCreateView, hence you'll get null if you try to call the Activity in the onCreateView. Try to call it in onActivityCreated or in onStart that should solve your problem.
I hope this helps.
EDIT-----: So I did manage to make it show me users and be able to select some, and to send me back the selected users to my app but there is a slight problem. "Uri.parse("picker://friend");" doesn't give me the list of my friends, but only a list of the friends that I have and have my app installed.
I followed this example: https://developers.facebook.com/docs/android/scrumptious/show-friends but I am trying to modify it, so basically I took out the selectionActivity and Fragment. So I have from my activity a button that calls the PickerActivity which contains FriendPickerFragment. I can select my friends from there, but back in my activities onActivityResult i get back "data" as null.
I have an Application class in my app, where i save the FB session, and also have the login function in there.
In my MainActivity onCreate I have this:
MyApp.getInstance().facebookLogin(PSAddFriendsActivity.this, new CrudStateCallback() {
#Override
public void onResponse(final String string) {
Log.i("", "session : session is opened? : " + MyApp.getInstance().fbSession.getAccessToken());
}
});
After having logged in, I instantiate a list with the current friends I have in my app, and the first position of this list is a FB button:
#Override
protected void onListItemClick(ListView l, View v, int position, long id){
super.onListItemClick(l, v, position, id);
if(position == 0){
startPickerActivity(PSPickerActivity.FRIEND_PICKER, 0);
}else if(position ==1){
//TODO: OPEN CONTACTS PAGE TO ADD FRIENDS
}
}
This is my onACtivityResult and the "startPickerActivity" from this class:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
Log.i("","--------------data is : " + data);
Log.i("","--------------resultCode is : " + resultCode);
Log.i("","--------------requestCode is : " + requestCode);
}
public void startPickerActivity(Uri data, int requestCode) {
Intent intent = new Intent();
intent.setData(data);
intent.setClass(PSAddFriendsActivity.this, PickerActivity.class);
startActivityForResult(intent, requestCode);
}
This is the PickerActivity, how I took it from FB:
public class PickerActivity extends FragmentActivity{
private FriendPickerFragment friendPickerFragment;
public static final Uri FRIEND_PICKER = Uri.parse("picker://friend");
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pickers);
Bundle args = getIntent().getExtras();
FragmentManager manager = getSupportFragmentManager();
Fragment fragmentToShow = null;
Uri intentUri = getIntent().getData();
if (FRIEND_PICKER.equals(intentUri)) {
if (savedInstanceState == null) {
friendPickerFragment = new FriendPickerFragment(args);
} else {
friendPickerFragment =
(FriendPickerFragment) manager.findFragmentById(R.id.picker_fragment);
}
// Set the listener to handle errors
friendPickerFragment.setOnErrorListener(new PickerFragment.OnErrorListener() {
#Override
public void onError(PickerFragment<?> fragment,
FacebookException error) {
PSPickerActivity.this.onError(error);
}
});
// Set the listener to handle button clicks
friendPickerFragment.setOnDoneButtonClickedListener(
new PickerFragment.OnDoneButtonClickedListener() {
#Override
public void onDoneButtonClicked(PickerFragment<?> fragment) {
finishActivity();
}
});
fragmentToShow = friendPickerFragment;
} else {
// Nothing to do, finish
setResult(RESULT_CANCELED);
finish();
return;
}
manager.beginTransaction()
.replace(R.id.picker_fragment, fragmentToShow)
.commit();
}
private void onError(Exception error) {
onError(error.getLocalizedMessage(), false);
}
private void onError(String error, final boolean finishActivity) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.error_dialog_title).
setMessage(error).
setPositiveButton(R.string.error_dialog_button_text,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if (finishActivity) {
finishActivity();
}
}
});
builder.show();
}
private void finishActivity() {
setResult(RESULT_OK, null);
finish();
}
#Override
protected void onStart() {
super.onStart();
if (FRIEND_PICKER.equals(getIntent().getData())) {
try {
friendPickerFragment.loadData(false);
} catch (Exception ex) {
onError(ex);
}
}
}
#Override
protected void onResume() {
Log.i("", "location test onResume");
super.onResume();
MyApp.getInstance().pref.setIsBackground(this, false);
MyApp.getInstance().startLocationClient();
}
#Override
protected void onPause() {
Log.i("", "location test onPause");
super.onPause();
MyApp.getInstance().pref.setIsBackground(this, true);
}
}
Now I looked over this fragment, do not know if I have to add something or save something from the fragment on "onDoneButtonClicked"? or what exactly, because my main activity does return null as data..
forgot to call this in the finishActivty:
if (FRIEND_PICKER.equals(getIntent().getData())) {
if (friendPickerFragment != null) {
MyApp.getInstance().setSelectedUsers(friendPickerFragment.getSelection());
}
}
Now I can get from my Application the list of selected users.
About my edit, after this i found out that with Graph2.0 you cannot get a list of your whole friendlist. You can only get back the info of friends that also liked the app. It is possible to invite friends to like an app but only if you set it as a Game from the FB developers page