guys i know that passing realm object to another activity is really hard. Anyway i try to do this by service so:
1) MainActivity to job, make realm object and put it safe by use setter in service,
2) service is just like a holder or connection bridge between two activities,
3) in second activity a try to get realm object from service,
Of course i have nullPointerException in get line.
I know that somebody say: hello sqlite is better but i try to understand how realm lib and service can cooperate.
Thats my codes:
Main:
public class MainActivity extends AppCompatActivity {
List<String> shopsNames;
ArrayList<RowModel> rowModels;
protected RealmService mService;
protected boolean mBound = false;
public Realm mRealm;
#BindView(R.id.toolbar_layout)
CollapsingToolbarLayout toolbarLayout;
#BindView(R.id.app_bar)
AppBarLayout appBar;
private ShopsAdapter adapter;
#BindView(R.id.recycler_view)
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
ButterKnife.bind(this);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ConnectionDetector connectionDetector = new ConnectionDetector(this);
if (!connectionDetector.isConnection()){
finish();
}
rowModels = new ArrayList<>();
shopsNames = new ArrayList<>();
mRealm = Realm.getInstance(this);
initCollapsingToolbar();
adapter = new ShopsAdapter(MainActivity.this, shopsNames);
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getApplicationContext(), 2);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
Intent intent = new Intent(getApplicationContext(), RealmService.class);
bindService(intent, mConnection, this.BIND_AUTO_CREATE);
AsyncTaskRetro asyncTaskRetro = new AsyncTaskRetro();
asyncTaskRetro.execute();
}
private class AsyncTaskRetro extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
PlacesAPI.Factory.getInstance().getPlaces().enqueue(new Callback<Places>() {
#Override
public void onResponse(Call<Places> call, Response<Places> response) {
for (int i = 0; i < response.body().getPosts().size(); i++) {
RowModel rowModel = new RowModel(response.body().getPosts().get(i).getNazwa(),
Double.parseDouble(response.body().getPosts().get(i).getSzer()),
Double.parseDouble(response.body().getPosts().get(i).getDlug()));
rowModels.add(rowModel);
}
String oldName;
oldName = rowModels.get(0).getName();
shopsNames.add(rowModels.get(0).getName());
mRealm.beginTransaction();
RowModel rowModelRealm = mRealm.createObject(RowModel.class);
mRealm.commitTransaction();
for (int j = 0; j < rowModels.size(); j++) {
mRealm.beginTransaction();
rowModelRealm.setName(rowModels.get(j).getName());
rowModelRealm.setLattitude(rowModels.get(j).getLattitude());
rowModelRealm.setLongitude(rowModels.get(j).getLongitude());
mRealm.commitTransaction();
if (rowModels.get(j).getName().equals(oldName)) {
continue;
}
oldName = rowModels.get(j).getName();
shopsNames.add(rowModels.get(j).getName());
}
mService.setRealm(mRealm);
RealmResults<RowModel> rw = mRealm.where(RowModel.class).findAll();
Log.d("sdfsd", Integer.toString(rw.size()));
//sortowanie listy z nazwami sklepow
Collections.sort(shopsNames);
adapter = new ShopsAdapter(MainActivity.this, shopsNames);
recyclerView.setAdapter(adapter);
try {
Glide.with(getApplicationContext()).load("http://www.wp.pl/shop-local-logo.png").
into((ImageView) findViewById(R.id.backdrop));
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<Places> call, Throwable t) {
}
});
return null;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
RealmService.LocalBinder binder = (RealmService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
private void initCollapsingToolbar() {
final CollapsingToolbarLayout collapsingToolbar =
(CollapsingToolbarLayout) findViewById(R.id.toolbar_layout);
collapsingToolbar.setTitle(" ");
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.app_bar);
appBarLayout.setExpanded(true);
// hiding & showing the title when toolbar expanded & collapsed
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
boolean isShow = false;
int scrollRange = -1;
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
if (scrollRange == -1) {
scrollRange = appBarLayout.getTotalScrollRange();
}
if (scrollRange + verticalOffset == 0) {
collapsingToolbar.setTitle(getString(R.string.app_name));
isShow = true;
} else if (isShow) {
collapsingToolbar.setTitle(" ");
isShow = false;
}
}
});
}
}
My second class:
public class Test extends AppCompatActivity {
protected RealmService mService;
protected boolean mBound = false;
public Realm mRealm;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.text);
Intent intent = new Intent(this, RealmService.class);
bindService(intent, mConnection, this.BIND_AUTO_CREATE);
mRealm = mService.getRealm();
mRealm.beginTransaction();
RealmResults<RowModel> rowModels = mRealm.where(RowModel.class).findAll();
if(!rowModels.isEmpty()){
String s;
for (int i = 0; i < rowModels.size(); i++) {
s = rowModels.get(i).getName() + " " + rowModels.get(i).getLattitude()
+ " " + rowModels.get(i).getLongitude();
Log.d("S: ", s);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
RealmService.LocalBinder binder = (RealmService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
and service:
public class RealmService extends Service {
public Realm getRealm() {
return realm;
}
public void setRealm(Realm realm) {
this.realm = realm;
}
public Realm realm;
private final IBinder iBinder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return iBinder;
}
public class LocalBinder extends Binder {
RealmService getService() {
return RealmService.this;
}
}
}
Related
Hello i had implement code of Music service i want to create demo of music player but it not start automatically from onCreate() i want to start player automatically when activity open. here below i put code for Activity and service please help me any help will be appreciate.
public class MainActivity extends Activity {
private ArrayList<Song> songList;
private ListView songView;
private MusicService musicSrv;
private Intent playIntent;
private boolean musicBound = false;
private MusicController controller;
private boolean paused = false, playbackPaused = false;
private ServiceConnection musicConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
musicSrv = binder.getService();
musicSrv.setList(songList);
musicBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
songView = (ListView) findViewById(R.id.song_list);
songList = new ArrayList<Song>();
getSongList();
Collections.sort(songList, new Comparator<Song>() {
public int compare(Song a, Song b) {
return a.getTitle().compareTo(b.getTitle());
}
});
SongAdapter songAdt = new SongAdapter(this, songList);
songView.setAdapter(songAdt);
songPicked();
}
#Override
protected void onStart() {
super.onStart();
if (playIntent == null) {
playIntent = new Intent(this, MusicService.class);
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
}
}
public void songPicked() {
musicSrv.setSong(0);
musicSrv.playSong();
}
#Override
protected void onPause() {
super.onPause();
paused = true;
}
#Override
protected void onResume() {
super.onResume();
if (paused) {
paused = false;
}
}
#Override
protected void onStop() {
controller.hide();
super.onStop();
}
#Override
protected void onDestroy() {
stopService(playIntent);
musicSrv = null;
super.onDestroy();
}
}
Here below i put service code also.
public class MusicService extends Service implements
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
private final IBinder musicBind = new MusicBinder();
private MediaPlayer player;
private ArrayList<Song> songs;
private int songPosn;
private String songTitle = "";
private Random rand;
public void onCreate() {
super.onCreate();
songPosn = 0;
rand = new Random();
player = new MediaPlayer();
initMusicPlayer();
}
public void initMusicPlayer() {
player.setWakeMode(getApplicationContext(),
PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
public void setList(ArrayList<Song> theSongs) {
songs = theSongs;
}
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
#Override
public boolean onUnbind(Intent intent) {
player.stop();
player.release();
return false;
}
public void playSong() {
player.reset();
Song playSong = songs.get(0);
songTitle = playSong.getTitle();
long currSong = playSong.getID();
Uri trackUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
currSong);
try {
player.setDataSource(getApplicationContext(), trackUri);
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
try {
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setSong(int songIndex) {
songPosn = songIndex;
}
#Override
public void onCompletion(MediaPlayer mp) {
if (player.getCurrentPosition() > 0) {
mp.reset();
}
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
playSong();
}
#Override
public void onDestroy() {
stopForeground(true);
}
public class MusicBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
}
I just want to start player when application start automatically without any click. but it display unfortunately stopped with null object reference of Media player. I had never work with service also with music player.
Null pointer exception throws because music service object returns null so.
Finally solved as per #vladMatvienko answer thanks for your support man.
private ServiceConnection musicConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder) service;
musicSrv = binder.getService();
musicSrv.setList(songList);
musicBound = true;
songPicked();
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
};
I'm currently getting a ClassCastException in my android app caused by "activity cannot be cast to interface".
Here is my code:
Logcat says the Exception is thrown in the onAttach part in MovieGridFragment on the line "this.clickListener = (clickInterfaceHelper) context;".
My Interface:
public interface clickInterfaceHelper {
void clickOnItem(int id);
void favoriteMovieItem(int movieId); }
The Fragment Class:
public class MovieGridFragment extends Fragment {
public clickInterfaceHelper clickListener;
private int index;
private GridView movieGridView;
public List<movieData> movieDataList = new ArrayList<>();
public MovieGridFragment() {} //empty constructor
#Override
public void onAttach(Context context) {
this.clickListener = (clickInterfaceHelper) context;
super.onAttach(context);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
if(savedInstanceState != null) {
if (!movieDataList.isEmpty()) {
movieDataList = Arrays.asList((movieData[]) savedInstanceState.getSerializable("OLDMOVIEDATA"));
}
}
super.onCreate(savedInstanceState);
}
The MainActivity:
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
View rootView = inflater.inflate(R.layout.movie_display_fragment, container, false);
movieGridView = (GridView) rootView.findViewById(R.id.gv_movie_display);
movieAdapter adapter = new movieAdapter(getActivity(),movieDataList);
adapter.notifyDataSetChanged();
movieGridView.setAdapter(adapter);
movieGridView.setSelection(index);
movieGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(clickListener != null)
clickListener.clickOnItem(position);
}
});
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
index = movieGridView.getFirstVisiblePosition();
outState.putSerializable("OLDMOVIEDATA",movieData.movieDataArray);
super.onSaveInstanceState(outState);
}}
and mainactivity:
public class MainActivity extends AppCompatActivity implements clickInterfaceHelper {
public static String sorterString = null;
public static String urlBase = "https://api.themoviedb.org/3/movie/";
public static String urlFinal = null;
RequestQueue requestQueue;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.activity_container, new MovieGridFragment())
.commit();
movieData.movieDataPosition = 0;
}
if(savedInstanceState != null) {
sorterString = savedInstanceState.getString("SORTER");
}
if(savedInstanceState == null)
movieData.movieDataPosition = 0;
if(sorterString==null)
sorterString="popular?";
if(sorterString!="favorite" && sorterString!=null) {
if(networkChecker.isNetworkAvailableChecker(this)) {
movieRequest();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu_act, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == R.id.m_popularity_action) {
if(sorterString != "popular?") {
sorterString = "popular?";
if(networkChecker.isNetworkAvailableChecker(this))
movieRequest();
}
return true;
}
if(id == R.id.m_action_voter) {
if(sorterString != "top_rated?") {
sorterString = "top_rated?";
if(networkChecker.isNetworkAvailableChecker(this))
movieRequest();
}
return true;
}
if(id == R.id.m_favorite_btn) {
if(sorterString != "favorite") {
SQLiteOpenHelper helper = new movieDataDbHelper(this);
SQLiteDatabase database = helper.getReadableDatabase();
Cursor cursor= database.query(movieDataContract.contractEntry.TABLE_NAME,
new String[] {
movieDataContract.contractEntry.ID,
movieDataContract.contractEntry.IMG_PATH},null,null,null,null,null);
if(cursor.getCount() == 0) {
Toast.makeText(this, "there are no favorite movies yet!",Toast.LENGTH_SHORT).show();
} else {
sorterString = "favorite";
showFavoriteFragment();
}
database.close();
helper.close();
cursor.close();
}
return true;
}
return super.onOptionsItemSelected(item);
}
public void showFavoriteFragment() {
favoriteMoviesDetailsFragment fragment = new favoriteMoviesDetailsFragment();
try {
getFragmentManager().beginTransaction().replace(R.id.activity_container,fragment).commit();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
outState.putString("SORTER", sorterString);
outState.putInt("POSITION",movieData.movieDataPosition);
super.onSaveInstanceState(outState, outPersistentState);
}
public void movieRequest() {
urlFinal = urlBase + sorterString + movieData.apiKey;
urlFinal.trim();
requestQueue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, urlFinal, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray array = response.getJSONArray("results");
movieData.movieDataArray = new movieData[array.length()];
for (int i = 0; i < array.length(); i++) {
movieData movie = new movieData();
JSONObject jsonObject = array.getJSONObject(i);
//movie.setPosition(i);
movie.setMovieId(jsonObject.getString("id"));
movie.setMovieImagePath(jsonObject.getString("poster_path"));
movie.setMovieTitle(jsonObject.getString("original_title"));
movie.setMoviePlot(jsonObject.getString("overview"));
movie.setMovieVoting(jsonObject.getString("vote_average"));
movie.setMovieReleaseDate(jsonObject.getString("release_date"));
movieData.movieDataArray[i] = movie;
}
MovieGridFragment gridFragment = new MovieGridFragment();
gridFragment.movieDataList = Arrays.asList(movieData.movieDataArray); //hier wird datalist eigentlich zugewiesen
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.activity_container, gridFragment);
try {
transaction.commitAllowingStateLoss();
} catch (Exception e) {
e.printStackTrace();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("volley", String.valueOf(error));
}
}
);
requestQueue.add(jsonObjectRequest);
}
#Override
public void clickOnItem(int id) {
movieData.movieDataPosition = id;
if(movieData.movieDataArray == null) {
movieRequest();
} else {
Intent intent = new Intent(this, detailsActivity.class);
intent.putExtra("FRAGMENT","MOVIE");
startActivity(intent);
}
}
#Override
public void favoriteMovieItem(int movieId) {
movieData.dbPosition = movieId;
Intent intent = new Intent(this,detailsActivity.class);
intent.putExtra("FRAGMENT","favorite");
startActivity(intent);
} }
You can try this
this.clickListener = (MainActivity) getActivity();
You get the FragmentActivity and cast it into your MainActivity
EDIT:
I suggest you to add a function in your fragment like :
public void setListener(clickInterfaceHelper listener) {
this.clickListener = listener;
}
And in your activity :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
MovieGridFragment fragment = new MovieGridFragment();
fragment.setListener(this); // some change here
getSupportFragmentManager().beginTransaction()
.add(R.id.activity_container, fragment)
.commit();
movieData.movieDataPosition = 0;
}
if(savedInstanceState != null) {
sorterString = savedInstanceState.getString("SORTER");
}
if(savedInstanceState == null)
movieData.movieDataPosition = 0;
if(sorterString==null)
sorterString="popular?";
if(sorterString!="favorite" && sorterString!=null) {
if(networkChecker.isNetworkAvailableChecker(this)) {
movieRequest();
}
}
}
.... no relevant functions
public void movieRequest() {
urlFinal = urlBase + sorterString + movieData.apiKey;
urlFinal.trim();
requestQueue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, urlFinal, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONArray array = response.getJSONArray("results");
movieData.movieDataArray = new movieData[array.length()];
for (int i = 0; i < array.length(); i++) {
movieData movie = new movieData();
JSONObject jsonObject = array.getJSONObject(i);
//movie.setPosition(i);
movie.setMovieId(jsonObject.getString("id"));
movie.setMovieImagePath(jsonObject.getString("poster_path"));
movie.setMovieTitle(jsonObject.getString("original_title"));
movie.setMoviePlot(jsonObject.getString("overview"));
movie.setMovieVoting(jsonObject.getString("vote_average"));
movie.setMovieReleaseDate(jsonObject.getString("release_date"));
movieData.movieDataArray[i] = movie;
}
MovieGridFragment gridFragment = new MovieGridFragment();
gridfragment.setListener(this); // some change here
gridFragment.movieDataList = Arrays.asList(movieData.movieDataArray); //hier wird datalist eigentlich zugewiesen
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.activity_container, gridFragment);
try {
transaction.commitAllowingStateLoss();
} catch (Exception e) {
e.printStackTrace();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("volley", String.valueOf(error));
}
}
);
requestQueue.add(jsonObjectRequest);
}
Hope this helps.
The context passed in is not necessarily your activity. It could be a wrapper around it with various theming and other overrides. You can never assume that when passed a Context, you're passed an Activity. If you need a reference to a click handler, write a setClickHandler function and call it explicitly.
Even if it is the Activity, the app doesn't know that- at that point its a Context. You'd need to explicitly cast it, which may not work (and may work on some versions of the OS and not others) due to paragraph 1.
Try to put your interface inside fragment class.
public class MovieGridFragment extends Fragment {
public clickInterfaceHelper clickListener;
private int index;
private GridView movieGridView;
public List<movieData> movieDataList = new ArrayList<>();
public MovieGridFragment() {} //empty constructor
#Override
public void onAttach(Context context) {
this.clickListener = (clickInterfaceHelper) context;
super.onAttach(context);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
if(savedInstanceState != null) {
if (!movieDataList.isEmpty()) {
movieDataList = Arrays.asList((movieData[]) savedInstanceState.getSerializable("OLDMOVIEDATA"));
}
}
super.onCreate(savedInstanceState);
}
public interface clickInterfaceHelper {
void clickOnItem(int id);
void favoriteMovieItem(int movieId);
}
}
To all android beginners, you can use the interface like below-mentioned way.
Define an Interface,
public interface CallBack {
String stringValue(String s);
}
In Fragment,
Callback mCallback;
In onAttach(Context context) method of your fragment,
mCallback = (Callback) context; // Casting to the activity
mcallback.stringValue("Your message");
Then in your Activity, you must implement the interface else you will get
classcastException
public class MainActivity implements CallBack{
#Override
public String stringValue(String s) {
// Here you will get the value from the fragment
return s;
}
}
It's not advisable to pass values between two fragments directly using interfaces. You should use the activity as a mediator while passing values.
I know what a null pointer exception is i have tried using
MediaPlayer mp = new MediaPlayer();
and
public int check()
{
if(mp!=null)
{
return 1;
}
else
{
return 2;
}
}
doesn't helps.
This is the error im getting-
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.openaisearch.www.musicplayer/com.openaisearch.www.musicplayer.MainActivity}:
java.lang.NullPointerException: Attempt to invoke virtual method
'boolean com.openaisearch.www.musicplayer.Music.check()' on a null
object reference
public class MainActivity extends AppCompatActivity {
ArrayList<String> mSongsList = new ArrayList<>() ;
ArrayList<Long> SongsPath = new ArrayList<>() ;
Button btnPlay;
Music mService;
SeekBar seekBar;
ListView lv;
boolean mBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
Music.LocalBinder binder = (Music.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, Music.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
startService(intent);
btnPlay = (Button) findViewById(R.id.buttonPlay);
seekBar = (SeekBar) findViewById(R.id.seekBar);
lv = (ListView) findViewById(R.id.list);
getAudioList();
ArrayAdapter arrayAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,mSongsList);
lv.setAdapter(arrayAdapter);
onSongClick();
setSeekBar();
check();
}
#Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
public void getAudioList() {
String orderBy = MediaStore.Audio.Media.TITLE ;
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
Cursor mCursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[] { MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media._ID }, selection, null, orderBy);
int count = mCursor.getCount();
while (mCursor.moveToNext()) {
mSongsList.add(mCursor.getString(mCursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)));
SongsPath.add(mCursor.getLong(mCursor
.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)));
}
mCursor.close();
}
public void onSongClick()
{
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mService.playSong(SongsPath.get(position));
if(btnPlay.getText() == "Play")
{
btnPlay.setText("Pause");
}
}
});
}
public void onButtonClick(View view) {
int a = mService.stopMusic();
if(a == 1)
{
btnPlay.setText("Play");
}
else if (a ==2)
{
btnPlay.setText("Pause");
}
}
public void check()
{
boolean check = mService.check();
}
public void setSeekBar()
{
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser )
{
mService.setProg(progress*1000);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
}
Service-
public class Music extends Service {
Long b;
MediaPlayer mp;
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
Music getService() {
return Music.this;
}
}
public void playSong(Long a) {
if (a!= b)
{ if(mp!=null)
{
mp.stop();
mp.release();
mp=null;
}
b =a;
Uri contentUri = ContentUris.withAppendedId(
android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, a);
mp = new MediaPlayer();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mp.setDataSource(getApplicationContext(), contentUri);
mp.prepare();
mp.setLooping(true);
mp.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public int stopMusic()
{
if(mp.isPlaying())
{
mp.pause();
return 1;
}
else if (mp!=null)
{
mp.start();
return 2;
}
else
{
return 0;
}
}
public void setProg(int a)
{ if(mp!=null)
{
mp.seekTo(a);
}
}
public boolean check()
{
if(mp!=null)
{
return true;
}
else
{
return false;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
You are not checking if the service has been connected to the activity or not using mbound in ur function.
public void check()
{
i f(mBound)
{
boolean check = mService.check();
}
}
You're probably getting the NPE from this line: boolean check = mService.check(); So it's mService that is null, not mp
I think you trying to bind service that is not started yet. Try to call startService(intent); before bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Your service class should follow this format; overwrite the onCreate() method
you are getting NPE because mService is null in line: mService.check();
public class MyService extends Service {
private Binder binder;
#Override
public void onCreate() {
super.onCreate();
binder = new Binder();
}
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public class Binder extends android.os.Binder {
public MyService getService() {
return MyService.this; // return instance
}
}
}
I am trying to implement an Instant Messaging functionality into my app following this guide: https://www.sinch.com/tutorials/android-messaging-tutorial-using-sinch-and-parse/#start the sinch client
I have followed everything in the guide exactly, but when I attempt to send a message I get a NullPointerException. Here is the guilty code:
private void sendMessage() {
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(getApplicationContext(), "Enter a message", Toast.LENGTH_LONG).show();
return;
}
Log.i(TAG, "messageService: " + messageService);
Log.i(TAG, "recipientId: " + recipientId);
Log.i(TAG, "messageBody: " + messageBody);
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
From the logs, I see that the recipientId and messageBody are properly assigned, and that the messageService object is null. Below is the full code of the activity:
public class ChatActivity extends AppCompatActivity {
private static final String TAG = "ChatActivity";
private String recipientId;
private EditText messageBodyField;
private ListView messagesList;
private ChatAdapter chatAdapter;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private String currentUserId;
private ServiceConnection serviceConnection = new MyServiceConnection();
private MessageClientListener messageClientListener = new MyMessageClientListener();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
bindService(new Intent(this, MessageService.class), serviceConnection, BIND_AUTO_CREATE);
//Log.i("Tag", "bindService(): " + bindService(new Intent(this, MessageService.class), serviceConnection, BIND_AUTO_CREATE));
Intent intent = getIntent();
recipientId = intent.getStringExtra("RECIPIENT_ID");
currentUserId = ParseUser.getCurrentUser().getObjectId();
messagesList = (ListView) findViewById(R.id.listview_chat);
chatAdapter = new ChatAdapter(this);
messagesList.setAdapter(chatAdapter);
loadMessageHistory();
messageBodyField = (EditText) findViewById(R.id.edittext_messageBodyField);
findViewById(R.id.button_send).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
private void loadMessageHistory() {
String[] userIds = {currentUserId, recipientId};
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereContainedIn("senderId", Arrays.asList(userIds));
query.whereContainedIn("recipientId", Arrays.asList(userIds));
query.orderByAscending("createdAt");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, ParseException e) {
if (e == null) {
for (int i = 0; i < messageList.size(); i++) {
WritableMessage message = new WritableMessage(messageList.get(i).get("recipientId").toString(), messageList.get(i).get("messageText").toString());
if (messageList.get(i).get("senderId").toString().equals(currentUserId)) {
chatAdapter.addMessage(message, ChatAdapter.DIRECTION_OUTGOING);
} else {
chatAdapter.addMessage(message, ChatAdapter.DIRECTION_INCOMING);
}
}
}
}
});
}
private void sendMessage() {
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(getApplicationContext(), "Enter a message", Toast.LENGTH_LONG).show();
return;
}
Log.i(TAG, "messageService: " + messageService);
Log.i(TAG, "recipientId: " + recipientId);
Log.i(TAG, "messageBody: " + messageBody);
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
#Override
public void onDestroy() {
messageService.removeMessageClientListener(messageClientListener);
unbindService(serviceConnection);
super.onDestroy();
}
private class MyServiceConnection implements ServiceConnection {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
messageService = (MessageService.MessageServiceInterface) iBinder;
Log.i(TAG, "messageService::onServiceConnected: " + messageService);
messageService.addMessageClientListener(messageClientListener);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
Log.i(TAG, "messageService::onServiceDisconnected: " + messageService);
}
}
private class MyMessageClientListener implements MessageClientListener {
#Override
public void onMessageFailed(MessageClient client, Message message, MessageFailureInfo failureInfo) {
Toast.makeText(ChatActivity.this, "Failed to send message", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, final Message message) {
if (message.getSenderId().equals(recipientId)) {
final WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereEqualTo("sinchId", message.getMessageId());
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, ParseException e) {
if (e == null) {
if (messageList.size() == 0) {
ParseObject parseMessage = new ParseObject("ParseMessage");
parseMessage.put("senderId", currentUserId);
parseMessage.put("recipientId", writableMessage.getRecipientIds().get(0));
parseMessage.put("messageText", writableMessage.getTextBody());
parseMessage.put("sinchId", message.getMessageId());
parseMessage.saveInBackground();
chatAdapter.addMessage(writableMessage, chatAdapter.DIRECTION_INCOMING);
}
}
}
});
}
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
final WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
chatAdapter.addMessage(writableMessage, ChatAdapter.DIRECTION_OUTGOING);
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {
}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {
}
}
}
And the MessageService class code:
package com.example.aes.ctf;
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "app-key";
private static final String APP_SECRET = "secret";
private static final String ENVIRONMENT = "";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
//private Intent broadcastIntent = new Intent("com.example.aes.ctf.ListUsersActivity");
//private LocalBroadcastManager broadcaster;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
//broadcaster = LocalBroadcastManager.getInstance(this);
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username)
.applicationKey(APP_KEY).applicationSecret(APP_SECRET)
.environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onClientStarted(SinchClient client) {
/*broadcastIntent.putExtra("success", true);
broadcaster.sendBroadcast(broadcastIntent);*/
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
client = null;
}
#Override
public void onClientFailed(SinchClient client, SinchError sinchError) {
/*broadcastIntent.putExtra("success", false);
broadcaster.sendBroadcast(broadcastIntent);*/
client = null;
}
#Override
public void onRegistrationCredentialsRequired(SinchClient sinchClient, ClientRegistration clientRegistration) {
}
#Override
public void onLogMessage(int i, String s, String s1) {
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
#Override
public void onDestroy() {
sinchClient.stopListeningOnActiveConnection();
sinchClient.terminate();
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
}
I can post more related code if needed. I've been stuck on this error for awhile.
EDIT:
I was able to fix it by changing
#Override
public IBinder onBind(Intent intent) {
return null;
}
to
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
Thanks guy!
well, this is because you never INITIALIZE the messageService object.
it seems like you wish to start a service and then - control it from your activity... are you sure you wish to send messages from a service rather from an AsyncTask?
AsyncTask also run in the background and much more easier to control for this purpose...
try to chek this link: http://developer.android.com/reference/android/os/AsyncTask.html
Your problem is here:
#Override
public IBinder onBind(Intent intent) {
return null;
}
You should implement a binder for your service and return it in the onBind method of your service, so in your MessageServiceInterface class declare following method:
public MessageService getService() {
Log.v("Serivce Bind", "Bind");
return MessageService.this;
}
}
And declare a field in MessageService class:
IBinder binder = new MessageSeviceInterface();
Return binder instance in onBind method and finally get the allocated instance of MessageService using following code:
Replace
messageService = (MessageService.MessageServiceInterface) iBinder;
With:
MessageService.MessageServiceInterface binder = (MessageService.MessageServiceInterface) iBinder;
messageService = binder.getService()`
I am using Sinch and Parse for my instant messaging system integrated in our application, and I have two concerns.
1) For some reason, I am receiving the following error when the messaging activity is displayed: The message client did not start". Furthermore, the message does not seem to go through in Sinch and not reflected visually in the application.
Below is the activity code (when the user clicks on the "quick chat" button, it takes them to the messaging activity page.
Below is the activity code for the messaging activity
public class MessagingActivity extends Activity implements ServiceConnection, MessageClientListener {
private String recipientId;
private Button sendButton;
private EditText messageBodyField;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private MessageAdapter messageAdapter;
private ListView messagesList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaging);
doBind();
messagesList = (ListView) findViewById(R.id.listMessages);
messageAdapter = new MessageAdapter(this);
messagesList.setAdapter(messageAdapter);
Intent intent = getIntent();
recipientId = intent.getStringExtra("Name");
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
sendButton = (Button) findViewById(R.id.sendButton);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
private void sendMessage() {
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(this, "Please enter a message", Toast.LENGTH_LONG).show();
return;
}
//Here is where you will actually send the message throught Sinch
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
private void doBind() {
Intent serviceIntent = new Intent(this, MessageService.class);
bindService(serviceIntent, this, BIND_AUTO_CREATE);
}
#Override
public void onDestroy() {
unbindService(this);
super.onDestroy();
}
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//Define the messaging service and add a listener
messageService = (MessageService.MessageServiceInterface) iBinder;
messageService.addMessageClientListener(this);
if (!messageService.isSinchClientStarted()) {
Toast.makeText(this, "The message client did not start."
,Toast.LENGTH_LONG).show();
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {
//Intentionally left blank
}
#Override
public void onMessageFailed(MessageClient client, Message message,
MessageFailureInfo failureInfo) {
//Notify the user if message fails to send
Toast.makeText(this, "Message failed to send.", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, Message message) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_INCOMING);
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_OUTGOING);
}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {
//Intentionally left blank
}
}
I have verified that the APP_KEY, the APP_SECRET and ENVIRONMENT matches what was recorded on Sinch.
I have tried this both on the emulator, and on a physical device.
Thanks in advance
Code service
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "XXXXX";
private static final String APP_SECRET = "YYYYY";
private static final String ENVIRONMENT = "sandbox.sinch.com";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId().toString();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username).applicationKey(APP_KEY)
.applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public void onClientFailed(SinchClient client, SinchError error) {
sinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
sinchClient = null;
}
public void stop() {
if (isSinchClientStarted()) {
sinchClient.stop();
sinchClient.removeSinchClientListener(this);
}
sinchClient = null;
}
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
#Override
public void onLogMessage(int level, String area, String message) {
//Intentionally left blank
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {
//Intentionally left blank
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
}
2) Limit: I would like to set a limit, where a only 25 messages would be available between a particular party.
Thanks in advance, and if you need any clarification, let me know.
Update 3
When user clicks on this button, he is taking to the MessagingActivity with the person he has been matched to based upon the below criteria
final Button ibutton = (Button) this.findViewById(R.id.btnQuickChat);
idrinks.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
openConversation();
}
private void openConversation() {
// TODO Auto-generated method stub
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereNotEqualTo("objectId", ParseUser.getCurrentUser()
.getObjectId());
query.setLimit(1);
query.findInBackground(new FindCallback<ParseUser>() {
public void done(List<ParseUser> user, ParseException e) {
if (e == null) {
Intent intent = new Intent(getApplicationContext(), MessagingActivity.class);
intent.putExtra("RECIPIENT_ID", user.get(0).getObjectId());
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(),
"Error finding that user",
Toast.LENGTH_SHORT).show();
}
}
});
}
});
MessagingActivity (nearly same as one provided in tutorial):
public class MessagingActivity extends Activity {
private String recipientId;
private EditText messageBodyField;
private String messageBody;
private MessageService.MessageServiceInterface messageService;
private MessageAdapter messageAdapter;
private ListView messagesList;
private String currentUserId;
private ServiceConnection serviceConnection = new MyServiceConnection();
private MessageClientListener messageClientListener = new MyMessageClientListener();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaging);
bindService(new Intent(this, MessageService.class), serviceConnection, BIND_AUTO_CREATE);
Intent intent = getIntent();
recipientId = intent.getStringExtra("RECIPIENT_ID");
currentUserId = ParseUser.getCurrentUser().getObjectId();
messagesList = (ListView) findViewById(R.id.listMessages);
messageAdapter = new MessageAdapter(this);
messagesList.setAdapter(messageAdapter);
populateMessageHistory();
messageBodyField = (EditText) findViewById(R.id.messageBodyField);
findViewById(R.id.sendButton).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
//get previous messages from parse & display
private void populateMessageHistory() {
String[] userIds = {currentUserId, recipientId};
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereContainedIn("senderId", Arrays.asList(userIds));
query.whereContainedIn("recipientId", Arrays.asList(userIds));
query.orderByAscending("createdAt");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, com.parse.ParseException e) {
if (e == null) {
for (int i = 0; i < messageList.size(); i++) {
WritableMessage message = new WritableMessage(messageList.get(i).get("recipientId").toString(), messageList.get(i).get("messageText").toString());
if (messageList.get(i).get("senderId").toString().equals(currentUserId)) {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_OUTGOING);
} else {
messageAdapter.addMessage(message, MessageAdapter.DIRECTION_INCOMING);
}
}
}
}
});
}
private void sendMessage() {
messageBody = messageBodyField.getText().toString();
if (messageBody.isEmpty()) {
Toast.makeText(this, "Please enter a message", Toast.LENGTH_LONG).show();
return;
}
messageService.sendMessage(recipientId, messageBody);
messageBodyField.setText("");
}
#Override
public void onDestroy() {
messageService.removeMessageClientListener(messageClientListener);
unbindService(serviceConnection);
super.onDestroy();
}
private class MyServiceConnection implements ServiceConnection {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
messageService = (MessageService.MessageServiceInterface) iBinder;
messageService.addMessageClientListener(messageClientListener);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
messageService = null;
}
}
private class MyMessageClientListener implements MessageClientListener {
#Override
public void onMessageFailed(MessageClient client, Message message,
MessageFailureInfo failureInfo) {
Toast.makeText(MessagingActivity.this, "Message failed to send.", Toast.LENGTH_LONG).show();
}
#Override
public void onIncomingMessage(MessageClient client, Message message) {
if (message.getSenderId().equals(recipientId)) {
WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
messageAdapter.addMessage(writableMessage, MessageAdapter.DIRECTION_INCOMING);
}
}
#Override
public void onMessageSent(MessageClient client, Message message, String recipientId) {
final WritableMessage writableMessage = new WritableMessage(message.getRecipientIds().get(0), message.getTextBody());
//only add message to parse database if it doesn't already exist there
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseMessage");
query.whereEqualTo("sinchId", message.getMessageId());
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> messageList, com.parse.ParseException e) {
if (e == null) {
if (messageList.size() == 0) {
ParseObject parseMessage = new ParseObject("ParseMessage");
parseMessage.put("senderId", currentUserId);
parseMessage.put("recipientId", writableMessage.getRecipientIds().get(0));
parseMessage.put("messageText", writableMessage.getTextBody());
parseMessage.put("sinchId", writableMessage.getMessageId());
parseMessage.saveInBackground();
messageAdapter.addMessage(writableMessage, MessageAdapter.DIRECTION_OUTGOING);
}
}
}
});
}
#Override
public void onMessageDelivered(MessageClient client, MessageDeliveryInfo deliveryInfo) {}
#Override
public void onShouldSendPushData(MessageClient client, Message message, List<PushPair> pushPairs) {}
}
}
MessageService activity
public class MessageService extends Service implements SinchClientListener {
private static final String APP_KEY = "61b1bfc0-b82a-44f5-ab68-dedca69ead8c";
private static final String APP_SECRET = "jrFrLr8Adkm0Na4nLdASDw==";
private static final String ENVIRONMENT = "sandbox.sinch.com";
private final MessageServiceInterface serviceInterface = new MessageServiceInterface();
private SinchClient sinchClient = null;
private MessageClient messageClient = null;
private String currentUserId;
private LocalBroadcastManager broadcaster;
private Intent broadcastIntent = new Intent("com.dooba.beta.matchOptionActivity");
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
currentUserId = ParseUser.getCurrentUser().getObjectId();
if (currentUserId != null && !isSinchClientStarted()) {
startSinchClient(currentUserId);
}
broadcaster = LocalBroadcastManager.getInstance(this);
return super.onStartCommand(intent, flags, startId);
}
public void startSinchClient(String username) {
sinchClient = Sinch.getSinchClientBuilder().context(this).userId(username).applicationKey(APP_KEY)
.applicationSecret(APP_SECRET).environmentHost(ENVIRONMENT).build();
sinchClient.addSinchClientListener(this);
sinchClient.setSupportMessaging(true);
sinchClient.setSupportActiveConnectionInBackground(true);
sinchClient.checkManifest();
sinchClient.start();
}
private boolean isSinchClientStarted() {
return sinchClient != null && sinchClient.isStarted();
}
#Override
public void onClientFailed(SinchClient client, SinchError error) {
broadcastIntent.putExtra("success", false);
broadcaster.sendBroadcast(broadcastIntent);
sinchClient = null;
}
#Override
public void onClientStarted(SinchClient client) {
broadcastIntent.putExtra("success", true);
broadcaster.sendBroadcast(broadcastIntent);
client.startListeningOnActiveConnection();
messageClient = client.getMessageClient();
}
#Override
public void onClientStopped(SinchClient client) {
sinchClient = null;
}
#Override
public IBinder onBind(Intent intent) {
return serviceInterface;
}
#Override
public void onLogMessage(int level, String area, String message) {
}
#Override
public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration clientRegistration) {
}
public void sendMessage(String recipientUserId, String textBody) {
if (messageClient != null) {
WritableMessage message = new WritableMessage(recipientUserId, textBody);
messageClient.send(message);
}
}
public void addMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.addMessageClientListener(listener);
}
}
public void removeMessageClientListener(MessageClientListener listener) {
if (messageClient != null) {
messageClient.removeMessageClientListener(listener);
}
}
public class MessageServiceInterface extends Binder {
public void sendMessage(String recipientUserId, String textBody) {
MessageService.this.sendMessage(recipientUserId, textBody);
}
public void addMessageClientListener(MessageClientListener listener) {
MessageService.this.addMessageClientListener(listener);
}
public void removeMessageClientListener(MessageClientListener listener) {
MessageService.this.removeMessageClientListener(listener);
}
public boolean isSinchClientStarted() {
return MessageService.this.isSinchClientStarted();
}
}
Message adapter activity:
public class MessageAdapter extends BaseAdapter {
public static final int DIRECTION_INCOMING = 0;
public static final int DIRECTION_OUTGOING = 1;
private List<Pair<WritableMessage, Integer>> messages;
private LayoutInflater layoutInflater;
public MessageAdapter(Activity activity) {
layoutInflater = activity.getLayoutInflater();
messages = new ArrayList<Pair<WritableMessage, Integer>>();
}
public void addMessage(WritableMessage message, int direction) {
messages.add(new Pair(message, direction));
notifyDataSetChanged();
}
#Override
public int getCount() {
return messages.size();
}
#Override
public Object getItem(int i) {
return messages.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int i) {
return messages.get(i).second;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
int direction = getItemViewType(i);
//show message on left or right, depending on if
//it's incoming or outgoing
if (convertView == null) {
int res = 0;
if (direction == DIRECTION_INCOMING) {
res = R.layout.message_right;
} else if (direction == DIRECTION_OUTGOING) {
res = R.layout.message_left;
}
convertView = layoutInflater.inflate(res, viewGroup, false);
}
WritableMessage message = messages.get(i).first;
TextView txtMessage = (TextView) convertView.findViewById(R.id.txtMessage);
txtMessage.setText(message.getTextBody());
return convertView;
}
}
I wrote the tutorial you're following, and actually just updated it yesterday to fix your first problem. Check out http://tutorial.sinch.com/android-messaging-tutorial/#show-spinner to see the updates. Instead of showing a toast message when the service is not started, the new version will show a progress dialog (loading spinner) until the service has either started or failed to start.
Could you clarify your second question?
Just declare your service in manifest. I had the same problem and it solved it.