项目介绍
- 贴话APP实现的功能类似于百度贴吧,实现发帖,读帖,修改帖,删帖功能,
- 项目特色在于借助个人服务器的数据库实现网络服务,利用本地
LitaPal
实现用户数据缓存。 - 没有唯一用户的说法,使用人可以以任何用户名发帖,他人发帖可以看到。
- 实现了
NavigationView
侧边栏功能和WebView
个人博客,上传图片的功能,支持用户登录,头像上传和帖子图片上传。 - 设计使用高德地图开发包实现地图功能。
- 使用
CardView
美化RecylerView
,支持ToolBar
和Scrolling
美化页面动画。
关注博客
项目搭建
首页
-
首页采用
Android Stdio
模板(自带侧边栏),首页采用碎片,用RecylerView
和CardView
搭建,侧边栏采用NavigationView
搭建。public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { private static Connection conn = null; private static PreparedStatement stmt = null; private SwipeRefreshLayout swipeRefreshLayout; private List<News> sNewsList = new ArrayList<News>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle("主页"); setSupportActionBar(toolbar); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.setDrawerListener(toggle); toggle.syncState(); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); navigationView.setNavigationItemSelectedListener(this); } @Override public void onBackPressed() { DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { Intent intent = new Intent(MainActivity.this, PublishPost.class); startActivity(intent); item.setIntent(intent); } return super.onOptionsItemSelected(item); } @SuppressWarnings("StatementWithEmptyBody") @Override public boolean onNavigationItemSelected(MenuItem item) { // Handle navigation view item clicks here. int id = item.getItemId(); if (id == R.id.nav_camera) { Intent intent = new Intent(); intent.setClass(MainActivity.this, PublishPost.class); startActivityForResult(intent, 1); } else if (id == R.id.nav_gallery) { Intent intent = new Intent(); intent.setClass(MainActivity.this, WebBlog.class); startActivity(intent); } else if (id == R.id.nav_slideshow) { } else if (id == R.id.nav_manage) { } else if (id == R.id.nav_share) { } else if (id == R.id.nav_send) { } return true; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 1: if (requestCode == RESULT_OK) { String result = data.getStringExtra("message"); finish(); Intent intent = new Intent(this, MainActivity.class); startActivity(intent); Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show(); } } } }
-
其中,onCreate函数初始化界面,引入ToolBar和NavigationView,onNavigationItemSelected函数设置侧边栏的点击事件的响应,onOptionsItemSelected函数设置ToolBar右边下拉框点击事件的响应。
-
布局
<?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" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:openDrawer="start"> <include layout="@layout/app_bar_main" android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.design.widget.NavigationView android:id="@+id/nav_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" app:headerLayout="@layout/nav_header_main" app:menu="@menu/activity_main_drawer"> </android.support.design.widget.NavigationView> </android.support.v4.widget.DrawerLayout>
-
其中
<include>
导入主页面,<android.support.design.widget.NavigationView>
标签设置侧边栏,app:headerLayout
和app:menu
设置侧边栏的头部和身体。
首页碎片显示
-
首页内容显示采用
碎片+RecylerView+CardView
,核心代码如下
public class NewsTitleFragment extends Fragment { private boolean isTwoPane; private static Connection conn = null; private static PreparedStatement stmt = null; private List<News> sNewsList = new ArrayList<News>(); private static final CountDownLatch ctl = new CountDownLatch(1); private SwipeRefreshLayout swipeRefreshLayout; private NewsAdapter newsAdapter = new NewsAdapter(); @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.news_title_frag, container, false); RecyclerView newsTitleRecyclerView = (RecyclerView) view.findViewById(R.id.news_title_recycle_view); LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()) { @Override protected int getExtraLayoutSpace(RecyclerView.State state) { return 300; } }; newsTitleRecyclerView.setLayoutManager(layoutManager); @SuppressLint("HandlerLeak") final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { sNewsList = (List<News>) msg.obj; Log.d("sNewList.length : ", String.valueOf(sNewsList.size())); } }; Thread thread = null; thread = new Thread(new Runnable() { @Override public void run() { Log.d(TAG, "ppppp: ???"); try { conn = MySQLConnections.getConnection("blog"); } catch (Exception e) { e.printStackTrace(); } try { String sql = "select id,author,title,content from Blog"; List<News> list_tmp = new ArrayList<News>(); if (conn != null) { stmt = conn.prepareStatement(sql); conn.setAutoCommit(false); ResultSet rs = stmt.executeQuery();//用rs接收sql语句返回的查询结果 //执行查询语句并且保存结果 while (rs.next()) { Log.d("1", "1"); News news = new News(); news.setId(Integer.parseInt(rs.getString("id"))); news.setAuthor(rs.getString("author")); news.setTitle(rs.getString("title")); news.setContent("\u3000\u3000" + rs.getString("content")); Log.d("Title", news.getTitle()); list_tmp.add(news); } Collections.reverse(list_tmp); sNewsList = list_tmp; Message msg = new Message(); msg.obj = list_tmp; handler.sendMessage(msg); rs.close(); } } catch (Exception e) { e.printStackTrace(); } finally { } } }); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swip_refresh); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener(){ @Override public void onRefresh() { refreshContent(); } }); newsAdapter.setmNewList(sNewsList); Log.d("length:", String.valueOf(sNewsList.size())); Log.d(TAG, "What???"); newsTitleRecyclerView.setAdapter(newsAdapter); return view; } private void refreshContent() { @SuppressLint("HandlerLeak") final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { sNewsList = (List<News>) msg.obj; newsAdapter.addList(sNewsList); swipeRefreshLayout.setRefreshing(false); Log.d("sNewList.length : ", String.valueOf(sNewsList.size())); } }; Thread thread = null; thread = new Thread(new Runnable() { @Override public void run() { Log.d(TAG, "ppppp: ???"); try { Thread.sleep(2000); conn = MySQLConnections.getConnection("blog"); } catch (Exception e) { e.printStackTrace(); } try { String sql = "select id,author,title,content from Blog"; List<News> list_tmp = new ArrayList<News>(); if (conn != null) { stmt = conn.prepareStatement(sql); conn.setAutoCommit(false); ResultSet rs = stmt.executeQuery();//用rs接收sql语句返回的查询结果 //执行查询语句并且保存结果 while (rs.next()) { Log.d("1", "1"); News news = new News(); news.setId(Integer.parseInt(rs.getString("id"))); news.setAuthor(rs.getString("author")); news.setTitle(rs.getString("title")); news.setContent("\u3000\u3000" + rs.getString("content")); Log.d("Title", news.getTitle()); list_tmp.add(news); } sNewsList = list_tmp; Message msg = new Message(); msg.obj = list_tmp; handler.sendMessage(msg); rs.close(); } } catch (SQLException e) { e.printStackTrace(); } } }); thread.start(); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (getActivity().findViewById(R.id.new_content_layout) != null) { isTwoPane = true; } else { isTwoPane = false; } } class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> { private List<News> mNewsList = new ArrayList<News>(); private LayoutInflater mInflater; class ViewHolder extends RecyclerView.ViewHolder { TextView newsTitleText; CardView newsCardView; TextView newsContentPreView; ImageView imageViewPreView; public ViewHolder(View view) { super(view); newsCardView = (CardView) view.findViewById(R.id.item_cardview); newsTitleText = (TextView) view.findViewById(R.id.news_title); newsContentPreView = (TextView) view.findViewById(R.id.news_contentPre); imageViewPreView = (ImageView) view.findViewById(R.id.imagePreRandon); } } public NewsAdapter() { } public void setmNewList(List<News> list) { this.mNewsList = list; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.new_item, parent, false); final ViewHolder holder = new ViewHolder(view); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { News news = mNewsList.get(holder.getAdapterPosition()); if (isTwoPane) { NewsContentFragment newsContentFragment = (NewsContentFragment) getFragmentManager() .findFragmentById(R.id.news_content_fragment); newsContentFragment.refresh(news.getTitle(), news.getContent()); } else { NewsContentActivity.actionStart(getActivity(), news.getTitle(), news.getContent()); } } }); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { News news = mNewsList.get(position); holder.newsTitleText.setText(news.getTitle()); holder.newsContentPreView.setText(news.getContent().substring(0, (news.getContent().length() > 10 ? 10 : news.getContent().length() / 2))); int cnt = 1 + new Random().nextInt(11); if (cnt == 1) { holder.imageViewPreView.setImageResource(R.drawable.img_1); } else if (cnt == 2) { holder.imageViewPreView.setImageResource(R.drawable.img_2); } else if (cnt == 3) { holder.imageViewPreView.setImageResource(R.drawable.img_3); } else if (cnt == 4) { holder.imageViewPreView.setImageResource(R.drawable.img_5); } else if (cnt == 5) { holder.imageViewPreView.setImageResource(R.drawable.img_5); } else if (cnt == 6) { holder.imageViewPreView.setImageResource(R.drawable.img_6); } else if (cnt == 7) { holder.imageViewPreView.setImageResource(R.drawable.img_7); } else if (cnt == 8) { holder.imageViewPreView.setImageResource(R.drawable.img_8); } else if (cnt == 9) { holder.imageViewPreView.setImageResource(R.drawable.img_9); } else if (cnt == 10) { holder.imageViewPreView.setImageResource(R.drawable.img_10); } else if (cnt == 11) { holder.imageViewPreView.setImageResource(R.drawable.img_11); } else { holder.imageViewPreView.setImageResource(R.drawable.img_12); } } @Override public int getItemCount() { return mNewsList.size(); } } }
-
重写
onCreateView
函数承载每个子项的布局,函数中开启线程和回调函数负责于服务器服务器建立连接MySQLConnections.getConnection("blog")
,同时进行select查询;建立SwipeRefreshLayout
实现下拉刷新事件。onActivityCreated
函数判断是平板显示还是手机显示,若是平板显示,则调用帖子内容碎片,否则调用内容活动Activity。建立内容类适配器
NewsAdapter
,初始化CardView_item
的内容,同时重写onCreateViewHolder
函数,负责接收点击CardView_item跳转到帖子详情页面的事件。重写
onBindViewHolder
函数承载每个子项Holder绑定数据,函数实现了随机图片显示。swipeRefreshLayout.setOnRefreshListener
实现下拉刷新事件,重写OnRefresh
函数使用refreshContent
函数实现下拉刷新内容数据的更新。getItemCount
函数获取帖子个数。
-
-
碎片布局
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/bg_wood" /> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swip_refresh" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.RecyclerView android:id="@+id/news_title_recycle_view" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" /> </android.support.v4.widget.SwipeRefreshLayout> </RelativeLayout>
- 主页内容碎片采用RelativeLayout布局,标签设置背景图片,SwipeRefreshLayout实现下拉刷新
RecylarView
。
- 主页内容碎片采用RelativeLayout布局,标签设置背景图片,SwipeRefreshLayout实现下拉刷新
-
RecylerView
的子布局<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginLeft="12dp" android:layout_marginRight="12dp" android:layout_marginTop="2dp" app:cardCornerRadius="15dp" app:cardElevation="10dp"> <LinearLayout android:layout_width="361dp" android:layout_height="282dp" android:background="#fff" android:orientation="vertical" android:weightSum="1"> <ImageView android:id="@+id/imagePreRandon" android:layout_width="match_parent" android:layout_height="182dp" android:scaleType="centerCrop" /> <LinearLayout android:layout_width="match_parent" android:layout_height="113dp" android:layout_centerVertical="true" android:layout_margin="12dp" android:orientation="vertical"> <TextView android:id="@+id/news_title" android:layout_width="match_parent" android:layout_height="42dp" android:padding="5dp" android:textSize="18sp" android:textStyle="bold" /> <TextView android:id="@+id/news_contentPre" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp" /> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView>
RecyclerView
的子view
采用CardView布局
侧边栏
-
Head
<?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" android:layout_width="match_parent" android:layout_height="@dimen/nav_header_height" android:background="@drawable/side_nav_bar" android:gravity="bottom" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:theme="@style/ThemeOverlay.AppCompat.Dark" android:weightSum="1"> <ImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="88dp" android:paddingTop="@dimen/nav_header_vertical_spacing" android:src="@drawable/touxiang" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:text="GaoMing" android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="所爱山海间"/> </LinearLayout>
-
Menu
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/nav_camera" android:icon="@drawable/ic_menu_camera" android:title="登录" /> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="发帖" /> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="GaoMing’s Web " /> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="地图 " /> </group> <item android:title="Communicate"> <menu> <item android:id="@+id/nav_share" android:icon="@drawable/ic_menu_share" android:title="Share" /> <item android:id="@+id/nav_send" android:icon="@drawable/ic_menu_send" android:title="Send" /> </menu> </item> </menu>
帖子详情页面
-
活动核心代码
public class NewsContentActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { private ImageView imageViewContent; public static void actionStart(Context context, String newsTitle, String newsContent) { Intent intent = new Intent(context, NewsContentActivity.class); intent.putExtra("news_title", newsTitle); intent.putExtra("news_content", newsContent); context.startActivity(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_news_content); imageViewContent = (ImageView) findViewById(R.id.imageContent); int cnt = 1 + new Random().nextInt(11); if (cnt == 1) { imageViewContent.setImageResource(R.drawable.img_1); } else if (cnt == 2) { imageViewContent.setImageResource(R.drawable.img_2); } else if (cnt == 3) { imageViewContent.setImageResource(R.drawable.img_3); } else if (cnt == 4) { imageViewContent.setImageResource(R.drawable.img_5); } else if (cnt == 5) { imageViewContent.setImageResource(R.drawable.img_5); } else if (cnt == 6) { imageViewContent.setImageResource(R.drawable.img_6); } else if (cnt == 7) { imageViewContent.setImageResource(R.drawable.img_7); } else if (cnt == 8) { imageViewContent.setImageResource(R.drawable.img_8); } else if (cnt == 9) { imageViewContent.setImageResource(R.drawable.img_9); } else if (cnt == 10) { imageViewContent.setImageResource(R.drawable.img_10); } else if (cnt == 11) { imageViewContent.setImageResource(R.drawable.img_11); } else { imageViewContent.setImageResource(R.drawable.img_12); } Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); String newsTitle = getIntent().getStringExtra("news_title"); String newContent = getIntent().getStringExtra("news_content"); NewsContentFragment newsContentFragment = (NewsContentFragment) getSupportFragmentManager() .findFragmentById(R.id.news_content_fragment); newsContentFragment.refresh(newsTitle, newContent); toolbar.setTitle(newsTitle); toolbar.setSubtitle(newsTitle); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true);//左侧添加一个默认的返回图标 getSupportActionBar().setHomeButtonEnabled(true); //设置返回键可用 toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { return false; } }
- actionStart函数负责启动活动,onCreate生成活动窗口,初始化内容。
-
帖子详情页面布局
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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" android:fitsSystemWindows="true" android:orientation="vertical"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="200dp"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="@color/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/imageContent" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.9" tools:ignore="ContentDescription" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="50dp" android:theme="@style/ToolBarTheme" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:id="@+id/visibility_layout" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="15dp" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginTop="15dp" app:cardCornerRadius="10dp" app:cardElevation="10dp"> <TextView android:id="@+id/news_content" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:textSize="20sp" /> </android.support.v7.widget.CardView> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout>
- 内容布局采用
CoordinatorLayout
(Super-power FrameLayout)作为顶部布局和同时负责协调子view交互。使用AppBarLayout
响应滚动手势和ToorBar
**作为顶部子项。使用CardView
作为帖子详细内容主体。
- 内容布局采用
发布帖子页面
-
PublishPost
核心代码public class PublishPost extends AppCompatActivity { private Uri imageUri; private static int number = 0; private ImageView imageView; private EditText editText1; private EditText editText2; private EditText editText3; private Toolbar toolbar; private Button button; private final int CODE_PICK_PHOTO = 0; private final int RESULT_REQUEST_CODE = -1; private String bitmapToString= null; private String photoPath = null; private Bitmap bitmap; private String username; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_publish_post); Intent intentRec = getIntent(); username = intentRec.getStringExtra("userName"); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); final Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { return false; } }); new Thread(new Runnable() { @Override public void run() { Message msg = new Message();//message用于给handler传递参数 try { MySQLConnections.getConnection("Blog"); } catch (Exception e) { e.printStackTrace(); Log.d("TAG", " 数据操作异常"); } handler.sendMessage(msg); } }).start(); imageView = (ImageView) findViewById(R.id.imageUp); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent_gallery = new Intent(Intent.ACTION_PICK); intent_gallery.setType("image/*"); startActivityForResult(intent_gallery, CODE_PICK_PHOTO); } }); editText1 = (EditText) findViewById(R.id.upAuthor); editText2 = (EditText) findViewById(R.id.uptitle); editText3 = (EditText) findViewById(R.id.upcontent); button = (Button) findViewById(R.id.buttonPub); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String title = editText1.getText().toString(); final String author = editText2.getText().toString(); final String content = editText3.getText().toString(); new Thread(new Runnable() { @Override public void run() { try { MySQLConnections.insertIntoData(PublishPost.number++, title, author, content,bitmapToString);//调用插入数据库语句 } catch (SQLException e) { e.printStackTrace(); } } }).start(); Saving(title,content,username,bitmapToString); Intent intent = new Intent(PublishPost.this, MainActivity.class); intent.putExtra("postTitle",title); intent.putExtra("UNAME",username); setResult(RESULT_OK, intent); finish(); } }); toolbar = (Toolbar) findViewById(R.id.toolbarPub); toolbar.setTitle("发帖"); toolbar.setSubtitle("GaoMing"); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private void Saving(String title, String content, String username, String bitmapToString) { MyPost mypost = new MyPost(); mypost.setNewstitle(title); mypost.setNewscontent(content); mypost.setUsername(username); mypost.setImagePost(bitmapToString); boolean is_ok = mypost.save(); Log.d("Answer:",String.valueOf(is_ok)); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CODE_PICK_PHOTO) {//相册 imageUri= data.getData(); //获取照片路径 imageView.setImageURI(imageUri); Bitmap bitmap = null; try { bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri); bitmapToString = ImageHelper.bitmapToString(bitmap); } catch (IOException e) { e.printStackTrace(); } } } }
- onCreate函数初始化发帖活动和布局,同时开启线程连接服务器的数据库(
MySQL
)。在onActivityResult函数处理图片解析,将图片解析成字符串并保存到数据库。点击发布按钮,触发开启线程插入帖子到数据库(MySQLConnections.insertIntoData
)。
- onCreate函数初始化发帖活动和布局,同时开启线程连接服务器的数据库(
-
PublishPost布局
<?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" android:fitsSystemWindows="true" android:orientation="vertical" tools:context="cn.com.text.Activity.PublishPost"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.NoActionBar.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbarPub" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.NoActionBar.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <Button android:id="@+id/buttonPub" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="发布" /> </LinearLayout> <LinearLayout android:layout_width="368dp" android:layout_height="wrap_content" android:orientation="vertical"></LinearLayout> <include android:id="@+id/include" layout="@layout/content_publish_post" android:layout_width="wrap_content" android:layout_height="429dp" /> </LinearLayout>
WebBlog
-
此模块使用WebView实现APP内嵌网页,网页链接到我的个人博客(
GaoMing’s Web
),并且添加ToolBar
作为顶部,添加返回键。public class WebBlog extends AppCompatActivity { private Toolbar toolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_web_blog); toolbar = (Toolbar) findViewById(R.id.toolbarWeb); toolbar.setTitle("Blog"); toolbar.setSubtitle("GaoMing"); setSupportActionBar(toolbar); // toolbar.setNavigationIcon(R.drawable.ic_action_n); getSupportActionBar().setDisplayHomeAsUpEnabled(true);//左侧添加一个默认的返回图标 getSupportActionBar().setHomeButtonEnabled(true); //设置返回键可用 toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); WebView webView = (WebView) findViewById(R.id.web_view); webView.getSettings().setJavaScriptEnabled(true); webView.setWebViewClient(new WebViewClient()); webView.loadUrl("http://www.keegan.cn"); } }
登录功能
-
登录活动实现用户登录和注册,否则用户只有看帖操作,无发帖删帖更新帖子的操作。后台获取到
username
和password
,会进行验证是否为空,根据点击的按钮触发注册或者登录,如果是注册,会查询数据库是否已存在该用户,没有的话就进行插入操作,如果是点击登录,会查询数据库是否存在该用户,如果存在,则跳转登录到主页,否则弹出不存在该用户的Toast
提示。对于头像上传,要求注册时必须选择头像,否则会注册失败。public class LogActivity extends AppCompatActivity { private Button button_submit; private EditText username; private EditText password; private Button button_reg; private ImageView imageView; private final int CODE_PICK_PHOTO = 1; private Uri imageUri; private String bitmapToString = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_log); LitePal.getDatabase(); username = (EditText) findViewById(R.id.username); password = (EditText) findViewById(R.id.password); imageView = (ImageView) findViewById(R.id.userImage); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent_gallery = new Intent(Intent.ACTION_PICK); intent_gallery.setType("image/*"); startActivityForResult(intent_gallery, CODE_PICK_PHOTO); } }); button_submit = (Button) findViewById(R.id.button_submit); button_submit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if ((!TextUtils.isEmpty(username.getText()) && (!TextUtils.isEmpty(password.getText())))) { User usr = new User(); usr.setName(username.getText().toString()); usr.setPassword(password.getText().toString()); usr.setImage(bitmapToString); //检查是否有此用户 List<User> userList = DataSupport.where("name = ? and password = ?", usr.getName(),usr.getPassword()).find(User.class); if (userList.isEmpty()) { Toast.makeText(LogActivity.this, "用户名或密码错误", Toast.LENGTH_SHORT).show(); } else { Log.d("username", username.getText().toString()); Toast.makeText(LogActivity.this, "登陆成功", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(LogActivity.this, MainActivity.class); intent.putExtra("username",usr.getName()); intent.putExtra("password",usr.getPassword()); // intent.putExtra("image",bitmapToString); setResult(RESULT_OK,intent); finish(); } }else { Toast.makeText(LogActivity.this,"用户名或密码不为空",Toast.LENGTH_SHORT).show(); } } }); button_reg = (Button) findViewById(R.id.reg_button); button_reg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if ((!TextUtils.isEmpty(username.getText()) && (!TextUtils.isEmpty(password.getText())))) { final User usr = new User(); final String usrname = username.getText().toString(); final String usrpassword = password.getText().toString(); usr.setName(usrname); usr.setPassword(usrpassword); usr.setImage(bitmapToString); //检查是否有此用户 List<User> userList = DataSupport.where("name = ?", usr.getName()).find(User.class); if(bitmapToString != null){ if (userList.isEmpty()) { Thread thread = null; thread = new Thread(new Runnable() { @Override public void run() { try { MySQLConnections.insertIntoUser(usrname,usrpassword,bitmapToString); } catch (SQLException e) { e.printStackTrace(); } } }); thread.start(); try { thread.join(); }catch (Exception e){ e.printStackTrace(); } usr.save(); Toast.makeText(LogActivity.this, "注册成功", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(LogActivity.this, "重复注册,请登录", Toast.LENGTH_SHORT).show(); } }else { Toast.makeText(LogActivity.this,"请选择头像",Toast.LENGTH_SHORT).show(); } }else{ Toast.makeText(LogActivity.this,"注册用户名或密码不为空",Toast.LENGTH_SHORT).show(); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CODE_PICK_PHOTO) {//相册 imageUri= data.getData(); //获取照片路径 imageView.setImageURI(imageUri); Bitmap bitmap = null; try { bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri); bitmapToString = ImageHelper.bitmapToString(bitmap); } catch (IOException e) { e.printStackTrace(); } } } }
-
登录页面布局
<?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:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:weightSum="1" tools:context="cn.com.text.Activity.LogActivity"> <LinearLayout android:layout_width="wrap_content" android:layout_height="133dp" android:layout_weight="0.02" android:orientation="vertical"> <ImageView android:id="@+id/userImage" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" app:srcCompat="@drawable/touxiang" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="16dp" android:orientation="vertical"></LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="76dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:text="账户:" /> <EditText android:id="@+id/username" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="76dp"> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:text="密码:" /> <EditText android:id="@+id/password" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <Button android:id="@+id/button_submit" android:layout_width="match_parent" android:layout_height="69dp" android:text="登录" /> <Button android:id="@+id/reg_button" android:layout_width="match_parent" android:layout_height="69dp" android:text="注册" /> </LinearLayout>
用户中心页面
-
MyPostActivity
实现用户信息显示和已发帖显示,支持点击查看帖子详情和修改删除该贴。实现过程如下:从MainActivity
传输的intent
中获取当前登录的用户名,查询数据库MyPost
表,用户发过的帖子经过PublishPost
都已经保存了,所以此时读取到数据后,使用适配器填充ListView
的内容显示出来,增加onItem
点击事件跳转到其他页面或者选择删除该贴。public class MyPostActivity extends AppCompatActivity { private List<MyPost> mypost = new ArrayList<MyPost>(); private String username = null; private ImageView imageView; private String imageBit = ""; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_post); Intent intent = getIntent(); username = intent.getStringExtra("userName"); imageView = (ImageView) findViewById(R.id.imageUserTouxiang); List<User> userList = DataSupport.where("name = ?", username).find(User.class); if (userList.size() != 0) { imageBit = userList.get(0).getImage(); } if (imageBit.equals("")) { imageView.setImageResource(R.drawable.touxiang); } else { imageView.setImageBitmap(ImageHelper.stringToBitmap(imageBit)); } initMyPost(); MyPostAdapter myPostAdapter = new MyPostAdapter(MyPostActivity.this, R.layout.mypost_item, mypost); ListView listview = (ListView) findViewById(R.id.list_MyPost); listview.setAdapter(myPostAdapter); listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, final int position, long id) { final MyPost post = mypost.get(position); showNormalDialog(position); // Intent intent = new Intent(MyPostActivity.this,NewsContentActivity.class); // intent.putExtra("news_title", post.getNewstitle()); // intent.putExtra("news_content", post.getNewscontent()); // startActivity(intent); } }); } private void initMyPost() { mypost = DataSupport.where("username = ?", username).find(MyPost.class); } private void showNormalDialog(final int position) { //创建dialog构造器 AlertDialog.Builder normalDialog = new AlertDialog.Builder(this); //设置title normalDialog.setTitle("选择"); //设置内容 normalDialog.setMessage("你确定这样做么?"); //设置按钮 normalDialog.setPositiveButton("查看" , new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { final MyPost post = mypost.get(position); Intent intent = new Intent(MyPostActivity.this, NewsContentActivity.class); intent.putExtra("news_title", post.getNewstitle()); intent.putExtra("news_content", post.getNewscontent()); startActivity(intent); dialog.dismiss(); } }); normalDialog.setNegativeButton("更改", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { final MyPost post = mypost.get(position); Intent intent = new Intent(MyPostActivity.this, UpdataPost.class); intent.putExtra("username", username); intent.putExtra("title", post.getNewstitle()); intent.putExtra("content", post.getNewscontent()); startActivity(intent); } }); //创建并显示 normalDialog.create().show(); } }
-
用户帖子适配器
public class MyPostAdapter extends ArrayAdapter<MyPost>{ private int rescoureId; public MyPostAdapter(Context context, int textViewResourceId, List<MyPost> objects) { super(context,textViewResourceId,objects); this.rescoureId = textViewResourceId; } @NonNull @Override public View getView(int position, View convertView, ViewGroup parent) { MyPost myPost = getItem(position); View view = LayoutInflater.from(getContext()).inflate(rescoureId,parent,false); ImageView imageView = (ImageView) view.findViewById(R.id.imageViewMyPost); TextView postTitle = (TextView) view.findViewById(R.id.textViewTitle); TextView postContent = (TextView) view.findViewById(R.id.textViewContent); imageView.setImageBitmap(ImageHelper.stringToBitmap(myPost.getImagePost())); postTitle.setText(myPost.getNewstitle()); postContent.setText(myPost.getNewscontent()); return view; } }
-
-
用户中心页面布局
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout 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" android:fitsSystemWindows="true" android:orientation="vertical"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="200dp"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/toolbar_layout1" android:layout_width="match_parent" android:layout_height="match_parent" app:contentScrim="@color/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/imageUserTouxiang" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" app:layout_collapseMode="parallax" app:layout_collapseParallaxMultiplier="0.9" tools:ignore="ContentDescription" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="50dp" android:theme="@style/ToolBarTheme" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:id="@+id/visibility_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <ListView android:id="@+id/list_MyPost" android:layout_width="match_parent" android:layout_height="match_parent"></ListView> </android.support.v4.widget.NestedScrollView> </android.support.design.widget.CoordinatorLayout>
-
用户页面List子布局
<?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" android:layout_width="match_parent" android:layout_height="100dp"> <ImageView android:id="@+id/imageViewMyPost" android:layout_width="100dp" android:layout_height="match_parent" app:srcCompat="@color/Blue" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:weightSum="1"> <TextView android:id="@+id/textViewTitle" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_horizontal" android:text="TextView" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/textViewContent" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal" android:text="TextView" /> </LinearLayout> </LinearLayout> </LinearLayout> </LinearLayout>
-
地图
借助高德地图API开发包,参考博客
-
该模块借助高德地图开发包,实现APP内嵌地图和定位,查找地区等功能。
进入活动后,首先请求获取相应权限,获取成功后,调用initLocation初始化位置以及调用initMap初始化地图,根据用户位置,调用updateMapCenter使得相机视角转到用户位置。同时设计短时点击和长按点击监听事件,优化用户体验。搜索地址实现原理是获取到输入的内容,搜索位置,得到经纬度,随后调用updateMapCenter使得视角转向地址。
-
核心代码
public class MapActivity extends AppCompatActivity implements
AMapLocationListener, LocationSource,
PoiSearch.OnPoiSearchListener, AMap.OnMapClickListener, AMap.OnMapLongClickListener,
GeocodeSearch.OnGeocodeSearchListener, EditText.OnKeyListener {
//输入框
private EditText etAddress;
//城市
private String city;
//地理编码搜索
private GeocodeSearch geocodeSearch;
//解析成功标识码
private static final int PARSE_SUCCESS_CODE = 1000;
//POI查询对象
private PoiSearch.Query query;
//POI搜索对象
private PoiSearch poiSearch;
//城市码
private String cityCode = null;
//浮动按钮
private FloatingActionButton fabPOI;
//定义一个UiSettings对象
private UiSettings mUiSettings;
//定位样式
private MyLocationStyle myLocationStyle = new MyLocationStyle();
//地图控制器
private AMap aMap = null;
//位置更改监听
private OnLocationChangedListener mListener;
private MapView mapView;
private static final int REQUEST_PERMISSIONS = 9527;
//声明AMapLocationClient类对象
public AMapLocationClient mLocationClient = null;
//声明AMapLocationClientOption对象
public AMapLocationClientOption mLocationOption = null;
private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
ServiceSettings.updatePrivacyShow(this, true, true);
ServiceSettings.updatePrivacyAgree(this, true);
toolbar = (Toolbar) findViewById(R.id.toolbarMap);
toolbar.setTitle("地图");
setSupportActionBar(toolbar);
// toolbar.setNavigationIcon(R.drawable.ic_action_n);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);//左侧添加一个默认的返回图标
getSupportActionBar().setHomeButtonEnabled(true); //设置返回键可用
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
fabPOI = (FloatingActionButton) findViewById(R.id.fab_poi);
etAddress = (EditText) findViewById(R.id.et_address);
etAddress.setOnKeyListener(this);
mapView = (MapView) findViewById(R.id.map_view);
mapView.onCreate(savedInstanceState);
initLocation();
try {
initMap(savedInstanceState);
} catch (AMapException e) {
e.printStackTrace();
}
checkingAndroidVersion();
}
/**
* 检查Android版本
*/
private void checkingAndroidVersion() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Android6.0及以上先获取权限再定位
requestPermission();
} else {
//Android6.0以下直接定位
mLocationClient.startLocation();
}
}
@AfterPermissionGranted(REQUEST_PERMISSIONS)
private void requestPermission() {
String[] permissions = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
if (EasyPermissions.hasPermissions(this, permissions)) {
//true 有权限 开始定位
showMsg("已获得权限,可以定位啦!");
mLocationClient.startLocation();
} else {
//false 无权限
EasyPermissions.requestPermissions(this, "需要权限", REQUEST_PERMISSIONS, permissions);
}
}
/**
* 请求权限结果
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//设置权限请求结果
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
/**
* 初始化定位
*/
private void initLocation() {
//初始化定位
try {
mLocationClient = new AMapLocationClient(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
//设置定位回调监听
mLocationClient.setLocationListener(this);
//初始化AMapLocationClientOption对象
mLocationOption = new AMapLocationClientOption();
//设置定位模式为AMapLocationMode.Hight_Accuracy,高精度模式。
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//获取最近3s内精度最高的一次定位结果:
//设置setOnceLocationLatest(boolean b)接口为true,启动定位时SDK会返回最近3s内精度最高的一次定位结果。如果设置其为true,setOnceLocation(boolean b)接口也会被设置为true,反之不会,默认为false。
mLocationOption.setOnceLocationLatest(true);
//设置是否返回地址信息(默认返回地址信息)
mLocationOption.setNeedAddress(true);
//设置定位请求超时时间,单位是毫秒,默认30000毫秒,建议超时时间不要低于8000毫秒。
mLocationOption.setHttpTimeOut(20000);
//关闭缓存机制,高精度定位会产生缓存。
mLocationOption.setLocationCacheEnable(false);
//给定位客户端对象设置定位参数
mLocationClient.setLocationOption(mLocationOption);
}
private void showMsg(String s) {
Toast.makeText(MapActivity.this, s, Toast.LENGTH_SHORT).show();
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (aMapLocation != null) {
if (aMapLocation.getErrorCode() == 0) {
//地址
String address = aMapLocation.getAddress();
double latitude = aMapLocation.getLatitude();
double longitude = aMapLocation.getLongitude();
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("纬度:" + latitude + "\n");
stringBuffer.append("经度:" + longitude + "\n");
stringBuffer.append("地址:" + address + "\n");
Log.d("MapActivity:", stringBuffer.toString());
if (mListener != null) {
mListener.onLocationChanged(aMapLocation);
}
mLocationClient.stopLocation();
//显示浮空按钮
fabPOI.show();
//赋值
cityCode = aMapLocation.getCityCode();
//城市赋值
city = aMapLocation.getCity();
updateMapCenter(new LatLng(latitude, longitude));
} else {
//定位失败时,可通过ErrCode(错误码)信息来确定失败的原因,errInfo是错误信息,详见错误码表。
Log.e("AmapError", "location Error, ErrCode:"
+ aMapLocation.getErrorCode() + ", errInfo:"
+ aMapLocation.getErrorInfo());
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//销毁定位客户端,同时销毁本地定位服务。
mLocationClient.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView.onResume (),重新绘制加载地图
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView.onPause (),暂停地图的绘制
mapView.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState (outState),保存地图当前的状态
mapView.onSaveInstanceState(outState);
}
/**
* 初始化地图
*
* @param savedInstanceState
*/
private void initMap(Bundle savedInstanceState) throws AMapException {
mapView = (MapView) findViewById(R.id.map_view);
//在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图
mapView.onCreate(savedInstanceState);
//初始化地图控制器对象
aMap = mapView.getMap();
//设置最小缩放等级为16 ,缩放级别范围为[3, 20]
aMap.setMinZoomLevel(12);
//开启室内地图
aMap.showIndoorMap(true);
aMap.setOnMapClickListener(this);
aMap.setOnMapLongClickListener(this);
// 自定义精度范围的圆形边框颜色 都为0则透明
myLocationStyle.strokeColor(Color.argb(0, 0, 0, 0));
// 自定义精度范围的圆形边框宽度 0 无宽度
myLocationStyle.strokeWidth(0);
// 设置圆形的填充颜色 都为0则透明
myLocationStyle.radiusFillColor(Color.argb(0, 0, 0, 0));
//设置定位蓝点的Style
aMap.setMyLocationStyle(myLocationStyle);
// 设置定位监听
aMap.setLocationSource(this);
// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false
aMap.setMyLocationEnabled(true);
//实例化UiSettings类对象
mUiSettings = aMap.getUiSettings();
//隐藏缩放按钮
mUiSettings.setZoomControlsEnabled(false);
//显示比例尺 默认不显示
mUiSettings.setScaleControlsEnabled(true);
//构建GeocodeSearch对象
geocodeSearch = new GeocodeSearch(this);
geocodeSearch.setOnGeocodeSearchListener(this);
}
/**
* 通过经纬度获取地址
*
* @param latLng
*/
private void latlonToAddress(LatLng latLng) {
//位置点 通过经纬度进行构建
LatLonPoint latLonPoint = new LatLonPoint(latLng.latitude, latLng.longitude);
//逆编码查询 第一个参数表示一个Latlng,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系
RegeocodeQuery query = new RegeocodeQuery(latLonPoint, 20, GeocodeSearch.AMAP);
//异步获取地址信息
geocodeSearch.getFromLocationAsyn(query);
}
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
if (mLocationClient == null) {
mLocationClient.startLocation();//启动定位
}
}
@Override
public void deactivate() {
mListener = null;
if (mLocationClient != null) {
mLocationClient.stopLocation();
mLocationClient.onDestroy();
}
mLocationClient = null;
}
/**
* 浮动按钮点击查询附近POI
*
* @param view
*/
public void queryPOI(View view) throws AMapException {
//构造query对象
query = new PoiSearch.Query("购物", "", cityCode);
// 设置每页最多返回多少条poiitem
query.setPageSize(10);
//设置查询页码
query.setPageNum(1);
//构造 PoiSearch 对象
poiSearch = new PoiSearch(this, query);
//设置搜索回调监听
poiSearch.setOnPoiSearchListener(this);
//发起搜索附近POI异步请求
poiSearch.searchPOIAsyn();
}
@Override
public void onPoiSearched(PoiResult poiResult, int i) {
//解析result获取POI信息
//获取POI组数列表
ArrayList<PoiItem> poiItems = poiResult.getPois();
for (PoiItem poiItem : poiItems) {
Log.d("MainActivity", " Title:" + poiItem.getTitle() + " Snippet:" + poiItem.getSnippet());
}
}
@Override
public void onPoiItemSearched(PoiItem poiItem, int i) {
}
@Override
public void onMapClick(LatLng latLng) {
showMsg("点击了地图,经度:" + latLng.longitude + ",纬度:" + latLng.latitude);
latlonToAddress(latLng);
updateMapCenter(latLng);
}
@Override
public void onMapLongClick(LatLng latLng) {
showMsg("长按了地图,经度:" + latLng.longitude + ",纬度:" + latLng.latitude);
latlonToAddress(latLng);
}
@Override
public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int rCode) {
//解析result获取地址描述信息
if (rCode == PARSE_SUCCESS_CODE) {
RegeocodeAddress regeocodeAddress = regeocodeResult.getRegeocodeAddress();
//显示解析后的地址
showMsg("地址:" + regeocodeAddress.getFormatAddress());
} else {
showMsg("获取地址失败");
}
}
@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
if (i == PARSE_SUCCESS_CODE) {
List<GeocodeAddress> geocodeAddressList = geocodeResult.getGeocodeAddressList();
if (geocodeAddressList != null && geocodeAddressList.size() > 0) {
LatLonPoint latLonPoint = geocodeAddressList.get(0).getLatLonPoint();
//显示解析后的坐标
showMsg("坐标csac:" + latLonPoint.getLongitude() + "," + latLonPoint.getLatitude());
LatLng latLng = new LatLng(latLonPoint.getLatitude(), latLonPoint.getLongitude());
updateMapCenter(latLng);
}
} else {
showMsg("获取坐标失败");
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
//获取输入框的值
String address = etAddress.getText().toString().trim();
if (address == null || address.isEmpty()) {
showMsg("请输入地址");
} else {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
//隐藏软键盘
imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
// name表示地址,第二个参数表示查询城市,中文或者中文全拼,citycode、adcode
GeocodeQuery query = new GeocodeQuery(address, city);
geocodeSearch.getFromLocationNameAsyn(query);
}
return true;
}
return false;
}
/**
* 改变地图中心位置
*
* @param latLng 位置
*/
private void updateMapCenter(LatLng latLng) {
// CameraPosition 第一个参数: 目标位置的屏幕中心点经纬度坐标。
// CameraPosition 第二个参数: 目标可视区域的缩放级别
// CameraPosition 第三个参数: 目标可视区域的倾斜度,以角度为单位。
// CameraPosition 第四个参数: 可视区域指向的方向,以角度为单位,从正北向顺时针方向计算,从0度到360度
Da
//位置变更
CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
//改变位置
aMap.animateCamera(cameraUpdate);
}
}
更新帖子
-
该模块实现更新修改用户已经发布的帖子。
-
核心代码
public class UpdataPost extends AppCompatActivity { private ImageView imageView; private EditText editText1; private EditText editText2; private EditText editText3; private Toolbar toolbar; private Button button; private Connection connection; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_updata_post); imageView = (ImageView) findViewById(R.id.imageUp); editText1 = (EditText) findViewById(R.id.upAuthor); editText2 = (EditText) findViewById(R.id.uptitle); editText3 = (EditText) findViewById(R.id.upcontent); Intent intent = getIntent(); String title = intent.getStringExtra("title"); final String content = intent.getStringExtra("content"); editText2.setText(title); editText3.setText(content); button = (Button) findViewById(R.id.buttonUp); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { try{ connection = MySQLConnections.getConnection("blog"); String title1 = editText2.getText().toString(); String content1 = editText3.getText().toString(); String sql = "update Blog set title='"+title1+"' where content='"+content+"'"; PreparedStatement pst; pst = connection.prepareStatement(sql); pst.executeUpdate(); sql = "update Blog set content='"+content1+"' where title='"+title1+"'"; pst.close(); connection.close(); }catch (Exception e){ e.printStackTrace(); } } }).start(); } }); } }
数据库设计
-
News
public class News { private String title; private String content; private String author; private int id; private String image; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } }
-
MyPost
public class MyPost extends DataSupport { private String username; private String newstitle; private String newscontent; private String imagePost; public String getNewstitle() { return newstitle; } public void setNewstitle(String newstitle) { this.newstitle = newstitle; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getNewscontent() { return newscontent; } public void setNewscontent(String newscontent) { this.newscontent = newscontent; } public String getImagePost() { return imagePost; } public void setImagePost(String imagePost) { this.imagePost = imagePost; } }
-
User
public class User extends DataSupport { private String name; private String password; private String image; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getImage() { return image; } public void setImage(String image) { this.image = image; } }
工具包类
-
ImageHelper
- 实现Bitmap和String的转换
public class ImageHelper { public static Bitmap stringToBitmap(String string) { // 将字符串转换成Bitmap类型 Bitmap bitmap = null; try { byte[] bitmapArray; bitmapArray = Base64.decode(string, Base64.DEFAULT); bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length); } catch (Exception e) { e.printStackTrace(); } return bitmap; } //把bitmap转换成字符串 public static String bitmapToString(Bitmap bitmap) { String string = null; ByteArrayOutputStream btString = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, btString); byte[] bytes = btString.toByteArray(); string = Base64.encodeToString(bytes, Base64.DEFAULT); return string; } }
-
MySQLConnection
- 实现服务器数据库的连接以及数据库的操作(导入MySqlConnector包)。
public class MySQLConnections { public static int number = 0; private String driver = ""; private String dbURL = ""; private String user = ""; private String password = ""; private static MySQLConnections connection = null; private static Connection conn = null; private static PreparedStatement stmt = null; private static List<News>newsList = new ArrayList<News>(); private MySQLConnections() throws Exception { driver = "com.mysql.jdbc.Driver"; dbURL = "jdbc:mysql://182.92.153.231:3306/blog"; user = "lkk"; password = "123456"; System.out.println("dbURL:" + dbURL); } public static Connection getConnection(String dbName) { Connection conn = null; if (connection == null) { try { connection = new MySQLConnections(); } catch (Exception e) { e.printStackTrace(); return null; } } try { Class.forName(connection.driver); conn = DriverManager.getConnection(connection.dbURL, connection.user, connection.password); } catch (Exception e) { e.printStackTrace(); } return conn; } public static int insertIntoData(final int id, final String author,final String title,final String content,String image) throws SQLException {//增加数据 Connection conn = null; conn = getConnection("blog");//填写需要连接的数据库的名称,我是用的是person //使用DriverManager获取数据库连接 Statement stmt = conn.createStatement(); //使用Connection来创建一个Statment对象 String sql = "insert INTO Blog (id,author,title,content,image)VALUES('"+id+"','"+author+"','"+title+"','"+content+"','"+image+"')"; return stmt.executeUpdate(sql);//返回的同时执行sql语句,返回受影响的条目数量,一般不作处理 } public static List<News> querycol() throws SQLException {//读取某一行 //加载数据库驱动 final Handler handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { //下一步执行的代码 return false; } }); new Thread(new Runnable() { @Override public void run() { Message msg = new Message();//message用于给handler传递参数 try { //调用连接数据库方法的代码 conn = MySQLConnections.getConnection("Blog"); } catch (Exception e) { e.printStackTrace(); Log.d("TAG", " 数据操作异常"); }handler.sendMessage(msg); try { String sql = "select * from Blog"; if(conn != null){ stmt = conn.prepareStatement(sql); conn.setAutoCommit(false); ResultSet rs =stmt.executeQuery();//用rs接收sql语句返回的查询结果 //执行查询语句并且保存结果 while (rs.next()){ News news = new News(); news.setId(Integer.parseInt(rs.getString("id"))); news.setAuthor(rs.getString("author")); news.setTitle(rs.getString("title")); news.setContent(rs.getString("content")); news.setImage(rs.getString("image")); newsList.add(news); } rs.close(); } sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } }).start(); return newsList; } public static int insertIntoUser(String name, String password, String image) throws SQLException { Connection conn = null; conn = getConnection("blog");//填写需要连接的数据库的名称,我是用的是person //使用DriverManager获取数据库连接 Statement stmt = conn.createStatement(); //使用Connection来创建一个Statment对象 String sql = "insert INTO User (name,password,image)VALUES('"+name+"','"+password+"','"+image+"')"; return stmt.executeUpdate(sql); } }
项目Gitee
- 地址:https://gitee.com/lkksxxdxxd/android