试图绕过通用名称,想知道我是否在此处正确应用了它。
请考虑以下内容:
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.annotation.NonNull;
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.LayoutInflater;
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.firebase.ui.database.FirebaseRecyclerOptions;
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;
FirebaseRecyclerAdapter<Model, ViewHolder> firebaseRecyclerAdapter;
FirebaseRecyclerOptions<Model> options;
@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);
//send Query to FirebaseDatabase
mFirebaseDatabase = FirebaseDatabase.getInstance();
mRef = mFirebaseDatabase.getReference("Data");
showData();
}
//show data
private void showData(){
options = new FirebaseRecyclerOptions.Builder<Model>().setQuery(mRef, Model.class).build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Model, ViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull Model model) {
holder.setDetails(getApplicationContext(), model.getTitle(), model.getDescription(), model.getImage());
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//Inflating layout row.xml
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView);
//item click listener
viewHolder.setOnClickListener(new ViewHolder.ClickListener() {
@Override
public void onItemClick(View view, int position) {
//get data from firebase at the position clicked
String mTitle = getItem(position).getTitle();
String mDesc = getItem(position).getDescription();
String mImage = getItem(position).getImage();
//pass this data to new activity
Intent intent = new Intent(view.getContext(), PostDetailActivity.class);
intent.putExtra("title", mTitle); // put title
intent.putExtra("description", mDesc); //put description
intent.putExtra("image", mImage); //put image url
startActivity(intent); //start activity
}
@Override
public void onItemLongClick(View view, int position) {
//Todo implement you on long click functionality here
}
});
return viewHolder;
}
};
//set layout as LinearLayout
mRecyclerView.setLayoutManager(mLayoutManager);
firebaseRecyclerAdapter.startListening();
//set adapter to firebase recycler view
mRecyclerView.setAdapter(firebaseRecyclerAdapter);
}
//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");
options = new FirebaseRecyclerOptions.Builder<Model>().setQuery(firebaseSearchQuery, Model.class).build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Model, ViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull Model model) {
holder.setDetails(getApplicationContext(), model.getTitle(), model.getDescription(), model.getImage());
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//Inflating layout row.xml
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView);
//item click listener
viewHolder.setOnClickListener(new ViewHolder.ClickListener() {
@Override
public void onItemClick(View view, int position) {
//get data from firebase at the position clicked
String mTitle = getItem(position).getTitle();
String mDesc = getItem(position).getDescription();
String mImage = getItem(position).getImage();
//pass this data to new activity
Intent intent = new Intent(view.getContext(), PostDetailActivity.class);
intent.putExtra("title", mTitle); // put title
intent.putExtra("description", mDesc); //put description
intent.putExtra("image", mImage); //put image url
startActivity(intent); //start activity
}
@Override
public void onItemLongClick(View view, int position) {
//Todo implement you on long click functionality here
}
});
return viewHolder;
}
};
//set layout as LinearLayout
mRecyclerView.setLayoutManager(mLayoutManager);
firebaseRecyclerAdapter.startListening();
//set adapter to firebase recycler view
mRecyclerView.setAdapter(firebaseRecyclerAdapter);
}
//load data into recycler view onStart
@Override
protected void onStart() {
super.onStart();
if (firebaseRecyclerAdapter !=null){
firebaseRecyclerAdapter.startListening();
}
}
@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;
}
if (id == R.id.action_add) {
//start Add Post Activity
startActivity(new Intent(PostsListActivity.this, AddPostActivity.class));
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();
}
}
无论何时调用该函数,我都希望Typescript强制使用描述最终数据结构的自定义接口。例如,从上方使用interface NameValuePair {
name: string;
value: string;
}
function flatten(data: NameValuePair[]) {
return data.reduce((obj, pair: NameValuePair) => {
obj[pair.name] = pair.value;
return obj;
}, {});
}
const formData: NameValuePair[] = [
{ name: "firstName", value: "John" },
{ name: "lastName", value: "Doe" }
];
let flattened = flatten(formData);
// { firstName: "John", lastName: "Doe" }
,可能的界面如下所示:
formData
以下是我尝试使用泛型的尝试:
interface ProfileForm {
firstName: string;
lastName: string;
}
它可以按预期工作,但是通过测试,它似乎提供了与以下结果相同的结果:
function flatten<T>(formData: NameValuePair[]): T {
return <T>formData.reduce((obj: T, pair: NameValuePair) => {
obj[pair.name] = pair.value;
return obj;
}, {});
}
let flattened = flatten<ProfileForm>(formData);
let firstName = flattened.firstName;
let age = flattened.age; // typescript error
在这种情况下,泛型能带来任何好处吗?
答案 0 :(得分:0)
这有效
const formDataRaw: NameValuePair[] = [{ name: "fullName", value: "John Doe" }]
// please note that reduce() was unnecessary, or you used it wrong.
// Anyway, your question should be focused, TypeScript and reduce() is
// two unrelated things, especially in your code I didn't see how they
// were related
const formData: NameValuePair = formDataRaw[0]
interface NameValuePair {
name: keyof ProfileForm | keyof OtherForm;
value: string;
}
interface ProfileForm {
fullName: string;
}
interface OtherForm {
otherProp: string;
}
type ResultingForm<NVP extends NameValuePair> =
NVP['name'] extends keyof ProfileForm ? ProfileForm :
NVP['name'] extends keyof OtherForm ? OtherForm :
never
interface Flatten {
<NVP extends NameValuePair>(formData: NVP): ResultingForm<NVP>
}
const flatten: Flatten = <NVP extends NameValuePair>(obj: NVP) => {
return { [obj['name']]: obj['value'] } as unknown as ResultingForm<NVP>
}
flatten(formData) // <--ok
flatten({ name: 'fullName', value: 'zxc' }) // <--ok. Code Completion works
flatten({ name: 'otherProp', value: 'zxc' }) // <--ok. Code Completion works
flatten({ name: 'foo', value: 'zxc' }) // <-- error
答案 1 :(得分:0)
以下是我尝试使用泛型的尝试:
function flatten<T>(formData: NameValuePair[]): T {
return <T>formData.reduce((obj: T, pair: NameValuePair) => {
obj[pair.name] = pair.value;
return obj;
}, {});
}
您正在使用泛型,但是在使用方式的情况下,它没有任何好处。任何编程语言的目标都应该是使用最少的代码来提供所需的结果。在这种情况下,具有以下签名的非泛型方法在没有泛型的情况下会做同样的事情:
function flatten(formData: NameValuePair[]): ProfileForm {
return formData.reduce((obj: T, pair: NameValuePair) => {
obj[pair.name] = pair.value;
return obj;
}, {}) as ProfileForm;
}
我想可以使用通用的方法在相同的输入下提供不同的结果,但实际上它应该只是那时的接口。
因此,在这种情况下,请不要使用泛型。然后您可能会问What exactly does Generics provide and why should I use it。