安卓大作业——校内快递代取app的一些总结

对大作业用到技术以及遇到的一些问题的总结
先上图了解基本功能

注册
登录
主界面
帮我取件
帮人代取

在未被确认为接单人时,只能查看酬金、包裹大小和收货地址,无法查看发布者个人信息

滑动菜单
我的发布

可选择接单人

接单人信息

可查看多个接单人的基本信息,并确定其中一个作为最终接单人

我的接单

被发布者确定为接单人之后,才显示发布者的基本信息和快递取件码

下面开始介绍用到的方法

数据库用的Bmob云数据库 https://www.bmob.cn

教程 https://www.bmob.cn/app/browser/228322

在开发中遇到的大坑:Bmob云数据库不支持多表联合查询;在update数据时,不相关的数据可能会被初始化为0

语法类似于SQLite

一、注册MD5加密,登录MD5解密

新建MD5类

public class MD5 {

public static String getMD5(String c_password) {

try {

// 生成一个MD5加密计算摘要

            MessageDigest md = MessageDigest.getInstance("MD5");

// 调用update方法计算MD5函数(参数:将密码串转换为操作系统的字节编码)

            md.update(c_password.getBytes());

// digest()最后返回md5的hash值,返回值为8位的字符串,但此方法要先调用update

// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值,数值从1开始

// BigInteger会把0省略掉,需补全至32位,重写一个方法将16位数转换为32位数

            String md5 =new BigInteger(1, md.digest()).toString(16);

return md5;

}catch (Exception e) {
    throw new RuntimeException("MD5加密错误:" + e.getMessage(), e);
 }
}
}

使用此类的静态方法,将输入的密码作为参数,加密后的字符串赋值给md5_pwd并存储到数据库
md5_pwd=MD5.getMD5(input_pwd);
登录时将输入的密码以同样以MD5加密的方式转换为字符串,与数据库中的字符串比较,若相同则登录成功
md5pwd=MD5.getMD5(pwd);

二、订单列表中头像的异步显示
订单列表是通过订单表的订单id查询出来的记录,但头像为用户的头像,存储在用户信息表中,而Bmob云数据库不支持多表查询,故此处用了异步机制,让图片在子线程中加载。订单表中存有发布者id,通过查询用户信息表中此id的记录,将图片地址取出来,再显示在列表中。但后来请教老师,老师建议在适配器与数据绑定前将数据查询出来。

public class MyAdapter extends ArrayAdapter<OrderList> {
    private int money;
    private String address;
    private String size;
    private String orderid;
    private int resourceId;
    private String sendPerson;
    private Context context;
    private String url;
    private ImageView img;
    public MyAdapter(Context context,int textViewResourceId, List<OrderList> list){
        super(context,textViewResourceId,list);
        resourceId=textViewResourceId;
        this.context=context;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        OrderList orderList=getItem(position);
        View view;
        final ViewHolder viewHolder;
        if (convertView == null){
            view =LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
            viewHolder = new ViewHolder();
            viewHolder.pk_address = (TextView)view.findViewById(R.id.pk_address);
            viewHolder.pk_size = (TextView)view.findViewById(R.id.pk_size);
            viewHolder.pk_money=(TextView)view.findViewById(R.id.pk_money);
            viewHolder.receiveimg=(ImageButton)view.findViewById(R.id.receiveimg);
            viewHolder.icon=(ImageView)view.findViewById(R.id.icon);
            view.setTag(viewHolder);
        }else {
            view=convertView;
            viewHolder = (ViewHolder) view.getTag();
        }
        money = orderList.getMoney();
        address = orderList.getAddress().toString();
        orderid = orderList.getOrder_id().toString();
        size =orderList.getPackage_size().toString();
        sendPerson=orderList.getStuID_send().toString();

        viewHolder.pk_address.setText("收货地址: "+address);
        viewHolder.pk_size.setText("包裹大小: "+size);
        viewHolder.pk_money.setText("酬金: ¥"+money);
        viewHolder.receiveimg.setImageResource(R.drawable.receive);

        MyAsyncTask imageTask=new MyAsyncTask(viewHolder.icon,context);
        imageTask.execute(sendPerson);//通过调用execute方法开始处理异步任务.相当于线程中的start方法.

        //给接单ImageButton设置监听事件

        viewHolder.receiveimg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mitemListener.onRbtnClick(position);
                mitemListener.getOrderID(orderid);
            }
        });
        return view;
    }



    /**
     * 图片按钮的监听接口
     */
    public interface onItemRbtnListener {
        void onRbtnClick(int i);
        void getOrderID(String oid);
    }

    private onItemRbtnListener mitemListener;

    public void setOnItemClickListener(onItemRbtnListener itemListener) {
        this.mitemListener = itemListener;
    }

    class ViewHolder{
        TextView pk_size;
        TextView pk_money;
        TextView pk_address;
        ImageButton receiveimg;
        ImageView icon;
    }

    class MyAsyncTask extends AsyncTask<String,String,Void>{
        private ImageView imv;
        private String imgurl;
        private String id;
        private Context context;
        public MyAsyncTask(ImageView imv,Context context){
            this.imv=imv;
            this.context=context;
        }
        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            Log.v("xiancheng",values[0]);
            Glide.with(context)
                    .load(values[0])
                    .into(imv);
        }

        @Override
        protected Void doInBackground(String... params) {
            id=params[0];
            BmobQuery<StudentMessage> query1 = new BmobQuery<>();
            query1.addWhereEqualTo("StuID", id);
            query1.findObjects(new FindListener<StudentMessage>() {
                @Override
                public void done(List<StudentMessage> object, BmobException e) {
                    if (e == null) {
                        imgurl =object.get(0).getImageUrl();
                        publishProgress(imgurl);
                    }
                    else{

                    }
                }
            });
            return null;
        }

    }
}

