ActionBar使用
最后更新于:2022-04-01 14:43:53
安卓SDK11.0版本以上就支持Action Bar了。所谓的Action Bar实际上就是代替以前的标题栏的存在,如果设置了那就会在Activity的顶部显示,我们可以在AndroidManifest.xml里面这样显示声明ActionBar:android:theme="@android:style/Theme.Holo"
一般情况下,我们需要在onCreateOptionsMenu里面把自定义的视图加载进去:
~~~
@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;
}
~~~
然后可以知道我们加载了一个R.menu.main的视图,这个视图是这样写的:
~~~
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings"/>
<item
android:id="@+id/writeArticle"
android:icon="@drawable/ic_launcher"
android:showAsAction="always"
android:title="写文章">
</item>
</menu>
~~~
第一个item是菜单,第二个item是我自定义的一个项。
其中要注意两个地方:
1)showAsAction:设置该条目什么时候显示在ActionBar里面
这个属性可接受的值有:
1、always:这个值会使菜单项一直显示在Action Bar上。
2、ifRoom:如果有足够的空间,这个值会使菜单项显示在Action Bar上。
3、never:这个值使菜单项永远都不出现在Action Bar上。
4、withText:这个值使菜单项和它的图标,菜单文本一起显示。
2)orderInCategory:actionbar里每个item的优先级,值越大优先级越低,actionbar地方不够就会放到overflow中。
那么设置了item之后怎么监听点击事件呢?
其实item点击之后会触发Activity里面的onOptionsItemSelected回调函数,下面是我处理的代码:
~~~
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.writeArticle:
Toast.makeText(this, "write", 0).show();
break;
default:
Toast.makeText(this, "null", 0).show();
break;
}
return super.onOptionsItemSelected(item);
}
~~~
这样设置我通过点击自定义的item writeArticle就能够Toast一条信息了。
最后是完整的Activity代码,还是贴出来吧,很简单。
~~~
package com.example.luntan;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@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) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.writeArticle:
Toast.makeText(this, "write", 0).show();
break;
default:
Toast.makeText(this, "null", 0).show();
break;
}
return super.onOptionsItemSelected(item);
}
}
~~~
Dialog学习笔记
最后更新于:2022-04-01 14:43:50
感觉对Dialog了解很少,今天看书学习一下,顺便更新一下blog(吐槽一下,最近几天都很忙没上blog)。。
1)自定义Dialog layout
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-13_575e8e163c3b1.jpg)
上面的Dialog界面采用了自己的layout,下面是代码:
~~~
package com.example.androiddialog;
import android.os.Bundle;
import android.app.Activity;
import android.app.Dialog;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
final Dialog dialog = new Dialog(MainActivity.this);
dialog.setTitle("标题");
dialog.setContentView(R.layout.dialog_layout);
dialog.show();
Button button = (Button) dialog.findViewById(R.id.bt);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
}
});
}
@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;
}
}
~~~
下面是自定义的layout代码:
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DIALOG" />
<Button
android:id="@+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消" />
</LinearLayout>
~~~
2)AlertDialog
AlertDialog是常用的Dialog实现之一,要构造AlertDialog界面,需要用到一个新的AlertDialog.Buider对象。
下面是实现界面:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-13_575e8e1661a9a.jpg)
下面是代码:
~~~
package com.example.androiddialog;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("标题");
dialog.setMessage("message");
dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "点击了确认", 0).show();
}
});
dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
dialog.show();
}
});
}
@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;
}
}
~~~
点击确认和取消按钮都有相应的响应事件。
需要注意的是,点击一次按钮在响应事件之后都会关闭对话框。在上面按下返回键不会关闭对话框的,如果想要返回键关闭对话框可以使用setOnCancleListener方法附上一个OnCancelListener来响应
3)DataPickerDialog
用户用这个Dialog选择时间,构造函数中有一个onDateSet函数通知Activity日期已经被设定
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-13_575e8e169301d.jpg)
下面是代码:
~~~
package com.example.androiddialog;
import android.os.Bundle;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
DatePickerDialog dialog = new DatePickerDialog(
MainActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
// TODO Auto-generated method stub
Toast.makeText(
MainActivity.this,
year + "年" + monthOfYear + "月"
+ dayOfMonth + "日", 0).show();
}
// 注意:月份是从0开始的,所以要-1
}, 2014, 7, 19);
dialog.show();
}
});
}
@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;
}
}
~~~
4)TimePickerDialog
TimePickerDialog的用法和上面的差不多,只不过这个是设置时间的上面是设置日期的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-13_575e8e16b3663.jpg)
下面是代码:
~~~
package com.example.androiddialog;
import android.os.Bundle;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TimePicker;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
TimePickerDialog dialog = new TimePickerDialog(MainActivity.this, new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, hourOfDay+"分"+minute+"秒", 0).show();
}
}, 12, 12, true);
dialog.setTitle("时间");
dialog.show();
}
});
}
@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;
}
}
~~~
5)AlertDialog中的setView
前面忘记说一点了,通过setView函数可以在AlertDialog中添加View,比如EditText ,TextView等等的,这样定制性会很高,又符合Dialog简单窗口的特性。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-13_575e8e16d6f5b.jpg)
下面是代码:
~~~
package com.example.androiddialog;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new AlertDialog.Builder(MainActivity.this).setTitle("titile")
.setView(new EditText(MainActivity.this)).setPositiveButton("确认", new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "选择了确定", 0).show();
}
}).show();
}
});
}
@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;
}
}
~~~
6)ProgressDialog
ProgressDialog是用来显示进度条的,默认分为圆形和水平两种,下面演示水平的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-13_575e918df08a4.jpg)
下面是代码:
~~~
package com.example.androiddialog;
import android.os.Bundle;
import android.app.Activity;
import android.app.ProgressDialog;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
ProgressDialog dialog = new ProgressDialog(MainActivity.this);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setTitle("title");
dialog.setMessage("message");
// 设置点击其他部分会不会取消Dialog
dialog.setCanceledOnTouchOutside(false);
// 返回键能否取消
dialog.setCancelable(false);
dialog.setMax(50);
dialog.incrementProgressBy(20);
dialog.incrementProgressBy(2);
dialog.show();
}
});
}
@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;
}
}
~~~
安卓隐式Intent启动Activity和BroadcastReceiver若干注意点
最后更新于:2022-04-01 14:43:48
隐式调用Activity和BroadcastReceiver调用方法之前已经介绍过了。今天只是来做下4个实验,假设B通过Intent隐式调用A,如果A没有一个Activity有
~~~
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
~~~
这个设置会怎么样?
下面是Activity的实验:
~~~
package com.example.intenta;
import android.app.Activity;
import android.os.Bundle;
public class ShowType extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.show_type);
}
}
~~~
上面是A的JAVA代码,下面是A的XML代码,只是定义了一个TextView
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="40sp"
android:text="启动A"
/>
</LinearLayout>
~~~
~~~
package com.example.intenta;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@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;
}
}
~~~
上面是A的另外一个Activity的代码(A有两个Activity,通过控制在这一个Acticity在manifest是否设置android.intent.action.MAIN等条目来控制实验变量)
~~~
<activity android:name="com.example.intenta.ShowType" >
<intent-filter>
<action android:name="com.mytest.IntentA" >
</action>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.mytest.startA" />
</intent-filter>
</activity>
~~~
这是A的IntentFilter
~~~
package com.example.intentb;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setAction("com.mytest.IntentA");
intent.addCategory("com.mytest.startA");
startActivity(intent);
}
});
}
@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;
}
}
~~~
这里是B的JAVA代码,通过点击按钮来隐式调用A
Activity实验结果:
1)在有设置的情况下:能够正常通过B启动A
2)没有设置的情况下:能够正常通过B启动A
实验结果分析:
Activity的Intent启动过程不受是否设置
~~~
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
~~~
下面是BroadcastReceiver的实验:
代码和上面基本类似,下面只放出A中BroadcastReceiver的代码:
~~~
package com.example.intenta;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
public class ShowType extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(context, "启动A...", Toast.LENGTH_LONG).show();
}
// @Override
// protected void onCreate(Bundle savedInstanceState) {
// // TODO Auto-generated method stub
// super.onCreate(savedInstanceState);
// setContentView(R.layout.show_type);
// }
}
~~~
实验结果:
1)在有设置的情况下:B能够正常通过Intent启动A的BroadcastReceiver
2)在没有设置的情况下:失败
最后实验结果:
~~~
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
~~~
如果A中没有一个Activity有这段IntentFilter设置,那么通过Intent,B能够启动A的Activity但是不能启动A的BroadcastReceiver。
安卓软引用解决图片OOM问题
最后更新于:2022-04-01 14:43:46
软引用是解决加载大量图片OOM问题的一个很好的思路,之前介绍了用LRUCACHE的策略了,这两个策略应该说是缓存的最好的两个策略吧。
系统在GC的时候会检查软引用,在内存不足的时候会回收掉只有软引用的对象(这里存在一些疑惑,回收是所有只有软引用的对象都回收呢还是按照某些策略回收其中的一些呢?我还要研究下)。
下面这个应用的目标是做动画效果,原本想用安卓里面的逐帧动画来做的,但是发现内存是个很大的问题,而自己对动画这部分又不是很了解,所以最后还是设计一个定时器70MS刷一次算了。用了软引用队列保存图片资源,但是命中率不是很好,还需要改进一下。
下面是代码:
~~~
package com.example.anima;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView iv;
private ArrayList<SoftReference<Drawable>> drawables;
// 在timer中更新
private int drawIndex = -1;
private int drawAmount = 0;
private ArrayList<Integer> picId;
private Timer timer = null;
private Handler handler = new Handler() {
@SuppressLint("NewApi")
public void handleMessage(android.os.Message msg) {
Drawable drawable = drawables.get(drawIndex).get();
System.out.println(drawIndex+" " +(drawable==null));
iv.setBackground(drawable);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initPicName();
iv = (ImageView) findViewById(R.id.aniPic);
drawables = new ArrayList<SoftReference<Drawable>>();
timer = new Timer(true);
timer.scheduleAtFixedRate(task, 0, 70);
}
/**
* 在计数器里面进行标号的更新和图片软引用的处理
*/
private TimerTask task = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
drawIndex ++;
drawIndex %= drawAmount;
SoftReference<Drawable> ref = null;
try {
ref = drawables.get(drawIndex);
Drawable refDraw = ref.get();
if (refDraw == null) {
System.out.println("fffffffffffffff");
Drawable drawable = getResources().getDrawable(picId.get(drawIndex));
ref = new SoftReference<Drawable>(drawable);
drawables.set(drawIndex, ref);
}
} catch (IndexOutOfBoundsException e) {
// TODO Auto-generated catch block
Drawable drawable = getResources().getDrawable(picId.get(drawIndex));
ref = new SoftReference<Drawable>(drawable);
drawables.add(ref);
}finally {
Message msg = Message.obtain();
handler.sendMessage(msg);
}
}
};
/**
* 初始化picNames,也就是获得动画每一帧图片资源名称
*/
private void initPicName() {
picId = new ArrayList<Integer>();
picId.add(R.drawable.man1);
picId.add(R.drawable.man2);
picId.add(R.drawable.man3);
picId.add(R.drawable.man4);
picId.add(R.drawable.man5);
picId.add(R.drawable.man6);
picId.add(R.drawable.man7);
picId.add(R.drawable.man8);
picId.add(R.drawable.man9);
picId.add(R.drawable.man10);
drawAmount = picId.size();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
timer.cancel();
super.onPause();
}
}
~~~
DrawerLayout实现简单的侧滑功能
最后更新于:2022-04-01 14:43:44
项目要实现类似于网易新闻客户端的侧滑拉出菜单的功能,搜了好些资料,有下面的三种方法:
1)自定义viewgroup
2)导入开源项目slidingmenu_library
3)采用V4包的组件DrawerLayout
第三种方法是最方便快捷的了,虽然第三种方法不能很好地支持低版本安卓手机,但是因为我们也没有这种需求,所以最后我还是决定采用DrawerLayout。不过第一种方法是最好的(虽然从开发效率上来说不是),有空自己还得要学一下自己造轮子。
DrawerLayout的xml:
~~~
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="open" />
</FrameLayout>
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:background="#FFB5C5"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:textSize="20sp" >
</TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
android:textSize="20sp" >
</TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
android:textSize="20sp" >
</TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="4"
android:textSize="20sp" >
</TextView>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
~~~
其中包裹了2个或者以上的view,需要注意的是第一个view是主页面的view,后面的才是侧滑出页面的view。主页面view的宽高要写成
~~~
android:layout_width="match_parent"
android:layout_height="match_parent"
~~~
因为在没有侧滑的时候是要包裹父view窗体的。
而在侧滑出的页面的view要设置layout_gravity的值指明是向左滑出还是向右滑出。
下面的Activity,比较简单:
~~~
package com.example.drawerlayout;
import android.os.Bundle;
import android.app.Activity;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 按钮按下,将抽屉打开
mDrawerLayout.openDrawer(Gravity.LEFT);
}
});
}
}
~~~
直接调用openDrawer就可以拉开侧滑页面了。需要注意的是后面也要写明侧滑方向(LEFT),并且与前面xml标明的方向要一致,不然可能会出错。
DrawerLayout还有很多很好用的API,我还在研究中所以就不贴出来了。
选项卡样式的fragment
最后更新于:2022-04-01 14:43:41
Fragment其实就是一个小的Activity,他的生命周期和Activity差不多。Fragment概念的提出就是因为平板编程的需要,Fragment使得UI设计得以模块化,平板等大屏设备的UI设计得到了很好的技术支持。然而Fragment概念的提出是因为大屏UI设计的需求,但是使用并不局限于平板设计。下面这坨代码(的确是坨。。)实现的是一个类似微信的选项卡切换界面的功能,全局只有一个Activity,真正改变的只是Fragment。
Activity:
~~~
package com.example.myfragment;
import android.os.Bundle;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener {
private TextView tv1;
private TextView tv2;
private TextView tv3;
private TextView tv4;
private FragmentManager fm;
private Fragment1 fragment1;
private Fragment2 fragment2;
private Fragment3 fragment3;
private Fragment4 fragment4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = (TextView) findViewById(R.id.text1);
tv2 = (TextView) findViewById(R.id.text2);
tv3 = (TextView) findViewById(R.id.text3);
tv4 = (TextView) findViewById(R.id.text4);
tv1.setOnClickListener(this);
tv2.setOnClickListener(this);
tv3.setOnClickListener(this);
tv4.setOnClickListener(this);
fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fragment1 = new Fragment1();
fragment2 = new Fragment2();
fragment3 = new Fragment3();
fragment4 = new Fragment4();
ft.replace(R.id.content, fragment1);
ft.commit();
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
FragmentTransaction ft = fm.beginTransaction();
switch (v.getId()) {
case R.id.text1:
ft.replace(R.id.content, fragment1);
break;
case R.id.text2:
ft.replace(R.id.content, fragment2);
break;
case R.id.text3:
ft.replace(R.id.content, fragment3);
break;
case R.id.text4:
ft.replace(R.id.content, fragment4);
break;
}
ft.commit();
}
}
~~~
activity xml:
~~~
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Text1" />
<TextView
android:id="@+id/text2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Text2" />
<TextView
android:id="@+id/text3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Text3" />
<TextView
android:id="@+id/text4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Text4" />
</LinearLayout>
<RelativeLayout
android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</RelativeLayout>
</LinearLayout>
~~~
fragment1:
~~~
package com.example.myfragment;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1, null);
return view;
}
}
~~~
f1 xml:
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fragment1"
android:textSize="20dp" >
</TextView>
</LinearLayout>
~~~
fragment2到fragment4的定义方式和fragment1类似,这里就不贴出来了。
安卓JSON解析初步探讨
最后更新于:2022-04-01 14:43:39
因为项目中要用到JSON解析,所以就学习了一下。有关于安卓JSON的教程网上有很多,来来去去都是这几个类的介绍。其实这一篇文章甚至也不能算是一篇学习心得,只能理解为一份备忘录。
下面是我要解析的JSON格式:
~~~
[{"file_id": "13", "filename": "grub2\u6559\u7a0b.pdf"}, {"file_id": "14", "filename": "demo.pdf"}]
~~~
这里面要用JSONArray来存储数组,然后用JSONObject获得里面的每一个键值对。
因为是随便写写,所以不免很多纰漏,listview的优化也没写。代码纯当笑话。
~~~
package com.example.getpdflist;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
/**
* 该类从服务器获取PDF文件名称和ID关系,获取方式:JSON
*
* @author USER
*
*/
public class MainActivity extends Activity {
// 网页传递JSON信息路径
private final String JSON_PATH = "http://sysucs.org:8080/list";
// 获得的JSON字符串内容
private StringBuilder str;
// 从JSON获取的名字与ID对应关系
private ArrayList<Pair> jsonContent;
private ListView lv;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
showListView();
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.lv);
jsonContent = new ArrayList<Pair>();
str = new StringBuilder();
new Thread(new getPdfThread()).start();
}
/**
* 该函数将stringBuilder转化为map对应关系
*/
private void handleJson() {
try {
JSONArray jsonArray = new JSONArray(str.toString());
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String name = jsonObject.getString("filename");
int id = jsonObject.getInt("file_id");
Pair pair = new Pair(name, id);
jsonContent.add(pair);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 为list设置内容
private void showListView() {
lv.setAdapter(new myAdapter());
}
private class myAdapter extends BaseAdapter {
@Override
public int getCount() {
// TODO Auto-generated method stub
return jsonContent.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Pair pair = jsonContent.get(position);
System.out.println(pair.id + " " + pair.name);
convertView = View.inflate(MainActivity.this, R.layout.item, null);
TextView name = (TextView) convertView.findViewById(R.id.file_name);
TextView id = (TextView) convertView.findViewById(R.id.file_id);
name.setText(pair.name);
id.setText(String.valueOf(pair.id));
return convertView;
}
}
/**
* 存储name id对的类
*
* @author Hehyu
*
*/
private class Pair {
public String name;
public int id;
public Pair(String name, int id) {
this.name = name;
this.id = id;
}
}
public class getPdfThread implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(JSON_PATH);
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
InputStream is = httpEntity.getContent();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = is.read(buffer)) != 0) {
String t = new String(buffer, 0, len);
str.append(t);
}
} catch (Exception e) {
e.printStackTrace();
}
// 获取JSON对应关系
handleJson();
Message msg = Message.obtain();
handler.sendMessage(msg);
}
}
}
~~~
安卓多线程下载
最后更新于:2022-04-01 14:43:37
上周时间基本都在做自己的项目了,所以很少来写博客了。今天上来更新下博客,内容是多线程下载,以冒一下泡。
多线程在一定程度下增快了下载的速度,但是最终下载速度还是决定于你的带宽,2G/3G网络下“带宽”这个词是否可以忽略?。。
其实如果文章名字改为多线程断点下载可能会屌一点,不过多线程下载和多线程断点下载的区别几乎只在于while循环的时候是否记录已经下载的文件块,断点下载记录了已经下载的文件块所以下次下载就能从断点开始下载(避免了重复下载),而下面这个代码没有记录,所以不具备这个功能。
多线程下载主要是用到下面这几个语句:
~~~
RandomAccessFile raf = new RandomAccessFile(PATH, "rwd");
raf.setLength(contentLength);
~~~
~~~
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+ endIndex);
~~~
~~~
RandomAccessFile raf = new RandomAccessFile(PATH, "rwd");
raf.seek(startIndex);
~~~
思路很简单:首先获得待下载文件的总长度,然后在本地生成一个一样大小的临时文件。然后将待下载的文件分块,让每个线程分别下载自己的文件块。非常要注意的是文件的下标。
~~~
package com.example.mytest;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
/**
* 该类会开三个线程下载URI的内容,下载到PATH文件夹内
*
* @author Hehyu
*
*/
public class Main extends Activity {
private final String PATH = Environment.getExternalStorageDirectory()
+ "/finger/东京暗鸦.jpg";
private final String URI = "http://e.hiphotos.baidu.com/zhidao/pic/item/e850352ac65c1038a7b590ceb0119313b17e89f7.jpg";
private final int THREAD_COUNT = 3;
private int contentLength = -1;
private int blockSize = -1;
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
for (int threadId = 1; threadId <= THREAD_COUNT; threadId++) {
int startIndex = (threadId - 1) * blockSize;
int endIndex = threadId * blockSize - 1;
if (threadId == THREAD_COUNT) {
endIndex = contentLength;
}
System.out
.println(threadId + " " + startIndex + " " + endIndex);
// 开启一个线程进行下载
new downloadThread(threadId, startIndex, endIndex).start();
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new calSize().start();
}
/**
* 该线程专门负责计算文件总共长度,并且在本地生成一个同名同大小的文件
*
* @author Hehyu
*
*/
private class calSize extends Thread {
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
URL url;
try {
url = new URL(URI);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
// 获取待下载文件长度
contentLength = conn.getContentLength();
blockSize = contentLength / THREAD_COUNT;
RandomAccessFile raf = new RandomAccessFile(PATH, "rwd");
raf.setLength(contentLength);
raf.close();
conn.disconnect();
// 已经获取了文件长度,通知主线程去创建子线程下载文件
Message msg = Message.obtain();
handler.sendMessage(msg);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 专门负责下载的进程
*
* @author Hehyu
*
*/
private class downloadThread extends Thread {
private int threadId;
private int startIndex;
private int endIndex;
public downloadThread(int threadId, int startIndex, int endIndex) {
// TODO Auto-generated constructor stub
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
RandomAccessFile raf = new RandomAccessFile(PATH, "rwd");
raf.seek(startIndex);
URL url = new URL(URI);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+ endIndex);
int code = conn.getResponseCode();
InputStream is = conn.getInputStream();
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
raf.write(buffer, 0, len);
}
raf.close();
conn.disconnect();
System.out.println("线程" + threadId + "下载完毕..");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
~~~
ListView优化以及checkbox状态问题
最后更新于:2022-04-01 14:43:34
ListView优化问题网上已经有很多资料了,下面只是简单贴一个demo。这里要说一下listview里面checkbox的状态问题。
~~~
holder.cb_vd.setChecked(state.get(position));
holder.tv_vd.setText(processList.get(position).processName);
holder.cb_vd
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
state.put(position, true);
} else {
state.put(position, false);
System.out.println(position+" :"+state.get(position));
}
}
});
~~~
通过这段代码进行注册checkbox的监听器,并且进行状态监听发现:当listview每一个item滑出屏幕的时候,上面这个函数都会被调用,并且isCheckde都会设为false!觉得非常的不可思议。然后自己查找了很久资料,发现是上面的话调错位置了。应该是这样写的:
~~~
holder.cb_vd
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
state.put(position, true);
} else {
state.put(position, false);
System.out.println(position);
}
}
});
holder.cb_vd.setChecked(state.get(position));
holder.tv_vd.setText(processList.get(position).processName);
~~~
至于原因的话,下面这段话表达的非常的好!
起因还是得讲到ListView的回收机制。假如我的ListView最多只能显示10个View,那么起初就会调用十次getView构造十个全新的View(包括对其中的checkbox设置监听器)。当我将列表往下拉出现第11个列表项的时候,顶部第一个列表项被隐藏,同样会再调用一次getView,不过此时getView的参数将返回刚刚被隐藏的第一个列表项的View,并对这个View更改数据作为即将出现的第11个View。问题就出在这里,我把checkbox.setChecked()方法调用放在了设置监听器前面,此时因为更改了checkbox的状态,势必引起触发状态更改的监听器。注意!由于第11个View是用被隐藏的第1个View回收来的,虽然还没有执行下一行设置监听器的代码,但实际上它已经拥有了一个状态监听器,这个监听器是这个View还是作为第一个View时设置。那个时候的监听器设置更改的第一项的数据,而不是第11项数据。因此,理所当然不能正确更改第11项数据,反而更改了无辜的第1项数据。如果我把两行代码顺序反过来,先更改监听器,再设置状态,引发的监听器自然也就是新的监听器,逻辑也就对了。
(转自 http://www.jb51.net/article/33424.htm)
下面贴上全部代码:
~~~
package com.example.mytesttwo;
import java.util.Hashtable;
import java.util.List;
import android.os.Bundle;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private ListView lv;
private List<RunningAppProcessInfo> processList;
private Hashtable<Integer, Boolean> state;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
state = new Hashtable<Integer, Boolean>();
lv = (ListView) findViewById(R.id.lv);
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
processList = am.getRunningAppProcesses();
lv.setAdapter(new MyAdapter());
}
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
// TODO Auto-generated method stub
return processList.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder = null;
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.iv_item,
null);
holder = new ViewHolder();
holder.tv_vd = (TextView) convertView
.findViewById(R.id.process_name);
holder.cb_vd = (CheckBox) convertView.findViewById(R.id.chose);
convertView.setTag(holder);
state.put(position, false);
} else {
holder = (ViewHolder) convertView.getTag();
if (state.get(position) == null) {
state.put(position, false);
}
}
holder.cb_vd
.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked) {
state.put(position, true);
} else {
state.put(position, false);
System.out.println(position);
}
}
});
holder.cb_vd.setChecked(state.get(position));
holder.tv_vd.setText(processList.get(position).processName);
return convertView;
}
}
private class ViewHolder {
public TextView tv_vd;
public CheckBox cb_vd;
}
}
~~~
简单的Notification
最后更新于:2022-04-01 14:43:32
下面这个代码是关于安卓Nitification的,也就是手机的通知栏。这个小程序创建了通知栏的一个消息,主要是演示下格式。
~~~
package com.example.mytest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@SuppressLint("NewApi")
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification.Builder builder = new Builder(MainActivity.this);
builder.setContentTitle("通知标题");
builder.setContentText("通知内容");
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.xiamu));
builder.setSmallIcon(R.drawable.ic_launcher);
Notification notification = builder.build();
nm.notify(10, notification);
}
});
}
}
~~~
短信拦截器
最后更新于:2022-04-01 14:43:30
今天用了几个小时做的小应用,一个短信拦截器,标记黑名单什么的。做这货的主要原因是为了巩固下前面的知识,这货用了数据库,listview,activity跳转,brocastcast receiver等知识。代码写得不好看看就行了。
~~~
package com.example.duanxinlanjie;
import java.util.Vector;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private EditText set_num;
private EditText clear_num;
private Button set_bt;
private Button clear_bt;
private Button exit_app;
private Button find_num;
private ListView lv;
private SQLiteDatabase db;
private MyAdapter myAdapter;
private Vector<String> sender;
private Vector<String> message;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
set_num = (EditText) findViewById(R.id.set_num);
clear_num = (EditText) findViewById(R.id.clear_num);
set_bt = (Button) findViewById(R.id.set_bt);
clear_bt = (Button) findViewById(R.id.clear_bt);
lv = (ListView) findViewById(R.id.lv);
exit_app = (Button) findViewById(R.id.exit_app);
find_num = (Button) findViewById(R.id.find_num);
sender = new Vector<String>();
message = new Vector<String>();
MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
db = helper.getWritableDatabase();
getData();
myAdapter = new MyAdapter();
lv.setAdapter(myAdapter);
set_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String num = set_num.getText().toString();
// 数据表phone_num插入一个待拦截的电话号码
db.execSQL("insert into num_data (phone_num) values (?)",
new Object[] { num });
Toast.makeText(MainActivity.this, "成功输入号码", 0).show();
}
});
clear_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String num = clear_num.getText().toString();
// 数据表phone_num插入一个待拦截的电话号码
db.execSQL("delete from num_data where phone_num = ?",
new Object[] { num });
Toast.makeText(MainActivity.this, "成功删除号码", 0).show();
}
});
exit_app.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
finish();
}
});
find_num.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setClass(MainActivity.this, FindNum.class);
startActivity(intent);
}
});
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
db.close();
}
private void getData() {
Cursor cursor = db.rawQuery("select * from msg_data", null);
while (cursor.moveToNext() == true) {
String s = cursor.getString(1);
String m = cursor.getString(2);
sender.add(s);
message.add(m);
}
cursor.close();
}
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
// TODO Auto-generated method stub
int count = sender.size();
return count;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
String senderInView = (String) sender.elementAt(position);
String messageInView = (String) message.elementAt(position);
View v = View.inflate(MainActivity.this, R.layout.lv_item, null);
TextView tv_num = (TextView) v.findViewById(R.id.tv_num);
TextView tv_content = (TextView) v.findViewById(R.id.tv_content);
tv_num.setText(senderInView);
tv_content.setText(messageInView);
return v;
}
}
}
~~~
~~~
package com.example.duanxinlanjie;
import java.util.Vector;
import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class FindNum extends Activity {
private Vector<String> num;
private ListView num_list;
private SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.find_num);
num = new Vector<String>();
num_list = (ListView) findViewById(R.id.num_list);
MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
db = helper.getWritableDatabase();
Cursor cursor = db.rawQuery("select * from num_data", null);
while (cursor.moveToNext()) {
String n = cursor.getString(1);
num.add(n);
}
cursor.close();
db.close();
num_list.setAdapter(new ArrayAdapter<String>(this, R.layout.num_item,
R.id.num_text, num));
}
}
~~~
~~~
package com.example.duanxinlanjie;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public MySQLiteOpenHelper(Context context) {
super(context, "phone_data.db", null, 1);
// TODO Auto-generated constructor stub
}
/**
* 建立两份表,第一份表是存要拦截的号码,第二份表存的是已经拦截的号码和短信内容
*/
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table num_data(id integer primary key autoincrement, phone_num varchar(20))");
db.execSQL("create table msg_data(id integer primary key autoincrement, phone_num varchar(20), msg varchar(100))");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
~~~
~~~
package com.example.duanxinlanjie;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.telephony.gsm.SmsMessage;
import android.widget.Toast;
public class SmsReceiver extends BroadcastReceiver {
private MySQLiteOpenHelper helper;
private SQLiteDatabase db;
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
helper = new MySQLiteOpenHelper(context);
db = helper.getWritableDatabase();
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
String body = smsMessage.getMessageBody();
String sender = smsMessage.getDisplayOriginatingAddress();
Cursor cursor = db.rawQuery(
"select * from num_data where phone_num = ?",
new String[] { sender });
if (cursor.getCount() == 0) {
cursor.close();
helper = null;
db.close();
return;
}
cursor.close();
db.execSQL("insert into msg_data (phone_num , msg) values (?,?)",
new Object[] { sender, body });
db.close();
helper = null;
}
Toast.makeText(context, "成功拦截", 0).show();
abortBroadcast();
}
}
~~~
~~~
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="标记号码: "
android:textSize="20dp" />
<EditText
android:id="@+id/set_num"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_weight="7.69" />
<Button
android:id="@+id/set_bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="确认" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="清除号码: "
android:textSize="20dp" />
<EditText
android:id="@+id/clear_num"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_weight="7.69" />
<Button
android:id="@+id/clear_bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="确认" />
</LinearLayout>
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_weight="10"
android:layout_marginTop="10dp" >
</ListView>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_weight="0"
android:orientation="horizontal" >
<Button
android:id="@+id/exit_app"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="退出程序"
android:layout_alignParentRight="true"
android:layout_marginRight="50dp" />
<Button
android:id="@+id/find_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="拦截号码"
android:layout_alignParentLeft="true"
android:layout_marginLeft="50dp" />
</RelativeLayout>
</LinearLayout>
~~~
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/num_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
></ListView>
</LinearLayout>
~~~
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_num"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="18dp"
android:text="电话号码" />
<TextView
android:id="@+id/tv_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textSize="18dp"
android:text="短信内容" />
</LinearLayout>
~~~
~~~
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/num_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:text="号码"
/>
</LinearLayout>
~~~
~~~
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.duanxinlanjie"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application
android:allowBackup="true"
android:icon="@drawable/wuya"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:logo="@drawable/wuya" >
<activity
android:name="com.example.duanxinlanjie.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MySQLiteOpenHelper" >
</activity>
<receiver android:name="com.example.duanxinlanjie.SmsReceiver" >
<intent-filter android:priority="1000" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<activity android:name="com.example.duanxinlanjie.FindNum" >
</activity>
</application>
</manifest>
~~~
SQLiteOpenHelper数据库操作
最后更新于:2022-04-01 14:43:28
发现之前写了这么多都没有涉及数据库的内容,但是数据库又是灰常的重要,所以这里就写一下安卓利用SQLiteOpenHelper进行数据库操作了。
数据库操作一般的思路是用一个类继承SQLiteOpenHelper,然后就可以各种增删改查了。必须要注意的是SQLiteDatabase和Cursor不用要close掉,不然会内存泄露。
提一下的是,设A继承了SQLiteOpenHelper,那么A的onCreate函数只有在数据库第一次创建的时候才会调用。
下面这个也不算是应用吧,只是输一句话进数据库然后显示出最近的两句而已。下面是代码:
~~~
package com.example.mytest;
import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
private EditText ed;
private TextView tv1;
private TextView tv2;
private Button bt;
private SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ed = (EditText) findViewById(R.id.ed);
tv1 = (TextView) findViewById(R.id.tv1);
tv2 = (TextView) findViewById(R.id.tv2);
bt = (Button) findViewById(R.id.bt);
MySQLiteOpenHelper helper = new MySQLiteOpenHelper(this);
db = helper.getWritableDatabase();
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String t = ed.getText().toString();
db.execSQL("insert into text (str) values (?)", new Object[]{t});
Cursor cursor = db.rawQuery("select * from text", null);
if (cursor.moveToLast()) {
String ans = cursor.getString(1);
tv1.setText(ans);
}
if (cursor.moveToPrevious()) {
String ans = cursor.getString(1);
tv2.setText(ans);
}
cursor.close();
}
});
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
db.close();
}
}
~~~
~~~
package com.example.mytest;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MySQLiteOpenHelper extends SQLiteOpenHelper{
public MySQLiteOpenHelper(Context context) {
super(context, "text.db", null, 1);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table text(id integer primary key autoincrement, str varchar(20))");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
~~~
~~~
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="matrix"
/>
<EditText
android:id="@+id/ed"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
/>
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="tv1"
/>
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv1"
android:layout_marginTop="30dp"
android:text="tv2"
android:layout_centerHorizontal="true"
/>
<Button
android:id="@+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv2"
android:layout_marginTop="30dp"
android:layout_centerHorizontal="true"
android:text="保存"
/>
</RelativeLayout>
~~~
LruCache图片缓存技术
最后更新于:2022-04-01 14:43:25
虽然遇到过几次因为BITMAP照成OOM,但是之前都没有正视过这个问题,今天去面试果然出现了这个问题,感觉被虐了啊。知耻而后勇,回去查了一些资料,现在总算明白了一点LruCache图片缓存技术,这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除,这种机制非常适合bitmap这种内存坑爹货啊。
下面贴一下示例代码,其实这个代码一点实用意义都没有,只不过把里面的一些函数和调用提了一下。
~~~
package com.example.mytest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.util.LruCache;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView iv;
private Bitmap bm;
private LruCache<String, Bitmap> mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory/8;
mMemoryCache = new LruCache<String, Bitmap>((cacheSize)){
@Override
protected int sizeOf(String key, Bitmap value) {
// TODO Auto-generated method stub
return value.getByteCount()/1024;
}
};
iv = (ImageView) findViewById(R.id.iv);
bm = BitmapFactory.decodeResource(getResources(), R.drawable.xiamu);
iv.setImageBitmap(bm);
mMemoryCache.put("key", bm);
iv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Bitmap bitmap = null;
// TODO Auto-generated method stub
if (mMemoryCache.get("key") == null) {
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.xiamu);
iv.setImageBitmap(bitmap);
}
else {
iv.setImageBitmap(mMemoryCache.get("key"));
}
}
});
}
}
~~~
多点触控拉伸图片
最后更新于:2022-04-01 14:43:23
下面这个代码实现的是用通过双指拉伸或者收缩实现图片的放大或者缩小。这里面注意几点:
1)多点触控的那些常量,这里面的知识参考博客:
http://blog.csdn.net/barryhappy/article/details/7392326
2)Bitmap的回收机制。这里面多次创建Bitmap会引起内存不足,下面并没有解决这个问题,所以多次拉伸之后程序会挂掉。。
3)后记:这句话是后面加的。上面这个问题已经解决了,详情请看我的另一篇博客:
http://blog.csdn.net/hhysirius/article/details/21525105
~~~
package com.example.mytest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView iv;
private Bitmap bm;
private Bitmap alterBm;
private Bitmap temp;
private Paint paint;
private Matrix matrix;
//旧的两指距离
private float oldDis = 0.0f;
//新的两指距离
private float newDis = 0.0f;
//判断是否是双指
private boolean flag = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = (ImageView) this.findViewById(R.id.iv);
bm = BitmapFactory.decodeResource(getResources(), R.drawable.xiamu);
temp = bm.copy(bm.getConfig(), true);
alterBm = bm.copy(bm.getConfig(), true);
paint = new Paint();
paint.setColor(Color.BLACK);
matrix = new Matrix();
iv.setImageBitmap(alterBm);
iv.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()&MotionEvent.ACTION_MASK) {
//第一个手指按下
case MotionEvent.ACTION_DOWN:
break;
//第二个手指按下
case MotionEvent.ACTION_POINTER_DOWN:
flag = true;
oldDis = spacing(event);
break;
//手指移动
case MotionEvent.ACTION_MOVE:
if (flag == false) {
//仅有一个手指下不做反映
break;
}
newDis = spacing(event);
//微小变化不作处理
if (newDis > (oldDis - 10.0f) && newDis < (oldDis + 10.0f)) {
break;
}
float scale = newDis / oldDis;
if (scale > 1) {
float t = scale - 1.0f;
t = t/2.0f;
scale = scale - t;
}
if (scale < 1) {
float t = 1.0f - scale;
t = t/2.0f;
scale = scale + t;
}
matrix.setScale(scale, scale);
int newHeight = alterBm.getHeight();
int newWidth = alterBm.getWidth();
temp.recycle();
temp = Bitmap.createBitmap(alterBm, 0, 0, newWidth, newHeight, matrix ,true);
iv.setImageBitmap(temp);
alterBm.recycle();
alterBm = temp.copy(temp.getConfig(), true);
newDis = oldDis;
break;
case MotionEvent.ACTION_POINTER_UP:
flag = false;
break;
default:
break;
}
return true;
}
});
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
}
~~~
startActivityForResult的初步学习
最后更新于:2022-04-01 14:43:21
安卓Activity之间传数据除了用putExtra之外还可以用startActivityForResult获取一个Activity的返回值。为了简单阐述这种方式我们来做个简单的模型:
假设A去开启B,则调用函数 void startActivityForResult([Intent]() intent,int requestCode),这时候会设置一个requestCode,要求>=0就行了
这时候A需要覆盖onActivityResult方法获取返回值,这个方法具体是这样的:void onActivityResult(int requestCode,int resultCode,[Intent]() data),requestCode的数值就是刚刚设置的requestCode,resultCode的数值会在B里面设置。这个函数将在B结束后调用。
这时候B需要调用setResult函数设置返回值,这个函数具体是这样的:void setResult(int resultCode,[Intent]() data),第一个参数设置resultCode,这里的resultCode就是onActivityResult的resultCode。
查了一些资料关于这几个函数的调用时机,发现下面这句话总结的很好:
**B**退回**A**过程中,首先是**B**处于Pause 状态,然后等待 **A **执行****restart——〉 start ——〉resume,然后才是B 的stop——〉destroy,而**A**的 onActivityResult() 需要在**B**pause之后,**A**restart 之前 这中间调用,所以**B**中的setResult()函数应该放在**B**pause 之前调用。这点非常的重要啊。
下面是代码:
第一个Activity:
~~~
package com.example.mytest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView tv ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
}
public void click(View v) {
Intent intent = new Intent(this, NextActivity.class);
startActivityForResult(intent, 1);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
String str = data.getStringExtra("data");
tv.setText(str);
System.out.println("onActivityResult");
}
}
~~~
第二个Activity:
~~~
package com.example.mytest;
import java.util.Random;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class NextActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.next_activity);
Intent intent = new Intent(this ,MainActivity.class);
intent.putExtra("data", "传输");
this.setResult(2, intent);
}
}
~~~
Activity的生命周期
最后更新于:2022-04-01 14:43:19
Activity的生命周期体现在下面的6个函数上面:
1)onCreate :Activity被创建的时候调用的方法
2)onStart :Activity变成用户可见的时候调用的方法
3)onResume :界面获取焦点的时候调用的方法
4)onPause :界面失去焦点,控件不能响应点击事件的时候调用的方法
5)onStop :界面不可见的时候调用的方法
6)onDestroy :Activity被销毁的时候调用的方法
Activity的完整生命周期自onCreate到onDestroy方法为止
可视生命周期由onStrart到onStop方法为止
前台生命周期由onResume到onPause方法为止
另外还有一个方法是onRestart方法,当一个Activity由onStop到onStart的时候就会调用onRestart方法
经过测试需要注意的点是:当应用程序点击back键之后它会依次调用onPause,onStop,onDestroy方法
当时如果点击home键之后它会调用onPause和onStop方法,并不会调用onDestroy方法,如果重新进入Activity则这个时候它会调用onRestart方法。这个点非常重要。
下面是我的测试代码,有两个Activity,只贴出第一个Activity:
~~~
package com.example.mytest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("onCreate");
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
System.out.println("onStart");
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
System.out.println("onResume");
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
System.out.println("onPause");
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
System.out.println("onStop");
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
System.out.println("onDestroy");
}
@Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
System.out.println("onRestrat");
}
public void click(View v) {
Intent intent = new Intent(this, NextActivity.class);
startActivity(intent);
}
}
~~~
隐式调用Activity
最后更新于:2022-04-01 14:43:16
其实这部分知识点不难,只不过感觉有点多而且杂。这里就写个简单的action和category匹配吧。
代码很快就写完了,写了两个Activity,不过测试总是ANF错误,坑爹!之后查了很多资料才知道如果自己定义的某个Activity要通过隐式调用,在AndroidManifast.xm那么必须加上android.intent.category.DEFAULT,否则不起作用,因为系统会默认给你加上android.intent.category.DEFAULT这货。intent filter这货允许你添加多个category条目,如果有一个category不匹配系统就会判定不匹配。
写的有点乱,下面贴代码:
两个Activity:
~~~
package com.example.mytest;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) this.findViewById(R.id.bt);
bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent();
intent.setAction("nextActivity");
intent.addCategory("haha");
startActivity(intent);
}
});
}
}
~~~
~~~
package com.example.mytest;
import android.app.Activity;
import android.os.Bundle;
public class NextActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.next_activity);
}
}
~~~
下面是清单文件:
~~~
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mytest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.mytest.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.mytest.NextActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="nextActivity" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="haha" />
</intent-filter>
</activity>
</application>
</manifest>
~~~
开启系统Activity
最后更新于:2022-04-01 14:43:14
下面这个代码首先会检查手机的wifi是否已经连接,如果没有连接就会跳转到系统的设置页面。
我首先在编译器里面通过连接手机查找手机打开设置页面是调用系统的哪个Activity,最后截出来的信息是:
03-01 15:40:54.293: V/ActivityManager(573): ACT-Launching: ActivityRecord{423fb8f8 u0 com.android.settings/.HWSettings}
根据这条信息可以知道设置页面是哪个包和哪个类。代码通俗易懂。。
~~~
package com.example.mytest;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WifiManager wifiManager = (WifiManager) this
.getSystemService(Context.WIFI_SERVICE);
if (wifiManager.isWifiEnabled() == true) {
Toast.makeText(this, "wifi可用", 0);
}
else {
Toast.makeText(this, "wifi不可用", 0);
//03-01 15:40:54.293: V/ActivityManager(573): ACT-Launching: ActivityRecord{423fb8f8 u0 com.android.settings/.HWSettings}
Intent intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.HWSettings");
startActivity(intent);
}
}
}
~~~
Handler初步学习
最后更新于:2022-04-01 14:43:12
前面介绍了异步任务的处理,这里来学一下Handler和Message机制吧。下面这个代码和之前的一样,都是从网上下载图片的。
~~~
package com.example.myasynctask;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
private Button button;
private ImageView iv;
private String path = "http://cdn.duitang.com/uploads/item/201310/17/20131017194234_eZfFU.thumb.600_0.png";
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
Bitmap bm = null;
byte[] data = (byte[])msg.obj;
bm = BitmapFactory.decodeByteArray(data, 0, data.length);
iv.setImageBitmap(bm);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) this.findViewById(R.id.bt);
iv = (ImageView) this.findViewById(R.id.iv);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new Thread(new myThread()).start();
}
});
}
private class myThread implements Runnable {
@Override
public void run() {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(path);
InputStream inputStream = null;
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200 ) {
HttpEntity httpEntity = httpResponse.getEntity();
byte[] data = EntityUtils.toByteArray(httpEntity);
Message message = Message.obtain();
message.obj = data;
handler.sendMessage(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
~~~
~~~
~~~
~~~
~~~
Looper维护一个消息队列(在loop()函数里面)
Message.obtain可回收的获取Message对象(这样就不用多次new对象)
Handler通过sendMessage来把Message进行消息队列的入队,并且把Message的target(也就是对应的Handler绑定为自己)
当消息队列循环到相应的Message的时候,会调用Message绑定的Handler的dispatchMessage函数,该函数会调用handleMessage函数,也就是用户实现的handleMessage函数。Handler可以绑定多个Message,通过Message.what来识别身份。
--------源码所得,2014/ 9/ 9 修改
AsyncTask再度学习
最后更新于:2022-04-01 14:43:10
上篇文章写到了简单的文件下载的功能,这里再简单的添加一个功能(显示下载进度)。代码方面改变不大,只是运用了AsyncTask的onProgressUpdate函数,不过下载图片的代码得要用另外一种方式写了。
~~~
package com.example.myasynctask;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
private Button button;
private ImageView iv;
private String path = "http://cdn.duitang.com/uploads/item/201310/17/20131017194234_eZfFU.thumb.600_0.png";
private ProgressDialog dia;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) this.findViewById(R.id.bt);
iv = (ImageView) this.findViewById(R.id.iv);
dia = new ProgressDialog(this);
dia.setTitle("提示信息");
dia.setMessage("正在下载...");
dia.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new myTask().execute(path);
}
});
}
private class myTask extends AsyncTask<String, Integer, Bitmap> {
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dia.show();
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
dia.setProgress(values[0]);
}
@Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
Bitmap bitmap = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
InputStream inputStream = null;
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(params[0]);
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
long total_length = httpResponse.getEntity()
.getContentLength();
int has_read = 0;
int total_read = 0;
byte[] data = new byte[1024];
inputStream = httpResponse.getEntity().getContent();
while ((has_read = inputStream.read(data)) != -1) {
total_read += has_read;
outputStream.write(data, 0, has_read);
int value = (int) (total_read / (float) total_length * 100);
publishProgress(value);
}
byte[] result = outputStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(result, 0,
result.length);
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
iv.setImageBitmap(result);
dia.dismiss();
}
}
}
~~~