I am using Android Things v1.0.1 with the Adafruit Ultimate GPS Breakout Board v3 on the Raspberry Pi 3.
I am trying to display GPS information on screen, specifically sending Lat, Long, Altitude and number of satellites to individual TextViews on the display but I am struggling.
The NMEA driver I am using is this: Github / Android Things / Contrib Drivers / GPS
And here is my MainActivity:
public class MainActivity extends Activity {
private static final String UART_DEVICE_NAME = "UART0";
UartDevice mDevice;
NmeaGpsModule mGpsModule;
NmeaParser mGpsModuleCallback;
NmeaGpsDriver mGpsDriver;
LocationManager mLocMan;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("GPS Test");
try {
NmeaGpsDriver mGpsDriver = new NmeaGpsDriver(
MainActivity.this,
"UART0",
9600,
1.8f );
mGpsDriver.register();
} catch (IOException e) {
// couldn't configure the gps driver...
Log.w(TAG, "Couldn't configure the GPS driver");
}
mLocMan = (LocationManager) getSystemService(LOCATION_SERVICE);
if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "No permission");
return;
}
mLocMan.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 0, mLocList);
mLocMan.registerGnssStatusCallback(mStatusCallback);
mLocMan.addNmeaListener(mMessageListener);
Button gpsbtn = (Button) findViewById(R.id.gpsbtn);
gpsbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i(TAG, "Updating Location...");
}
}
);
}
private LocationListener mLocList = new LocationListener() {
#Override
public void onLocationChanged(Location location) {
Log.i(TAG, "Latitude: " + location.getLatitude());
Log.i(TAG, "Latitude: " + location.getLongitude());
Log.i(TAG, "Altitute: " + location.getAltitude());
TextView latbox = new TextView(MainActivity.this);
latbox.findViewById(R.id.latbox);
latbox.setText(location.getLatitude());
TextView longbox = new TextView(MainActivity.this);
longbox.findViewById(R.id.longbox);
longbox.setText(location.getLongitude());
TextView altbox = new TextView(MainActivity.this);
altbox.findViewById(R.id.altbox);
altbox.setText(location.getAltitude());
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) { }
#Override
public void onProviderEnabled(String provider) { }
#Override
public void onProviderDisabled(String provider) { }
};
/** Report satellite status */
private GnssStatus.Callback mStatusCallback = new GnssStatus.Callback() {
#Override
public void onStarted() {
Log.i(TAG, "GNSS Callback Started");
}
#Override
public void onStopped() {
Log.i(TAG, "GNSS Callback Stopped");
}
#Override
public void onFirstFix(int ttffMillis) {
Log.i(TAG, "On First Fix???");
}
#Override
public void onSatelliteStatusChanged(GnssStatus status) {
Log.i(TAG, "GNSS Status: " + status.getSatelliteCount() + " satellites.");
}
};
private OnNmeaMessageListener mMessageListener = new OnNmeaMessageListener() {
#Override
public void onNmeaMessage(String message, long timestamp) {
Log.v(TAG, "NMEA: " + message);
}
};
#Override
protected void onDestroy() {
super.onDestroy();
if (mDevice != null) {
try {
mDevice.close();
mDevice = null;
mGpsDriver.unregister();
mGpsDriver.close();
} catch (IOException e) {
Log.w(TAG, "Unable to close" + UART_DEVICE_NAME, e); }
}
}
activity_main.xml:
<TextView
android:id="#+id/longbox"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="60dp"
android:layout_marginTop="16dp"
android:background="#android:drawable/editbox_background"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/guideline"
app:layout_constraintTop_toBottomOf="#+id/loctext" />
<Button
android:id="#+id/gpsbtn"
style="#android:style/Widget.Button"
android:layout_width="267dp"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:text="#string/gpsbtn"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/altbox"
app:layout_constraintVertical_bias="0.447" />
<TextView
android:id="#+id/loctext"
android:layout_width="66dp"
android:layout_height="21dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:text="#string/loctext"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/citybox"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="16dp"
android:background="#android:drawable/editbox_background"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="#+id/guideline"
app:layout_constraintTop_toBottomOf="#+id/latbox" />
<TextView
android:id="#+id/lattext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="22dp"
android:text="#string/lattext"
app:layout_constraintEnd_toStartOf="#+id/latbox"
app:layout_constraintTop_toBottomOf="#+id/loctext" />
<TextView
android:id="#+id/longtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="22dp"
android:text="#string/longtext"
app:layout_constraintEnd_toStartOf="#+id/longbox"
app:layout_constraintTop_toBottomOf="#+id/loctext" />
<TextView
android:id="#+id/citytext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="28dp"
android:text="#string/citytext"
app:layout_constraintEnd_toStartOf="#+id/citybox"
app:layout_constraintTop_toBottomOf="#+id/lattext" />
<TextView
android:id="#+id/countrytext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="28dp"
android:text="#string/countrytext"
app:layout_constraintEnd_toStartOf="#+id/countrybox"
app:layout_constraintTop_toBottomOf="#+id/longtext" />
<TextView
android:id="#+id/latbox"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="16dp"
android:background="#android:drawable/editbox_background"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="#+id/guideline"
app:layout_constraintTop_toBottomOf="#+id/loctext" />
<TextView
android:id="#+id/countrybox"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="60dp"
android:layout_marginTop="16dp"
android:background="#android:drawable/editbox_background"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/guideline"
app:layout_constraintTop_toBottomOf="#+id/longbox" />
<TextView
android:id="#+id/alttext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="30dp"
android:text="#string/alttext"
app:layout_constraintEnd_toStartOf="#+id/altbox"
app:layout_constraintTop_toBottomOf="#+id/citytext" />
<TextView
android:id="#+id/altbox"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="16dp"
android:background="#android:drawable/editbox_background"
android:visibility="visible"
app:layout_constraintEnd_toStartOf="#+id/guideline"
app:layout_constraintTop_toBottomOf="#+id/citybox" />
<TextView
android:id="#+id/fixtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="30dp"
android:text="#string/fixtext"
app:layout_constraintEnd_toStartOf="#+id/fixbox"
app:layout_constraintTop_toBottomOf="#+id/countrytext" />
<TextView
android:id="#+id/fixbox"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="60dp"
android:layout_marginTop="16dp"
android:background="#android:drawable/editbox_background"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="#+id/guideline"
app:layout_constraintTop_toBottomOf="#+id/countrybox" />
<android.support.constraint.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="302dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintGuide_percent="0.5"
app:layout_constraintTop_toTopOf="parent" />
Instead use the following in the onLocationChanged() method:
TextView latbox = (TextView) findViewById(R.id.latbox);
latbox.setText("" + location.getLatitude());
TextView longbox = (TextView) findViewById(R.id.longbox);
longbox.setText("" + location.getLongitude());
TextView altbox = (TextView) findViewById(R.id.altbox);
altbox.setText("" + location.getAltitude());
Related
I am currently creating a chat application for a project in Android Studio using Kotlin, Firebase Cloud Storage and Cloud Firestore, and Glide, and I am following a few tutorials to do so. Everything was fine until I created a fragment to handle the user's account settings, such as name, bio, etc. The fragment appears to work and the edit text fields and profile picture can all be edited and interacted with, but neither of the buttons for saving and signing out seem to be displayed, and I can't figure out what the issue is exactly. As a result, I can't actually test the code until I can these buttons to be displayed. Any ideas?
This is what the fragment is supposed to look like, according to the layout: https://i.stack.imgur.com/0qR0C.png
This is what the fragment looks like when the application is actually running: https://i.stack.imgur.com/vAgLG.png
This is what the fragment layout looks like in code:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
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=".fragment.MyAccountFragment">
<ImageView
android:id="#+id/imageView_profile_picture"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="155dp"
android:layout_marginTop="50dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="#drawable/ic_baseline_account_circle_24" />
<EditText
android:id="#+id/editText_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="225dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="0dp"
android:hint="Your Name"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/imageView_profile_picture"
app:layout_constraintVertical_bias="0.025" />
<EditText
android:id="#+id/editText_bio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="275dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="0dp"
android:hint="Your Bio"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/imageView_profile_picture"
app:layout_constraintVertical_bias="0.025" />
<Button
android:id="#+id/btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="550dp"
android:backgroundTint="?attr/colorAccent"
android:text="Save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.971"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.982"
tools:visibility="visible" />
<Button
android:id="#+id/btn_sign_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="310dp"
android:layout_marginTop="550dp"
android:backgroundTint="?attr/colorPrimaryDark"
android:text="Sign Out"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.028"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.982"
tools:visibility="visible" />
</FrameLayout>
This is the code for the fragment itself:
class MyAccountFragment : Fragment() {
// Request code:
private val RC_SELECT_IMAGE = 2
// Variable for the selected image:
private lateinit var selectedImageBytes: ByteArray
// Picture change flag:
private var pictureJustChanged = false
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_my_account, container, false)
view.apply {
findViewById<ImageView>(R.id.imageView_profile_picture).setOnClickListener{
val intent = Intent().apply {
type = "image/*"
action = Intent.ACTION_GET_CONTENT
putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("image/jpeg", "image/png"))
}
startActivityForResult(Intent.createChooser(intent, "Select Image"), RC_SELECT_IMAGE)
}
findViewById<Button>(R.id.btn_save).setOnClickListener{
if(::selectedImageBytes.isInitialized){
CloudStorageUtil.uploadProfilePicture(selectedImageBytes) { imagePath ->
CloudFirestoreUtil.updateCurrentUser(findViewById<EditText>(R.id.editText_name).text.toString(),
findViewById<EditText>(R.id.editText_bio).text.toString(),
imagePath)
}
}
else {
CloudFirestoreUtil.updateCurrentUser(findViewById<EditText>(R.id.editText_name).text.toString(),
findViewById<EditText>(R.id.editText_bio).text.toString(),
null)
}
}
findViewById<Button>(R.id.btn_sign_out).setOnClickListener {
FirebaseAuth.getInstance().signOut()
val intent = Intent(this#MyAccountFragment.context, LoginOrRegisterActivity::class.java)
intent.flags = (Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
}
return view
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?){
if(requestCode == RC_SELECT_IMAGE
&& resultCode == Activity.RESULT_OK
&& data != null
&& data.data != null) {
val selectedImagePath = data.data
val selectedImageBmp = MediaStore.Images.Media.getBitmap(activity?.contentResolver, selectedImagePath)
val outputStream = ByteArrayOutputStream()
selectedImageBmp.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
selectedImageBytes = outputStream.toByteArray()
GlideApp.with(this).load(selectedImageBytes).into(view?.findViewById(R.id.imageView_profile_picture))
pictureJustChanged = true
}
}
override fun onStart() {
super.onStart()
CloudFirestoreUtil.getCurrentUser { user ->
if(this#MyAccountFragment.isVisible){
if (user != null) {
view?.findViewById<EditText>(R.id.editText_name)?.setText(user.name)
view?.findViewById<EditText>(R.id.editText_bio)?.setText(user.bio)
if(!pictureJustChanged && user.profilePicturePath != null){
GlideApp.with(this)
.load(CloudStorageUtil.pathToReference(user.profilePicturePath))
.placeholder(R.drawable.ic_baseline_account_circle_24)
.into(view?.findViewById(R.id.imageView_profile_picture))
}
}
}
}
}
}
When I Click on Home navigation fragment(there is recyclerview) recycler view disappears with error message: E/RecyclerView: No adapter attached; skipping layout
when the app launchs it appears but when i move to another fragment and return again to home fragment, recycler view just disappears. even If I dont move on another fragment and click on home fragment, it still disappears.
What could be the problem and what can I do to fix it?
My codes:
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
android:paddingBottom="65dp"
app:reverseLayout="false" />
</LinearLayout>
Posts.kt
data class Posts(
var id: Int,
var imageUrl: String,
var title: String,)
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var recyclerViewPersonAdapter: RecyclerViewPersonAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView = findViewById<BottomNavigationView>(R.id.bottomNavMenu)
val controller = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.homeFragment,
R.id.addFragment,
R.id.userFragment
)
)
setupActionBarWithNavController(controller, appBarConfiguration)
navView.setupWithNavController(controller)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = RecyclerViewPersonAdapter(getData())
}
private fun getData() : List<Posts>{
val list = ArrayList<Posts>()
list.add(
Posts(
1,
"https://www.myanbiz-consulting.com/wp-content/uploads/2019/04/4214892-news-images.jpg",
"Best news in the world\nfor you"
)
)
list.add(
Posts(
2,
"https://www.myanbiz-consulting.com/wp-content/uploads/2019/04/4214892-news-images.jpg",
"very very gooood\nnews for you"
)
)
list.add(
Posts(
3,
"https://www.myanbiz-consulting.com/wp-content/uploads/2019/04/4214892-news-images.jpg",
"very very gooood\nnews for you"
)
)
list.add(
Posts(
4,
"https://www.myanbiz-consulting.com/wp-content/uploads/2019/04/4214892-news-images.jpg",
"very very gooood\nnews for you"
)
)
return list
}
}
RecyclerViewPersonAdapter.kt
class RecyclerViewPersonAdapter(private val list: List<Posts>) : RecyclerView.Adapter<RecyclerViewPersonAdapter.PersonViewHolder>() {
class PersonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val imageView: ImageView
val textView: TextView
init {
imageView = itemView.findViewById(R.id.imageView)
textView = itemView.findViewById(R.id.textView)
}
fun setData(posts: Posts){
Glide.with(itemView.context)
.load(posts.imageUrl)
.into(imageView)
textView.text = posts.title
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PersonViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.news_post, parent, false)
return PersonViewHolder(itemView)
}
override fun onBindViewHolder(holder: PersonViewHolder, position: Int) {
val posts = list[position]
holder.setData(posts)
}
override fun getItemCount(): Int {
return list.size
}
}
news_post.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="400dp"
android:layout_height="100dp"
android:background="#color/teal_200"
android:layout_marginTop="15dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal">
<ImageView
android:id="#+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
android:scaleType="centerCrop"
android:src="#drawable/img" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="22dp"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="8sp"
android:text="Best news in the world\nfor you"
android:textColor="#color/black"
android:textSize="16sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="center"
android:src="#drawable/ic_baseline_thumb_up_alt_24" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:lineSpacingExtra="7sp"
android:text="2,687"
android:textColor="#333333"
android:textSize="13sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="22dp"
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="center"
android:src="#drawable/ic_baseline_remove_red_eye_24" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:lineSpacingExtra="7sp"
android:text="32,577"
android:textColor="#333333"
android:textSize="13sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
Your RecyclerView is in fragment_home.xml.
But you declare it in MainActivity.
Just do that in your HomeFragment instead of MainActivity.
class HomeFragment : Fragment() {
private lateinit var recyclerView: RecyclerView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
recyclerView = view.findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.adapter = RecyclerViewPersonAdapter(getData())
...
I have recently discovered abut Viewpager 2 and exoplayer and not sure how to integrate them both. Viewpager contains a list with video player and each takes up the full screen. You can swipe to move to the next video. Can anybody help me with a simple implementation of Exoplayer with Viewpager2
Yes I can help you.
It is a very simple implementation of viewpager2 with ExoPlayer.
It will show you online videos and you can swipe these videos horizontally.
Lets discuss it step by step:
Step 1:
Add internet permission in your Manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
Step 2:
Add ExoPlayer dependency to your build.gradle
// exo player
implementation 'com.google.android.exoplayer:exoplayer:2.17.1'
Step 3 :
Add the following code to your themes.xml
<style name="ClickableView">
<item name="colorControlHighlight">#android:color/darker_gray</item>
<item name="android:background">?selectableItemBackgroundBorderless</item>
</style>
Step 4:
Create a controller layout file to control ExoPlayer named as custom_controller.xml. And then paste bellow code in that file.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#80000000"
android:layout_height="match_parent">
<ImageView
android:id="#+id/exo_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="10dp"
android:src="#drawable/ic_baseline_lock_open"
android:theme="#style/ClickableView" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/sec_controlvid1"
android:orientation="horizontal"
android:layout_centerInParent="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_rew"
android:src="#drawable/ic_baseline_replay"
android:layout_marginLeft="30dp"
android:theme="#style/ClickableView"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_play"
android:src="#drawable/ic_baseline_play_arrow"
android:layout_marginHorizontal="30dp"
android:theme="#style/ClickableView"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_pause"
android:src="#drawable/ic_baseline_pause"
android:layout_marginHorizontal="30dp"
android:theme="#style/ClickableView"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_ffwd"
android:layout_marginRight="30dp"
android:src="#drawable/ic_baseline_forward"
android:theme="#style/ClickableView"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/sec_controlvid2"
android:orientation="vertical"
android:padding="8dp"
android:gravity="center"
android:layout_alignParentBottom="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
android:gravity="center"
android:layout_alignParentBottom="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_position"
android:textColor="#color/white"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/"
android:layout_marginHorizontal="4dp"
android:textColor="#CBCDC8"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_duration"
android:layout_weight="1"
android:textColor="#CBCDC8"/>
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/ic_baseline_fullscreen"
android:id="#+id/bt_fullscreen"
android:theme="#style/ClickableView"/>
</LinearLayout>
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/exo_progress"
app:unplayed_color="#42454E"
app:buffered_color="#95989F"
app:played_color="#FF0000"
app:scrubber_color="#FF0000"
android:layout_alignParentBottom="true"
android:layout_marginTop="-8dp"/>
</LinearLayout>
</RelativeLayout>
Step 5:
Create a layout file for representing items in viewpager named as video_card_item.xml and write the following code in it:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center_vertical"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.exoplayer2.ui.PlayerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:id="#+id/statusSliderVideo"
app:use_controller="true"
android:background="#android:color/background_dark"
app:player_layout_id="#layout/exo_player_view"
app:controller_layout_id="#layout/custom_controller"/>
<ImageView
android:id="#+id/statusSliderThumbnailImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:padding="10dp"
android:scaleType="fitCenter"
android:src="#drawable/ic_default_image" />
<ImageView
android:id="#+id/playPauseBtn"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:src="#drawable/ic_play"
app:tint="#color/white" />
<ProgressBar
android:layout_width="80dp"
android:layout_height="80dp"
android:visibility="gone"
android:id="#+id/progress_bar"
android:layout_centerInParent="true"/>
</RelativeLayout>
Step 6 :
Create adapter class for viewpager items named as VideoSliderAdapter.java and write bellow code in it:
package com.example.practiceproject;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ui.PlayerView;
import java.util.ArrayList;
public class VideoSliderAdapter extends RecyclerView.Adapter<VideoSliderAdapter.ViewHolder> {
private Context context;
private ArrayList<String> pathsList;
private AppCompatActivity activity;
private boolean isFullScreen = false;
public static boolean isFullLock = false;
public VideoSliderAdapter(Context context, ArrayList<String> pathsList, AppCompatActivity activity) {
this.context = context;
this.pathsList = pathsList;
this.activity = activity;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.video_card_item, parent, false);
return new ViewHolder(view);
}
#SuppressLint("ClickableViewAccessibility")
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.thumbnailImage.setImageBitmap(ThumbnailUtils.createVideoThumbnail(pathsList.get(position),
MediaStore.Video.Thumbnails.FULL_SCREEN_KIND));
// get data
Uri videoUri = Uri.parse(pathsList.get(position));
holder.bt_fullscreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isFullScreen) {
holder.bt_fullscreen.setImageDrawable(
ContextCompat.getDrawable(context, R.drawable.ic_baseline_fullscreen_exit)
);
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else {
holder.bt_fullscreen.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_baseline_fullscreen));
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
isFullScreen = !isFullScreen;
}
});
holder.bt_lockscreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isFullLock) {
holder.bt_lockscreen.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_baseline_lock_open));
} else {
holder.bt_lockscreen.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_baseline_lock));
}
isFullLock = !isFullLock;
lockScreen(isFullLock, holder.sec_mid, holder.sec_bottom);
}
});
holder.playPauseBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.playPauseBtn.setVisibility(View.GONE);
// holder.thumbnailImage.setVisibility(View.GONE);
holder.playerView.setVisibility(View.VISIBLE);
holder.simpleExoPlayer = new SimpleExoPlayer.Builder(context)
.setSeekBackIncrementMs(5000)
.setSeekForwardIncrementMs(5000)
.build();
holder.playerView.setPlayer(holder.simpleExoPlayer);
holder.playerView.setKeepScreenOn(true);
holder.simpleExoPlayer.addListener(new Player.Listener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == Player.STATE_BUFFERING) {
holder.progressBar.setVisibility(View.VISIBLE);
} else if (playbackState == Player.STATE_READY) {
holder.progressBar.setVisibility(View.GONE);
}
}
});
MediaItem mediaItem = MediaItem.fromUri(videoUri);
holder.simpleExoPlayer.setMediaItem(mediaItem);
holder.simpleExoPlayer.prepare();
holder.simpleExoPlayer.play();
}
});
}
private void lockScreen(boolean isFullLock, LinearLayout sec_mid, LinearLayout sec_bottom) {
if (isFullLock) {
sec_mid.setVisibility(View.INVISIBLE);
sec_bottom.setVisibility(View.INVISIBLE);
} else {
sec_mid.setVisibility(View.VISIBLE);
sec_bottom.setVisibility(View.VISIBLE);
}
}
#Override
public int getItemCount() {
return pathsList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
PlayerView playerView;
ImageView thumbnailImage;
ImageView playPauseBtn;
ImageView bt_fullscreen, bt_lockscreen;
SimpleExoPlayer simpleExoPlayer;
ProgressBar progressBar;
LinearLayout sec_mid, sec_bottom;
public ViewHolder(#NonNull View view) {
super(view);
playerView = view.findViewById(R.id.statusSliderVideo);
thumbnailImage = view.findViewById(R.id.statusSliderThumbnailImage);
playPauseBtn = view.findViewById(R.id.playPauseBtn);
progressBar = view.findViewById(R.id.progress_bar);
bt_fullscreen = view.findViewById(R.id.bt_fullscreen);
bt_lockscreen = view.findViewById(R.id.exo_lock);
sec_mid = view.findViewById(R.id.sec_controlvid1);
sec_bottom = view.findViewById(R.id.sec_controlvid2);
}
}
}
Step 7 :
Paste following code in your activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="true"
android:foregroundGravity="center"
android:overScrollMode="never"
android:id="#+id/videoViewPager"/>
</LinearLayout>
Step 8 :
Paste bellow code in your MainActivity.java:
package com.example.practiceproject;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager;
private VideoSliderAdapter myAdapter;
ArrayList<String> videoPaths;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.videoViewPager);
videoPaths = new ArrayList<>();
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4");
// add paths for video simllarly
myAdapter = new VideoSliderAdapter(getApplicationContext(), videoPaths,
MainActivity.this);
viewPager.setAdapter(myAdapter);
viewPager.setPadding(10, 0, 10, 0);
}
}
Completed
Now you are good to go. Enjoy the app.. Best of Luck.
If you want to get project files (Source Code) for more simplicity, you can get source code from my github profile.
link : https://github.com/AbdullahProgrammer426351/Custom-Video-Slider-with-Exo-Player-and-ViewPager2
I have four radio button inside the radio group in recyclerview. when i click first position of radio button it reflect on eighth position of radio button. How can i resolve this? If no radio button clicked the group will disable. how can i do this also? when i click the submit button calculate how many radio button clicked?
Xml :
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/txt_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:maxLines="5"
android:text="#string/question_1"
android:textColor="#000"
android:textSize="16sp"
android:textStyle="bold" />
<RadioGroup
android:id="#+id/radio_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp">
<RadioButton
android:id="#+id/radio_option_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
<RadioButton
android:id="#+id/radio_option_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
<RadioButton
android:id="#+id/radio_option_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
<RadioButton
android:id="#+id/radio_option_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
</RadioGroup>
</LinearLayout>
</android.support.v7.widget.CardView>
Adapter :
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.RecyclerVH> {
private Context mCtx;
private List<TestResult> testList;
public TestAdapter(Context mCtx, List<TestResult> testList) {
this.mCtx = mCtx;
this.testList = testList;
}
#NonNull
#Override
public RecyclerVH onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(mCtx);
View view = layoutInflater.inflate(R.layout.list_test, parent, false);
return new RecyclerVH(view);
}
#Override
public void onBindViewHolder(#NonNull final RecyclerVH holder, final int position) {
TestResult test = testList.get(position);
String question = position + 1 + " " + test.getQuestion();
holder.question.setText(question);
holder.option_1.setText(test.getChoice0());
holder.option_2.setText(test.getChoice1());
holder.option_3.setText(test.getChoice2());
holder.option_4.setText(test.getChoice3());
// Log.d("Test",position+"");
}
#Override
public int getItemCount() {
return testList.size();
}
public void setList(ArrayList<TestResult> list) {
this.testList = list;
}
class RecyclerVH extends RecyclerView.ViewHolder {
TextView question;
RadioButton option_1;
RadioButton option_2;
RadioButton option_3;
RadioButton option_4;
RadioGroup group;
RecyclerVH(#NonNull View itemView) {
super(itemView);
question = itemView.findViewById(R.id.txt_question);
option_1 = itemView.findViewById(R.id.radio_option_1);
option_2 = itemView.findViewById(R.id.radio_option_2);
option_3 = itemView.findViewById(R.id.radio_option_3);
option_4 = itemView.findViewById(R.id.radio_option_4);
group = itemView.findViewById(R.id.radio_group);
}
}
}
add this in your adapter, it will handle item according to respective position.
#Override
public int getItemViewType(int position) {
return position;
}
I am new to Android Studio - Kotlin, I am building an app with numbers and math operators with decimal point(.dot button)In my math calculator app, if press the dot button, the button should be disabled or not entered for the second time. I want to disable or stop printing dot button(.) if pressed more than once.
Here is my code
Acitivity.kt file
package com.tripbegins.calculator
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import com.tripbegins.calculator.R.id.*
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
var emptyText = true
fun numberEvents(view: View) {
var checkButton:Boolean = false
if(emptyText){
viewResult.setText("")
}
emptyText = false
var button = view as Button
var isClicked = viewResult.text.toString()
when (button.id) {
buttonOne.id -> isClicked += "1"
buttonTwo.id -> isClicked += "2"
buttonThree.id -> isClicked += "3"
dotButton.id-> isClicked+="."
}
viewResult.setText(isClicked)
}
var operation ="+"
var oldValues:String? = null
fun mathOperation(view: View){
var mathButton = view as Button
var isClicked = viewResult.text.toString()
when(mathButton.id){
plusButton.id-> {
operation = "+"
}
minusButton.id->{
operation="-"
}
mulButton.id->{
operation="*"
}
}
oldValues = viewResult.text.toString()
emptyText = true
}
fun Calculate(view: View){
var newValues = viewResult.text.toString()
var calulateButton:Double? = null
when(operation){
"+"-> { calulateButton = oldValues!!.toDouble() + newValues.toDouble() }
"-"-> { calulateButton = oldValues!!.toDouble() - newValues.toDouble() }
"*"-> { calulateButton = oldValues!!.toDouble() * newValues.toDouble() }
}
viewResult.setText(calulateButton.toString())
emptyText=true
}
fun clearFunction(view: View){
viewResult.setText("")
}
}
activity.xml file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="com.tripbegins.calculator.MainActivity">
<EditText
android:id="#+id/viewResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="42dp"
android:ems="10"
android:gravity="bottom|right"
android:inputType="textPersonName"
android:text="0"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/buttonTwo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="76dp"
android:onClick="numberEvents"
android:text="2"
app:layout_constraintStart_toEndOf="#+id/buttonOne"
app:layout_constraintTop_toBottomOf="#+id/viewResult" />
<Button
android:id="#+id/plusButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="38dp"
android:onClick="mathOperation"
android:text="+"
app:layout_constraintBaseline_toBaselineOf="#+id/minusButton"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/minusButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="33dp"
android:onClick="mathOperation"
android:text="-"
app:layout_constraintStart_toEndOf="#+id/plusButton"
app:layout_constraintTop_toBottomOf="#+id/buttonTwo" />
<Button
android:id="#+id/mulButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="26dp"
android:onClick="mathOperation"
android:text="*"
app:layout_constraintBaseline_toBaselineOf="#+id/minusButton"
app:layout_constraintStart_toEndOf="#+id/minusButton" />
<Button
android:id="#+id/calButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="44dp"
android:onClick="Calculate"
android:text="Calculate"
app:layout_constraintStart_toStartOf="#+id/minusButton"
app:layout_constraintTop_toBottomOf="#+id/minusButton" />
<Button
android:id="#+id/buttonThree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="26dp"
android:onClick="numberEvents"
android:text="3"
app:layout_constraintBaseline_toBaselineOf="#+id/buttonTwo"
app:layout_constraintStart_toEndOf="#+id/buttonTwo" />
<Button
android:id="#+id/buttonOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="34dp"
android:onClick="numberEvents"
android:text="1"
app:layout_constraintBaseline_toBaselineOf="#+id/buttonTwo"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/dotButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="22dp"
android:onClick="numberEvents"
android:text="."
app:layout_constraintBaseline_toBaselineOf="#+id/calButton"
app:layout_constraintEnd_toStartOf="#+id/calButton" />
<Button
android:id="#+id/clearButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="11dp"
android:onClick="clearFunction"
android:text="Clear"
app:layout_constraintBaseline_toBaselineOf="#+id/calButton"
app:layout_constraintStart_toEndOf="#+id/calButton" />
</android.support.constraint.ConstraintLayout>
My expectation of the result
Valid entry -> 3. (.dot button should not be entered for the second time)
Invalid entry -> 3... (currently i can able to enter multiple .dot buttons)
Dot button should not pressed twice. It should be active only once.
Thanks
Mohammed
so you want to disable the button that has the name dotButton after the user clicks it for the first time :
to disable a button, use:
dotButton.isClickable=false
if you want the button to become clickable again(like when the user deletes the dot that he already pressed) you can use:
dotButton.isClickable=true
Edit:
modify your activity code like that :
when (button.id) {
buttonOne.id -> isClicked += "1"
buttonTwo.id -> isClicked += "2"
buttonThree.id -> isClicked += "3"
dotButton.id-> {
isClicked+="."
dotButton.isClickable=false//**add this line here**
}
}
fun clearFunction(view: View){
viewResult.setText("")
dotButton.isClickable=true//**add this line here**
}