下面解释一下上述代码
AsyncTask<Params,Progress,Result>是一个抽象类,通常用于被继承
需要指定以下三个泛型参数:

Params:启动任务时输入参数的类型
Progress:后台任务执行中返回进度值的类型
Result:后台执行任务完成后返回结果的类型

当调用imageTask.execute(sendPerson);时开始处理异步任务。
传入的是发布者的id。此参数被doInBackground方法接收,它的参数类型为Strings...代表是一个数组。
取出id查询出此id对应的头像图片地址,用publishProgress(imgurl)的方法更新imgurl的值,此方法调用后就会触发onProgressUpdate()方法,它的参数doInBackground()返回的结果,也就是图片的地址。
使用Glide加载图片。
Glide,是一个被google所推荐的图片加载库。
导入
在AndroidStudio上添加依赖

dependencies {  
    implementation 'com.github.bumptech.glide:glide:3.7.0'  
    implementation 'com.android.support:support-v4:23.2.1'  
}

Glide.with(context).load(values[0]).into(imv);
context上下文 values[0]图片地址 imv 图片显示的对象

三、通过接口的参数传递信息
点击图片按钮后,要将此列的订单id传回到Activity中处理

public interface onItemRbtnListener {
       void onRbtnClick(int i);
       void getOrderID(String oid);
}
private onItemRbtnListener mitemListener;

getView中:

//给接单ImageButton设置监听事件

        viewHolder.receiveimg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mitemListener.onRbtnClick(position);
                mitemListener.getOrderID(orderid);
            }
        });

Activity中:

 myAdapter.setOnItemClickListener(new MyAdapter.onItemRbtnListener() {
            @Override
            public void onRbtnClick(int i) {
                Log.v("Helpothers", "点击了接单按钮" + i);
            }

            @Override
            public void getOrderID(String oid) {
                Log.v("Helpothers", "订单号:" + oid);
            }
        });
}

定义了一个接口,并用它初始化了一个实例,当点击图片按钮时,调用接口的两个方法,将position和订单id作为参数传入。如果一个方法的参数是接口类型,我们就可以将任何实现该接口的类的实例的引用传递给该接口参数,那么该接口参数就可以回调类实现的接口方法。

四、google滑动菜单

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
    </FrameLayout>
    <android.support.design.widget.NavigationView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_view"
        android:layout_gravity="start"
        app:menu="@menu/nav_menu"
        app:headerLayout="@layout/nav_header"/>
</android.support.v4.widget.DrawerLayout>

DrawerLayout中放置了两个直接子控件:
第一个子控件是FrameLayout,用于作为主屏幕中显示的内容。
第二个子控件这里使用了一个NavigationView,用于作为滑动菜单中显示的内容。
google提出了meteral design这样的一个设计理念之后,提供给用户官方的侧边栏的控件,就是NavigationView。
引入DesignSupport库

    implementation 'com.android.support:design:27.1.1'

作为DrawerLayout的第二个子控件

<android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:menu="@menu/nav_menu"
        app:headerLayout="@layout/nav_header"/>

NavigationView包含两个部分:menu,headerLayout
headerLayout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="180dp"
                android:padding="10dp"
                android:background="@drawable/headerlayout">
</RelativeLayout>

