Firebase RecyclerView: Retrieve Images & Text, Implement SearchView, Handle Item Clicks
In this tutorial we will learn using Firebase in Android app using Android Studio. We will:
Output
YouTube Playlist:
✓Create Android Studio Project
✓Create Firebase Project and connect our Android Studio Project to that Firebase Project
✓Store Images to FirebaseStorage manually
✓Add data in FirebaseDatabase
✓Retrieve these data(Title, Image, Description) in RecyclerView. To retrieve Images we will use Picasso library.
✓Implement SearchView
✓Handle RecyclerView Item Clicks, When an item is clicked it will be opened in new Activity.
✓Sort Firebase Data displayed in RecyclerView.
✓Save Image, Share Image & Text, Set Image as Wallpaper
✓Create Firebase Project and connect our Android Studio Project to that Firebase Project
✓Store Images to FirebaseStorage manually
✓Add data in FirebaseDatabase
✓Retrieve these data(Title, Image, Description) in RecyclerView. To retrieve Images we will use Picasso library.
✓Implement SearchView
✓Handle RecyclerView Item Clicks, When an item is clicked it will be opened in new Activity.
✓Sort Firebase Data displayed in RecyclerView.
✓Save Image, Share Image & Text, Set Image as Wallpaper
Step 1: Create a new project OR Open your project
Step 2: Choose Empty Activity & name it as "PostsListActivity"
Step 3: Create menu.xml under res>menu folder, to search item.
Step 4: In menu bar click Tools > Firebase. Firebase Assistent will open at right side
Step 5: Scroll and click Realtime Database. Click Save & Retrieve data.
1: Connect your app to Firebase
Click Connect to Firebase button
Connect to Firebase window will open. Select Create new Firebase project and enter project name FirebaseProject. Choose country e.g. Pakistan. Click Connect to Firebase button
2: Add the Realtime database to your app
Click Add the Realtime database to your app button
Click Accept Changes button
Step 6: Open Firebase
Link: https://console.firebase.google.com
Step 6.1 Click Storage from menu
Click Files tab
Click Upload file and upload some images
Click Rules tab
Define Rules as follows:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if true;
}
}
}
Step 6.2 Click Database from menu
Click Data tab
Note: To get URL of image click the uploaded image, under File location click Download Url, it will be copied
Add data as follows in Data tab of Database.
Step 7: build.gradle(Module app):
apply plugin: 'com.android.application' android { compileSdkVersion 27 defaultConfig { applicationId "com.blogspot.atifsoftwares.firebaseproject" minSdkVersion 16 targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:27.1.1' //card view implementation 'com.android.support:cardview-v7:27.1.1' //recyclerView implementation 'com.android.support:recyclerview-v7:27.1.1' //picasso library to retrive images implementation 'com.squareup.picasso:picasso:2.71828' implementation 'com.android.support.constraint:constraint-layout:1.1.0' implementation 'com.google.firebase:firebase-database:11.8.0' implementation 'com.firebaseui:firebase-ui-database:0.4.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } apply plugin: 'com.google.gms.google-services'
Step 8: Create class Model.java
package com.blogspot.atifsoftwares.firebaseproject; public class Model { String title, image, description; //constructor public Model(){} //getter and setters press Alt+Insert public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
Step 9: Create class ViewHolder.java
package com.blogspot.atifsoftwares.firebaseproject; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; public class ViewHolder extends RecyclerView.ViewHolder { View mView; public ViewHolder(View itemView) { super(itemView); mView = itemView; //item click itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mClickListener.onItemClick(view, getAdapterPosition()); } }); //item long click itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { mClickListener.onItemLongClick(view, getAdapterPosition()); return true; } }); } //set details to recycler view row public void setDetails(Context ctx, String title, String description, String image){ //Views TextView mTitleTv = mView.findViewById(R.id.rTitleTv); TextView mDetailTv = mView.findViewById(R.id.rDescriptionTv); ImageView mImageIv = mView.findViewById(R.id.rImageView); //set data to views mTitleTv.setText(title); mDetailTv.setText(description); Picasso.get().load(image).into(mImageIv); } private ViewHolder.ClickListener mClickListener; //interface to send callbacks public interface ClickListener{ void onItemClick(View view, int position); void onItemLongClick(View view, int position); } public void setOnClickListener(ViewHolder.ClickListener clickListener){ mClickListener = clickListener; } }
Step 10: menu.xml
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/action_search" android:icon="@drawable/ic_action_search" android:title="Search" app:actionViewClass="android.support.v7.widget.SearchView" app:showAsAction="always" /> <item android:id="@+id/action_sort" android:title="Sort" app:showAsAction="never" /> </menu>. |
Step 11: Add new resource layout in res folder and name it as row.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" xmlns:app="http://schemas.android.com/apk/res-auto" app:cardBackgroundColor="#fff" app:cardCornerRadius="3dp" app:cardElevation="3dp" app:contentPadding="5dp" app:cardUseCompatPadding="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/rTitleTv" android:text="Title" android:textColor="#000" android:textSize="22sp" android:textStyle="bold" android:layout_width="match_parent" android:layout_height="wrap_content" /> <ImageView android:id="@+id/rImageView" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="centerCrop" android:adjustViewBounds="true" android:background="@drawable/loadingimage"/> <TextView android:id="@+id/rDescriptionTv" android:text="This will be the description of the post" android:textSize="20sp" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </android.support.v7.widget.CardView>
Step 12: activity_posts_list.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:layout_height="match_parent" tools:context=".PostsListActivity" android:orientation="vertical"> <!--RecyclerView--> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
Step 13: PostsListActivity.java
package com.blogspot.atifsoftwares.firebaseproject; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.firebase.ui.database.FirebaseRecyclerAdapter; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.Query; import java.io.ByteArrayOutputStream; public class PostsListActivity extends AppCompatActivity { LinearLayoutManager mLayoutManager; //for sorting SharedPreferences mSharedPref; //for saving sort settings RecyclerView mRecyclerView; FirebaseDatabase mFirebaseDatabase; DatabaseReference mRef; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_posts_list); //Actionbar ActionBar actionBar = getSupportActionBar(); //set title mSharedPref = getSharedPreferences("SortSettings", MODE_PRIVATE); String mSorting = mSharedPref.getString("Sort", "newest"); //where if no settingsis selected newest will be default if (mSorting.equals("newest")) { mLayoutManager = new LinearLayoutManager(this); //this will load the items from bottom means newest first mLayoutManager.setReverseLayout(true); mLayoutManager.setStackFromEnd(true); } else if (mSorting.equals("oldest")) { mLayoutManager = new LinearLayoutManager(this); //this will load the items from bottom means oldest first mLayoutManager.setReverseLayout(false); mLayoutManager.setStackFromEnd(false); } //RecyclerView mRecyclerView = findViewById(R.id.recyclerView); mRecyclerView.setHasFixedSize(true); //set layout as LinearLayout mRecyclerView.setLayoutManager(mLayoutManager); //send Query to FirebaseDatabase mFirebaseDatabase = FirebaseDatabase.getInstance(); mRef = mFirebaseDatabase.getReference("Data"); } //search data private void firebaseSearch(String searchText) { //convert string entered in SearchView to lowercase String query = searchText.toLowerCase(); Query firebaseSearchQuery = mRef.orderByChild("search").startAt(query).endAt(query + "\uf8ff"); FirebaseRecyclerAdapter<Model, ViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Model, ViewHolder>( Model.class, R.layout.row, ViewHolder.class, firebaseSearchQuery ) { @Override protected void populateViewHolder(ViewHolder viewHolder, Model model, int position) { viewHolder.setDetails(getApplicationContext(), model.getTitle(), model.getDescription(), model.getImage()); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { ViewHolder viewHolder = super.onCreateViewHolder(parent, viewType); viewHolder.setOnClickListener(new ViewHolder.ClickListener() { @Override public void onItemClick(View view, int position) { //Views TextView mTitleTv = view.findViewById(R.id.rTitleTv); TextView mDescTv = view.findViewById(R.id.rDescriptionTv); ImageView mImageView = view.findViewById(R.id.rImageView); //get data from views String mTitle = mTitleTv.getText().toString(); String mDesc = mDescTv.getText().toString(); Drawable mDrawable = mImageView.getDrawable(); Bitmap mBitmap = ((BitmapDrawable) mDrawable).getBitmap(); //pass this data to new activity Intent intent = new Intent(view.getContext(), PostDetailActivity.class); ByteArrayOutputStream stream = new ByteArrayOutputStream(); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] bytes = stream.toByteArray(); intent.putExtra("image", bytes); //put bitmap image as array of bytes intent.putExtra("title", mTitle); // put title intent.putExtra("description", mDesc); //put description startActivity(intent); //start activity } @Override public void onItemLongClick(View view, int position) { //TODO do your own implementaion on long item click } }); return viewHolder; } }; //set adapter to recyclerview mRecyclerView.setAdapter(firebaseRecyclerAdapter); } //load data into recycler view onStart @Override protected void onStart() { super.onStart(); FirebaseRecyclerAdapter<Model, ViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Model, ViewHolder>( Model.class, R.layout.row, ViewHolder.class, mRef ) { @Override protected void populateViewHolder(ViewHolder viewHolder, Model model, int position) { viewHolder.setDetails(getApplicationContext(), model.getTitle(), model.getDescription(), model.getImage()); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { ViewHolder viewHolder = super.onCreateViewHolder(parent, viewType); viewHolder.setOnClickListener(new ViewHolder.ClickListener() { @Override public void onItemClick(View view, int position) { //Views TextView mTitleTv = view.findViewById(R.id.rTitleTv); TextView mDescTv = view.findViewById(R.id.rDescriptionTv); ImageView mImageView = view.findViewById(R.id.rImageView); //get data from views String mTitle = mTitleTv.getText().toString(); String mDesc = mDescTv.getText().toString(); Drawable mDrawable = mImageView.getDrawable(); Bitmap mBitmap = ((BitmapDrawable) mDrawable).getBitmap(); //pass this data to new activity Intent intent = new Intent(view.getContext(), PostDetailActivity.class); ByteArrayOutputStream stream = new ByteArrayOutputStream(); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] bytes = stream.toByteArray(); intent.putExtra("image", bytes); //put bitmap image as array of bytes intent.putExtra("title", mTitle); // put title intent.putExtra("description", mDesc); //put description startActivity(intent); //start activity } @Override public void onItemLongClick(View view, int position) { //TODO do your own implementaion on long item click } }); return viewHolder; } }; //set adapter to recyclerview mRecyclerView.setAdapter(firebaseRecyclerAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { //inflate the menu; this adds items to the action bar if it present getMenuInflater().inflate(R.menu.menu, menu); MenuItem item = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) MenuItemCompat.getActionView(item); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { firebaseSearch(query); return false; } @Override public boolean onQueryTextChange(String newText) { //Filter as you type firebaseSearch(newText); return false; } }); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); //handle other action bar item clicks here if (id == R.id.action_sort) { //display alert dialog to choose sorting showSortDialog(); return true; } return super.onOptionsItemSelected(item); } private void showSortDialog() { //options to display in dialog String[] sortOptions = {" Newest", " Oldest"}; //create alert dialog AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Sort by") //set title .setIcon(R.drawable.ic_action_sort) //set icon .setItems(sortOptions, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // The 'which' argument contains the index position of the selected item // 0 means "Newest" and 1 means "oldest" if (which == 0) { //sort by newest //Edit our shared preferences SharedPreferences.Editor editor = mSharedPref.edit(); editor.putString("Sort", "newest"); //where 'Sort' is key & 'newest' is value editor.apply(); // apply/save the value in our shared preferences recreate(); //restart activity to take effect } else if (which == 1) { { //sort by oldest //Edit our shared preferences SharedPreferences.Editor editor = mSharedPref.edit(); editor.putString("Sort", "oldest"); //where 'Sort' is key & 'oldest' is value editor.apply(); // apply/save the value in our shared preferences recreate(); //restart activity to take effect } } } }); builder.show(); } }
Step 14: Create new Activity(Empty Activity) and name it as PostDetailActivity.java
package com.blogspot.atifsoftwares.firebaseproject; import android.app.WallpaperManager; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.Manifest; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Locale; public class PostDetailActivity extends AppCompatActivity { TextView mTitleTv, mDetailTv; ImageView mImageIv; Bitmap bitmap; Button mSaveBtn, mShareBtn, mWallBtn; private static final int WRITE_EXTERNAL_STORAGE_CODE = 1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_post_detail); //Action bar ActionBar actionBar = getSupportActionBar(); //Actionbar title actionBar.setTitle("Post Detail"); //set back button in action bar actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowHomeEnabled(true); //initialize views mTitleTv = findViewById(R.id.titleTv); mDetailTv = findViewById(R.id.descriptionTv); mImageIv = findViewById(R.id.imageView); mSaveBtn = findViewById(R.id.saveBtn); mShareBtn = findViewById(R.id.shareBtn); mWallBtn = findViewById(R.id.wallBtn); //get data from intent byte[] bytes = getIntent().getByteArrayExtra("image"); String title = getIntent().getStringExtra("title"); String desc = getIntent().getStringExtra("description"); Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); //set data to views mTitleTv.setText(title); mDetailTv.setText(desc); mImageIv.setImageBitmap(bmp); //get image from imageview as bitmap bitmap = ((BitmapDrawable)mImageIv.getDrawable()).getBitmap(); //save btn click handle mSaveBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //if os is >= marshmallow we need runtime permission to save image if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED){ String[] permission = {Manifest.permission.WRITE_EXTERNAL_STORAGE}; //show popup to grant permission requestPermissions(permission, WRITE_EXTERNAL_STORAGE_CODE); } else { //permission already granted, save image saveImage(); } } else { //System os is < marshmallow, save image saveImage(); } } }); //share btn click handle mShareBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { shareImage(); } }); //set wallpaper btn click handle mWallBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setImgWallpaper(); } }); } private void setImgWallpaper() { WallpaperManager myWallManager = WallpaperManager.getInstance(getApplicationContext()); try { myWallManager.setBitmap(bitmap); Toast.makeText(this, "Wallpaper set...", Toast.LENGTH_SHORT).show(); } catch (Exception e){ Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } private void shareImage() { try { //get title and description and save in string s String s = mTitleTv.getText().toString() + "\n" + mDetailTv.getText().toString(); File file = new File(getExternalCacheDir(), "sample.png"); FileOutputStream fOut = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); fOut.flush(); fOut.close(); file.setReadable(true,false); //intent to share image and text Intent intent = new Intent(Intent.ACTION_SEND); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(Intent.EXTRA_TEXT, s); // put the text intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); intent.setType("image/png"); startActivity(Intent.createChooser(intent, "Share via")); } catch (Exception e){ Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } private void saveImage() { //time stamp, for image name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(System.currentTimeMillis()); //path to external storage File path = Environment.getExternalStorageDirectory(); //create folder named "Firebase" File dir = new File(path+"/Firebase/"); dir.mkdirs(); //image name String imageName = timeStamp + ".PNG"; File file = new File(dir, imageName); OutputStream out; try { out = new FileOutputStream(file); bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); out.flush(); out.close(); Toast.makeText(this, imageName+" saved to"+ dir, Toast.LENGTH_SHORT).show(); } catch (Exception e){ //failed saving image Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show(); } } //handle onBackPressed(go to previous activity) @Override public boolean onSupportNavigateUp() { onBackPressed(); return true; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode){ case WRITE_EXTERNAL_STORAGE_CODE:{ //if request code is cancelled the result arrays are empty if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ //permission is granted, save image saveImage(); } else { //permission denied Toast.makeText(this, "enable permission to save image", Toast.LENGTH_SHORT).show(); } } } } }
Step 15: activity_post_detail.xmlStep 16: Run Project
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.blogspot.atifsoftwares.firebaseproject"> <!-- add internet permission --> <uses-permission android:name="android.permission.INTERNET" /> <!--External storage permission--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!--Wallpaper permission--> <uses-permission android:name="android.permission.SET_WALLPAPER"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".PostsListActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".PostDetailActivity"></activity> </application> </manifest>
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView 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="wrap_content" app:cardBackgroundColor="#fff" app:cardCornerRadius="3dp" app:cardElevation="3dp" app:cardUseCompatPadding="true" app:contentPadding="5dp" tools:context=".PostDetailActivity"> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/titleTv" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Title" android:textColor="#000" android:textSize="22sp" android:textStyle="bold" /> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:background="@drawable/loadingimage" android:scaleType="fitXY" /> <TextView android:id="@+id/descriptionTv" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="This will be the description of the post" android:textSize="20sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/saveBtn" android:layout_weight="1" android:text="Save" android:drawableLeft="@drawable/ic_action_save" style="@style/Base.Widget.AppCompat.Button.Colored" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/shareBtn" android:layout_weight="1" android:text="Share" android:drawableLeft="@drawable/ic_action_share" style="@style/Base.Widget.AppCompat.Button.Colored" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:id="@+id/wallBtn" android:layout_weight="1" android:text="Wall" android:drawableLeft="@drawable/ic_action_wall" style="@style/Base.Widget.AppCompat.Button.Colored" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout> </ScrollView> </android.support.v7.widget.CardView>
Step 16: AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.blogspot.atifsoftwares.firebaseproject"> <!-- add internet permission --> <uses-permission android:name="android.permission.INTERNET" /> <!--External storage permission--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!--Wallpaper permission--> <uses-permission android:name="android.permission.SET_WALLPAPER"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".PostsListActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".PostDetailActivity"></activity> </application> </manifest>
Step 17: Run Project
YouTube Playlist:
Comments
Post a Comment