紧接着上一篇博客,接着复习Android的知识点。一个暑假的时间自己在学车,即使每天都看了一点点知识,但是效率不高,现在需要在图书馆里给他补起来!
第五个知识点:如何利用Handle处理
在默认情况下,Android所有的操作都在主线程中进行,对一些耗时的操作,必须开启一个子线程来处理。这就需要用到Handle,通俗点来说,就是在子线程中获取数据,数据获取完之后,handle发送“数据已经获得的消息”,然后在主线程中把这些数据在组件中展示出来。
下面是具体的用法(类似与一种框架):
首先开启一个子线程,像是从数据库中取数据,进行网络需求下载数据等等都需要进行开启子线程,
子线程中存在多种消息(多种情况)
new Thread(){
@Override
public void run() {
msg = Message.obtain();
msg.what = "0101"
handler.sendMessage(msg);
}
}.start();
private Handler handler = new Handler(){
public void handleMessage(Message msg){
switch (msg.what){
case 0101:
//执行相应的操作
break;
case 0102:
//执行相应的操作
break;
default:
}
}
}
子线程中只存在一种消息:
new Thread(){
@Override
public void run() {
handler.sendEmptyMessage(0);
}
}.start();
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
lv_contact_items.setAdapter(new ContactAdapter());
}
};
Handle的使用框架就是上面的两种方式。
第六个知识点:SQLlite的使用
使用这个知识点的时候,我是真正的感觉到了书上的知识毕竟是书上的,自己写的代码是自己的写的,这还得从实践中得到真知啊!
三步走使用sqlite
第一步首先建立DBHelper,建造数据库:
public class BlackNumberDBHelper extends SQLiteOpenHelper {
public BlackNumberDBHelper(Context context) {
super(context,"blacknumber.db",null,1);
}
/**
* 创建一个数据库表
* @param db
* 包含三个字段 id phonenumber model
* model 0 全部拦截 1 电话拦截 2 短信拦截
*/
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table number1 (id Integer primary key AUTOINCREMENT,phonenumber varchar(20),model varchar(2) )");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
构建这个类,首先要继承SQLiteOpenHelper类,然后最重要的就是构造方法,使用父类的构造方法,传入一个上下文参数,第二个是数据库名称,其他两个不重要,照着写就行。
第二个方法是构建一张表,这就能用到之前学的数据库的知识了,注意点就是上面的表名就是number1,在编写第二步类的时候,要与这个表名保持一致才行!!!
然后就可以执行第二步了;
第二步:写BDDao
我觉得这个类中最主要就是构造方法,忽然觉得有一种豁然开朗的感觉,非常的舒服!
public class BlackNumberDao {
private BlackNumberDBHelper db;
private String tablename = "number1";
//写在构造器中 只要对象new 出来 数据库就会自动创建
public BlackNumberDao(Context context) {
db = new BlackNumberDBHelper(context);
}
public List<BlackNumberInfo> QueryAll(){
SQLiteDatabase readableDatabase = db.getReadableDatabase();
Cursor query = readableDatabase.query(tablename, null, null, null, null, null, null);
while (query.moveToNext()){
String phone = query.getString(1);
blackNumberInfo.setPhonenumber(phone);
String model = query.getString(2);
}
query.close();
readableDatabase.close();
return list;
}
/**
* 往数据库中添加数据
*
* @param phone 电话
* @param model 拦截模式
*/
public Boolean Add(String phone, String model) {
SQLiteDatabase writableDatabase = db.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("phonenumber", phone);
Log.d("测试", "Add: "+phone);
contentValues.put("model", model);
//如果insert的值位-1 则说明插入失败
long insert = writableDatabase.insert(tablename, null, contentValues);
writableDatabase.close();
//如果插入进数据库 则返回true
if (insert != -1) {
return true;
} else {
return false;
}
}
/**
* 删除数据库中的数据
*
* @param phone
* @return
*/
public Boolean Delete(String phone) {
SQLiteDatabase writableDatabase = db.getWritableDatabase();
//返回值为0 说明没有删除数据
int delete = writableDatabase.delete(tablename, "phonenumber=?", new String[]{phone});
writableDatabase.close();
if (delete != 0) {
return true;
} else {
return false;
}
}
/**
* 更改拦截模式
*
* @param phone
* @param model
* @return
*/
public Boolean Update(String phone, String model) {
SQLiteDatabase writableDatabase = db.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("model", model);
int update = writableDatabase.update(tablename, contentValues, "phonenumber=?",new String[]{phone});
writableDatabase.close();
if (update==0){
return false;
}else {
return true;
}
}
/**
* 查找数据的操作 主要是查找phone的model
* @param phone
* @return
*/
public String Query(String phone){
String model = null;
SQLiteDatabase readableDatabase = db.getReadableDatabase();
Cursor query = readableDatabase.query(tablename, new String[]{"model"}, "phonenumber=?", new String[]{phone}, null, null, null);
while (query.moveToNext()){
model = query.getString(0);
}
return model;
}
}
这个类中有个DBHelper的实例变量,恰好在构造方法中有初始化了这个实例变量,这个就能使用这个数据库了,记住这个上下文参数也要传进入,这样就可以利用这些db进行增删改查了。具体的使用方法基本就是上面这几种了。更新,删除,插入如果失败返回的是-1,因此只要判断返回的是不是-1即可。查询函数是比较难写的一个方法,因为他的参数特别多,需要加以记忆!还有就是这个SQL语句很简单,并没有涉及到很难得查询,因此那更难得查询应该怎样写,这还是一个自己没有尝试得地方。
第三步:在Activity中掉用这个DBdao即可使用:
BlackNumberDao blackNumberDao = new BlackNumberDao(getApplicationContext());
Boolean add = blackNumberDao.Add(phone, model);
这样就完成了数据库的使用,现在回想起来,使用这个数据库也挺简单的,每次看一遍代码,自己都会有新的体会!
第七个知识点:Fragment的使用
这个知识点的内容也是非常中要的,具体的重要原理咱不讲,咱只说如何使用。
用一个小小的Demo来说明如何使用Fragment:像微信的主页面那样,按下面的一张图片就跳转到一个界面,可以来回的跳转。
在做这个Demo的时候,我认为Fragment还不容易吗!!不就是利用replace和add等方法加上去不就行了,结果是,我居然搞了2个多小时,把我的激情都给搞没有了,再一次被编程打击了!!但是最终的结果还好,自己完成了这个小小的需求,自己遇到了三个错误,搞了半天。
错误一:自己把自己的Activity页面搞混了
这是一个小错误,我觉得是因为自己好多天没有学习Android所导致的,最近在写JavaWeb的东西,这个问题不大,自己看界面的错误就解决了
错误二:对于import android.app.Fragment和android.support.v4.app.Fragment的问题
我在Fragment中使用android.support.v4.app.Fragment,结果在Activity中使用import android.app.Fragment,结果是一致报错,我心想,我自己不会这么白痴吧,这点知识还能打错了,自己找了半天,才解决了这个问题,具体他们两个的区别点击这篇博客看看吧,一定要保持一致的包,这样才不会出错。
错误三:java.lang.IllegalStateException: commit already called报这个错误
到了最后了,我心想该没有错了吧,结果又给我提个错,结果百度一搜,答案就出来了,原因如下:
是因为你的ft事务是全局的变量,只能commit一次。所以用两个局部ft事务去做commit即可。
所以说,一个ft只能执行一次commit操作,而且,一定要保证ft为局部变量,否则可能会抛出这个错误,
还有一个最最最最最重要的错误,如下:下面两段代码中,这三句的
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = null;
的作用范围是一样的吗????
private void initEvent() {
View.OnClickListener pagechange = new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = null;
switch (v.getId()) {
case R.id.ib_home_home:
fragment = new HomeFragment();
break;
case R.id.ib_home_check:
fragment = new CheckFragment();
break;
case R.id.ib_home_myinfo:
fragment = new MyinfoFragment();
break;
default:
break;
}
ft.replace(R.id.home_content_fragment, fragment);
ft.commit();
}
};
private void initEvent() {
View.OnClickListener pagechange = new View.OnClickListener() {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
Fragment fragment = null;
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.ib_home_home:
fragment = new HomeFragment();
break;
case R.id.ib_home_check:
fragment = new CheckFragment();
break;
case R.id.ib_home_myinfo:
fragment = new MyinfoFragment();
break;
default:
break;
}
ft.replace(R.id.home_content_fragment, fragment);
ft.commit();
}
};
答案是不一样的,第二种代码就会报上面那种错。(我认为第二种方式ft已经是局部变量了,但是他不是,必须是onClick种的变量才是局部变量)具体的代码我就不展示了,毕竟是一个小小的Demo,不难,但是易错点多,我辈尚需努力啊!
第八个知识点,也是我认为最难理解的知识点:ListView的使用
ListView用到是会用,但是对于一些具体的细节问题,需要进步的去理解,去慢慢的琢磨
下面就先利用简单的list做个简单的demo,再利用很多的数据做一个进阶版的Demo,就是一个用系统的,一个用自定义的item
刚写好代码就遇到一个错误,这个错误是这样的Error running HomeActivity: The activity must be exported or contain an intent-filte
怎么都运行不了了,然后到网上一搜,发现我在运行一个activity界面,并不是一个app程序:如下所示:
listview的使用也分三个步骤:
第一:首先在布局里声明ListView组件:
<ListView
android:id="@+id/lv_listview_demo1"
android:divider="#000"
android:dividerHeight="5dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
divider属性是指两个item之间的边框线的颜色 ,dividerHeight是指边框线的高度
第二步:初始化对象
这一步很简单,就是find viewbyid之类的步骤
第三步:直接利用SetAdapter就行了:
private String [] data = new String[]{"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa",
"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa"
};
private ListView lv_listview_demo1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initData();
initAnimation();
initEvent();
}
private void initView() {
setContentView(R.layout.activity_listview1);
lv_listview_demo1 = findViewById(R.id.lv_listview_demo1);
}
private void initData() {
lv_listview_demo1.setAdapter(new ArrayAdapter<String>( Listview1Activity.this,android.R.layout.simple_list_item_1,data) );
}
private void initAnimation() {
}
private void initEvent() {
lv_listview_demo1.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String res = parent.getItemAtPosition(position).toString();
Toast.makeText(Listview1Activity.this,res,Toast.LENGTH_SHORT).show();
}
});
}
这种方式的ListView是最简单的,不过也是没有进行优化的。具体的优化方式就是我不太理解的地方(开发者为什么都知道这个bug了,为什么还是不在最基本的源码部分修改这个bug呢?)
接下来就是自定义一个listview了,开始自己写吧!
在这就只给一部分代码:
private ListView lv_listview_demo2;
private String [] data = new String[]{"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa",
"aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa","aaa"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
initData();
initAnimation();
initEvent();
}
private void initView() {
setContentView(R.layout.activity_listview2);
lv_listview_demo2 = findViewById(R.id.lv_listview_demo2);
}
private void initData() {
lv_listview_demo2.setAdapter(new DemoAdapter());
}
private void initAnimation() {
}
private void initEvent() {
}
public class DemoAdapter extends BaseAdapter{
@Override
public int getCount() {
return data.length;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View inflate = View.inflate(getApplicationContext(), R.layout.listview_item, null);
TextView title = inflate.findViewById(R.id.title);
TextView content = inflate.findViewById(R.id.content);
title.setText(data[position]);
content.setText(data[position]);
return inflate;
}
}
像这种级别的代码,一看就会,不过对于listview,这些都不行,还得学会他的优化方式,但是这篇博客,不说关于优化的方式,因为自己还没有学的很透彻,等我理解了具体的操作方式,我准备专门写一篇博客讲述为什么要优化listview。
这篇博客就到这吧,写了一下午的博客和代码,有点累了,不过很充实,我喜欢这种感觉!