可写任意布局,此处经常被用于展示用户信息
注意height写成180dp比较合适
menu

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_tv"
            android:icon="@drawable/ic_action_tv"
            android:title="TV"/>
        <item
            android:id="@+id/nav_song"
            android:icon="@drawable/ic_action_song"
            android:title="SONG"/>
        <item
            android:id="@+id/nav_word"
            android:icon="@drawable/ic_action_word"
            android:title="WORD"/>
    </group>

</menu>

menu就是普通menu的写法,但要注意这里的group标签表示该组中的item只能单选

设置菜单中的item的监听事件

NavigationView navigationView=(NavigationView)findViewById(R.id.nav_view);
        navigationView.setCheckedItem(R.id.nav_tv);
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener(){
            @Override
            public boolean onNavigationItemSelected(MenuItem item){
                mDrawerLayout.closeDrawers();
                return true;
            }
        });

setCheckedItem(int id)设置默认选中项
setNavigationItemSelectedListener()设置监听器

五、使用RecylerView的方法在listview中嵌套横向listview
my_publish.xml中

 <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f5f5f5"
        android:paddingLeft="15dp"
        android:paddingRight="15dp"
        android:paddingTop="20dp"
        android:divider="#00000000"
        android:dividerHeight="14dp"
        android:id="@+id/mypublis_list_view">
 </ListView>

mypublish_listview_item.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="20dp"
    android:elevation="2dp"
    android:background="@drawable/myrect" >
    <TextView
        android:id="@+id/mp_orderid"
        android:layout_width="wrap_content"
        android:layout_height="25dp"
        android:text="订单号"
        android:textColor="#757575"
        android:textSize="14sp" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_marginRight="15dp"
        android:background="#f5f5f5" />
                 ......
                 ......
    <android.support.v7.widget.RecyclerView
        android:focusable="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/list_two"></android.support.v7.widget.RecyclerView>

</LinearLayout>

mypublish_listview_item_item.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:id="@+id/stu_receive"
        android:scaleType="center"
        android:layout_margin="5dp"/>
</LinearLayout>

适配器中:
找到RecyclerView

viewHolder.recyclerView=(RecyclerView)view.findViewById(R.id.list_two);
LinearLayoutManager lm=new LinearLayoutManager(mcontext);
lm.setOrientation(LinearLayoutManager.HORIZONTAL);
viewHolder.recyclerView.setLayoutManager(lm);

设置布局管理器方法,实现RecylerView布局里面的内容显示方式;
LinearLayoutManager:线性布局管理器
使用布局显示关键字LinearLayoutManager.HORIZONTAL

横向listView的适配器

viewHolder.recyclerView.setAdapter(new MyHorizontalAdapter(orderid,mcontext));
package com.xiaoding.finalproject;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.io.IOException;
import java.util.List;

import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.FindListener;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import static cn.bmob.v3.b.From.e;

public class MyHorizontalAdapter extends RecyclerView.Adapter<MyHorizontalAdapter.ViewHolder>{
    private List<String> list;
    private View view;
    private String orderid;
    private Context context;
    private ImageView receiverImg;
    protected String[] receive_stuid=new String[100];
    MyHorizontalAdapter(){}
    MyHorizontalAdapter(String orderid,Context context){
        this.orderid=orderid;
        this.context=context;
    }

    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        view=View.inflate(parent.getContext(),R.layout.mypublish_listview_item_item,null);
        ViewHolder holder=new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        MyAsyncTask myAsyncTask=new MyAsyncTask(holder.tv,context);
        myAsyncTask.execute(orderid,""+position);
        receiverImg=(ImageView)view.findViewById(R.id.stu_receive);
        receiverImg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.v("dgc","点击了子listview的item"+receive_stuid[position]);
                Intent intent = new Intent();
                intent.putExtra("receiverid",receive_stuid[position]);
                intent.putExtra("orderid",orderid);
                Log.v("dgc","receiverid"+receive_stuid[position]);
                intent.setClass(context,ReceiverInfo.class);
                context.startActivity(intent);
            }
        });
    }

    @Override
    public int getItemCount() {
        return 10;
    }

    public class ViewHolder extends RecyclerView.ViewHolder{
        ImageView tv;
        public ViewHolder(View itemView){
            super(itemView);
            tv=(ImageView) itemView.findViewById(R.id.stu_receive);

        }
    }


        class MyAsyncTask extends AsyncTask<String,String,Void> {
        private ImageView imv;
        private Context context;
        private String imgurl;
        private int position;
        public MyAsyncTask(ImageView imv,Context context){
            this.imv=imv;
            this.context=context;
        }
        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            Log.v("xiancheng",values[0]);
            Glide.with(context)
                    .load(values[0])
                    .into(imv);
        }

        @Override
        protected Void doInBackground(String... params) {
            position=Integer.parseInt(params[1]);
            Log.v("dgc",position+"");
            BmobQuery<OrderDetail> query = new BmobQuery<>();
            query.addWhereEqualTo("order_id", params[0]);
            Log.v("dgc","orderid:"+params[0]);
            query.findObjects(new FindListener<OrderDetail>() {
                @Override
                public void done(List<OrderDetail> object, BmobException e) {
                    if (e == null) {
                        receive_stuid[position] =object.get(position).getStuID_receiveorder();
                        Log.v("dgc",receive_stuid[position]);
                        BmobQuery<StudentMessage> query1 = new BmobQuery<>();
                        query1.addWhereEqualTo("StuID", receive_stuid[position]);
                        query1.findObjects(new FindListener<StudentMessage>() {
                            @Override
                            public void done(List<StudentMessage> object, BmobException e) {
                                if (e == null) {
                                    imgurl=object.get(0).getImageUrl();
                                    Log.v("dgc",imgurl);
                                    publishProgress(imgurl);
                                }
                                else{
                                    Log.v("dgc","127:"+e.toString());
                                }
                            }
                        });
                    }
                    else{
                        Log.v("dgc","133:"+e.toString());
                    }
                }
            });
            return null;
        }

    }

}

啊 怎么解释
RecyclerViewAdapter.class :继承RecyclerView.Adapter后,会重写三个方法:
onCreateViewHolder()方法,负责承载每个子项的布局。它有两个参数,其中一个是 int viewType;
onBindViewHolder()方法,负责将每个子项holder绑定数据。俩参数分别是RecyclerView.ViewHolder holder, int position;
getItemCount()返回有多少项
下面的稍微复杂,还是用异步的方法,将订单id传入和所点击的position传入,通过查询接单表找到与传入订单id相同的列,取出接单人id,再用此接单人id在用户信息表中查询头像图片地址,用Glide加载。
还有一些比较简单的功能就不写了。

六、一些样式上的技巧
1、ToolBar代替Actionbar在AppCompatActivity的使用
需要给Activity设置主题 无Actionbar即可
android:theme="@style/Theme.AppCompat.Light.NoActionBar">

        Toolbar toolbar=(Toolbar)findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mDrawerLayout=(DrawerLayout)findViewById(R.id.drawer_layout);
        NavigationView navView=(NavigationView)findViewById(R.id.nav_view);//获取滑动菜单实例
        ActionBar actionBar=getSupportActionBar();//获取ActionBar实例
        if(actionBar!=null){
            actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setHomeAsUpIndicator(R.mipmap.ic_menu);
        }

最后两行是把导航栏的返回图标替换成菜单图标

2、NavigationView中获取对象要通过以下步骤

        NavigationView navigationView = findViewById(R.id.nav_view);
        View view = navigationView.getHeaderView(0);
        headimg=(ImageView)view.findViewById(R.id.icon_img);

3、列表项之间的空格
实际上是把分割线的颜色设置成透明,并给一定高度,看上去就像设置了一个间距

        android:divider="#00000000"
        android:dividerHeight="14dp"

4、矩形的圆角和阴影
自己写一个放在drawable里面,在设置样式的地方用background属性调用
android:background="@drawable/myrect"

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="#fff" />
    <corners android:radius="5dp" />
</shape>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 《明朝那些事儿》,作者当年明月,其实不用多做介绍,这是一套非常值得推崇的关于明史的书籍。作者用诙谐幽默的语言,在不...
    向日葵666666阅读 687评论 0 0
  • 结束了马拉喀什一天的行程后,第二天一大早,我们便坐上去沙漠的车。 车子慢慢的开出了马拉喀什,路途中司机接到了一个电...
    _若瑜_阅读 266评论 0 1
  • 假设我们对一个想法的信念越强,这个想法就越有效。一个想法的有效性是通过支持它证据的数量和质量所决定的。信念是与此无...
    张添雅阅读 303评论 0 0
  • 诗/昂格伦 猎猎雄风 骏马嘶鸣 草原英雄 准备出征 磨剑四载 在手长缨 万丈光芒 津门辉映 金秋归来日 下马美酒 ...
    昂格伦阅读 217评论 0 3
  • 今日作业:将上周跑的裂变数据和复盘,梳理做的好的做的不好的部分,以及可以优化的点。 学习内容进行整理 1、对三裂变...
    熊猫大哥哥阅读 232评论 0 0